diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/third_party/skia/src | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/skia/src')
687 files changed, 23977 insertions, 17351 deletions
diff --git a/chromium/third_party/skia/src/android/SkAnimatedImage.cpp b/chromium/third_party/skia/src/android/SkAnimatedImage.cpp index 3ae8a843ba4..966f150aa89 100644 --- a/chromium/third_party/skia/src/android/SkAnimatedImage.cpp +++ b/chromium/third_party/skia/src/android/SkAnimatedImage.cpp @@ -92,10 +92,10 @@ SkAnimatedImage::SkAnimatedImage(std::unique_ptr<SkAndroidCodec> codec, SkISize } if (!fSimple) { - fMatrix = SkMatrix::MakeTrans(-fCropRect.fLeft, -fCropRect.fTop); + fMatrix = SkMatrix::Translate(-fCropRect.fLeft, -fCropRect.fTop); float scaleX = (float) fScaledSize.width() / fDecodeInfo.width(); float scaleY = (float) fScaledSize.height() / fDecodeInfo.height(); - fMatrix.preConcat(SkMatrix::MakeScale(scaleX, scaleY)); + fMatrix.preConcat(SkMatrix::Scale(scaleX, scaleY)); } this->decodeNextFrame(); } diff --git a/chromium/third_party/skia/src/android/SkBitmapRegionCodec.cpp b/chromium/third_party/skia/src/android/SkBitmapRegionCodec.cpp deleted file mode 100644 index 081d0bbf3bc..00000000000 --- a/chromium/third_party/skia/src/android/SkBitmapRegionCodec.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "include/codec/SkAndroidCodec.h" -#include "src/android/SkBitmapRegionCodec.h" -#include "src/android/SkBitmapRegionDecoderPriv.h" -#include "src/codec/SkCodecPriv.h" - -SkBitmapRegionCodec::SkBitmapRegionCodec(SkAndroidCodec* codec) - : INHERITED(codec->getInfo().width(), codec->getInfo().height()) - , fCodec(codec) -{} - -bool SkBitmapRegionCodec::decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator, - const SkIRect& desiredSubset, int sampleSize, SkColorType dstColorType, - bool requireUnpremul, sk_sp<SkColorSpace> dstColorSpace) { - - // Fix the input sampleSize if necessary. - if (sampleSize < 1) { - sampleSize = 1; - } - - // The size of the output bitmap is determined by the size of the - // requested subset, not by the size of the intersection of the subset - // and the image dimensions. - // If inputX is negative, we will need to place decoded pixels into the - // output bitmap starting at a left offset. Call this outX. - // If outX is non-zero, subsetX must be zero. - // If inputY is negative, we will need to place decoded pixels into the - // output bitmap starting at a top offset. Call this outY. - // If outY is non-zero, subsetY must be zero. - int outX; - int outY; - SkIRect subset = desiredSubset; - SubsetType type = adjust_subset_rect(fCodec->getInfo().dimensions(), &subset, &outX, &outY); - if (SubsetType::kOutside_SubsetType == type) { - return false; - } - - // Ask the codec for a scaled subset - if (!fCodec->getSupportedSubset(&subset)) { - SkCodecPrintf("Error: Could not get subset.\n"); - return false; - } - SkISize scaledSize = fCodec->getSampledSubsetDimensions(sampleSize, subset); - - // Create the image info for the decode - SkAlphaType dstAlphaType = fCodec->computeOutputAlphaType(requireUnpremul); - SkImageInfo decodeInfo = - SkImageInfo::Make(scaledSize, dstColorType, dstAlphaType, dstColorSpace); - - // Initialize the destination bitmap - int scaledOutX = 0; - int scaledOutY = 0; - int scaledOutWidth = scaledSize.width(); - int scaledOutHeight = scaledSize.height(); - if (SubsetType::kPartiallyInside_SubsetType == type) { - scaledOutX = outX / sampleSize; - scaledOutY = outY / sampleSize; - // We need to be safe here because getSupportedSubset() may have modified the subset. - const int extraX = std::max(0, desiredSubset.width() - outX - subset.width()); - const int extraY = std::max(0, desiredSubset.height() - outY - subset.height()); - const int scaledExtraX = extraX / sampleSize; - const int scaledExtraY = extraY / sampleSize; - scaledOutWidth += scaledOutX + scaledExtraX; - scaledOutHeight += scaledOutY + scaledExtraY; - } - SkImageInfo outInfo = decodeInfo.makeWH(scaledOutWidth, scaledOutHeight); - if (kGray_8_SkColorType == dstColorType) { - // The legacy implementations of BitmapFactory and BitmapRegionDecoder - // used kAlpha8 for grayscale images (before kGray8 existed). While - // the codec recognizes kGray8, we need to decode into a kAlpha8 - // bitmap in order to avoid a behavior change. - outInfo = outInfo.makeColorType(kAlpha_8_SkColorType).makeAlphaType(kPremul_SkAlphaType); - } - bitmap->setInfo(outInfo); - if (!bitmap->tryAllocPixels(allocator)) { - SkCodecPrintf("Error: Could not allocate pixels.\n"); - return false; - } - - // Zero the bitmap if the region is not completely within the image. - // TODO (msarett): Can we make this faster by implementing it to only - // zero parts of the image that we won't overwrite with - // pixels? - SkCodec::ZeroInitialized zeroInit = allocator ? allocator->zeroInit() : - SkCodec::kNo_ZeroInitialized; - if (SubsetType::kPartiallyInside_SubsetType == type && - SkCodec::kNo_ZeroInitialized == zeroInit) { - void* pixels = bitmap->getPixels(); - size_t bytes = outInfo.computeByteSize(bitmap->rowBytes()); - memset(pixels, 0, bytes); - } - - // Decode into the destination bitmap - SkAndroidCodec::AndroidOptions options; - options.fSampleSize = sampleSize; - options.fSubset = ⊂ - options.fZeroInitialized = zeroInit; - void* dst = bitmap->getAddr(scaledOutX, scaledOutY); - - SkCodec::Result result = fCodec->getAndroidPixels(decodeInfo, dst, bitmap->rowBytes(), - &options); - switch (result) { - case SkCodec::kSuccess: - case SkCodec::kIncompleteInput: - case SkCodec::kErrorInInput: - return true; - default: - SkCodecPrintf("Error: Could not get pixels with message \"%s\".\n", - SkCodec::ResultToString(result)); - return false; - } -} diff --git a/chromium/third_party/skia/src/android/SkBitmapRegionCodec.h b/chromium/third_party/skia/src/android/SkBitmapRegionCodec.h deleted file mode 100644 index 21859514af9..00000000000 --- a/chromium/third_party/skia/src/android/SkBitmapRegionCodec.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkBitmapRegionCodec_DEFINED -#define SkBitmapRegionCodec_DEFINED - -#include "include/android/SkBitmapRegionDecoder.h" -#include "include/codec/SkAndroidCodec.h" -#include "include/core/SkBitmap.h" - -/* - * This class implements SkBitmapRegionDecoder using an SkAndroidCodec. - */ -class SkBitmapRegionCodec : public SkBitmapRegionDecoder { -public: - - /* - * Takes ownership of pointer to codec - */ - SkBitmapRegionCodec(SkAndroidCodec* codec); - - bool decodeRegion(SkBitmap* bitmap, SkBRDAllocator* allocator, - const SkIRect& desiredSubset, int sampleSize, - SkColorType colorType, bool requireUnpremul, - sk_sp<SkColorSpace> prefColorSpace) override; - - SkEncodedImageFormat getEncodedFormat() override { return fCodec->getEncodedFormat(); } - - SkColorType computeOutputColorType(SkColorType requestedColorType) override { - return fCodec->computeOutputColorType(requestedColorType); - } - - sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType, - sk_sp<SkColorSpace> prefColorSpace = nullptr) override { - return fCodec->computeOutputColorSpace(outputColorType, prefColorSpace); - } - -private: - - std::unique_ptr<SkAndroidCodec> fCodec; - - typedef SkBitmapRegionDecoder INHERITED; - -}; -#endif // SkBitmapRegionCodec_DEFINED diff --git a/chromium/third_party/skia/src/android/SkBitmapRegionDecoder.cpp b/chromium/third_party/skia/src/android/SkBitmapRegionDecoder.cpp deleted file mode 100644 index 328daa3bc97..00000000000 --- a/chromium/third_party/skia/src/android/SkBitmapRegionDecoder.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "include/android/SkBitmapRegionDecoder.h" -#include "include/codec/SkAndroidCodec.h" -#include "include/codec/SkCodec.h" -#include "src/android/SkBitmapRegionCodec.h" -#include "src/codec/SkCodecPriv.h" - -SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create( - sk_sp<SkData> data, Strategy strategy) { - return SkBitmapRegionDecoder::Create(new SkMemoryStream(data), - strategy); -} - -SkBitmapRegionDecoder* SkBitmapRegionDecoder::Create( - SkStreamRewindable* stream, Strategy strategy) { - std::unique_ptr<SkStreamRewindable> streamDeleter(stream); - switch (strategy) { - case kAndroidCodec_Strategy: { - auto codec = SkAndroidCodec::MakeFromStream(std::move(streamDeleter)); - if (nullptr == codec) { - SkCodecPrintf("Error: Failed to create codec.\n"); - return nullptr; - } - - switch ((SkEncodedImageFormat)codec->getEncodedFormat()) { - case SkEncodedImageFormat::kJPEG: - case SkEncodedImageFormat::kPNG: - case SkEncodedImageFormat::kWEBP: - case SkEncodedImageFormat::kHEIF: - break; - default: - return nullptr; - } - - return new SkBitmapRegionCodec(codec.release()); - } - default: - SkASSERT(false); - return nullptr; - } -} diff --git a/chromium/third_party/skia/src/android/SkBitmapRegionDecoderPriv.h b/chromium/third_party/skia/src/android/SkBitmapRegionDecoderPriv.h deleted file mode 100644 index 905d460c5c6..00000000000 --- a/chromium/third_party/skia/src/android/SkBitmapRegionDecoderPriv.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkBitmapRegionDecoderPriv_DEFINED -#define SkBitmapRegionDecoderPriv_DEFINED - -#include "include/core/SkRect.h" - -enum SubsetType { - kFullyInside_SubsetType, - kPartiallyInside_SubsetType, - kOutside_SubsetType, -}; - -/* - * Corrects image subset offsets and dimensions in order to perform a valid decode. - * Also indicates if the image subset should be placed at an offset within the - * output bitmap. - * - * Values of output variables are undefined if the SubsetType is kInvalid. - * - * @param imageDims Original image dimensions. - * @param subset As input, the subset that the client requested. - * As output, the image subset that we will decode. - * @param outX The left offset of the image subset within the output bitmap. - * @param outY The top offset of the image subset within the output bitmap. - * - * @return An indication of how the subset is contained in the image. - * If the return value is kInvalid, values of output variables are undefined. - */ -inline SubsetType adjust_subset_rect(const SkISize& imageDims, SkIRect* subset, int* outX, - int* outY) { - // These must be at least zero, we can't start decoding the image at a negative coordinate. - int left = std::max(0, subset->fLeft); - int top = std::max(0, subset->fTop); - - // If input offsets are less than zero, we decode to an offset location in the output bitmap. - *outX = left - subset->fLeft; - *outY = top - subset->fTop; - - // Make sure we don't decode pixels past the edge of the image or past the edge of the subset. - int width = std::min(imageDims.width() - left, subset->width() - *outX); - int height = std::min(imageDims.height() - top, subset->height() - *outY); - if (width <= 0 || height <= 0) { - return SubsetType::kOutside_SubsetType; - } - - subset->setXYWH(left, top, width, height); - if ((*outX != 0) || (*outY != 0) || (width != subset->width()) || - (height != subset->height())) { - return SubsetType::kPartiallyInside_SubsetType; - } - - return SubsetType::kFullyInside_SubsetType; -} - -#endif // SkBitmapRegionDecoderPriv_DEFINED diff --git a/chromium/third_party/skia/src/atlastext/SkAtlasTextContext.cpp b/chromium/third_party/skia/src/atlastext/SkAtlasTextContext.cpp deleted file mode 100644 index 91e7713c125..00000000000 --- a/chromium/third_party/skia/src/atlastext/SkAtlasTextContext.cpp +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "include/atlastext/SkAtlasTextContext.h" -#include "include/atlastext/SkAtlasTextRenderer.h" -#include "src/atlastext/SkInternalAtlasTextContext.h" - -sk_sp<SkAtlasTextContext> SkAtlasTextContext::Make(sk_sp<SkAtlasTextRenderer> renderer) { - return sk_sp<SkAtlasTextContext>(new SkAtlasTextContext(std::move(renderer))); -} - -SkAtlasTextContext::SkAtlasTextContext(sk_sp<SkAtlasTextRenderer> renderer) - : fInternalContext(SkInternalAtlasTextContext::Make(std::move(renderer))) {} diff --git a/chromium/third_party/skia/src/atlastext/SkAtlasTextTarget.cpp b/chromium/third_party/skia/src/atlastext/SkAtlasTextTarget.cpp deleted file mode 100644 index d541f38fb33..00000000000 --- a/chromium/third_party/skia/src/atlastext/SkAtlasTextTarget.cpp +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "include/atlastext/SkAtlasTextTarget.h" - -#include "include/atlastext/SkAtlasTextContext.h" -#include "include/atlastext/SkAtlasTextFont.h" -#include "include/atlastext/SkAtlasTextRenderer.h" -#include "src/atlastext/SkInternalAtlasTextContext.h" -#include "src/core/SkGlyphRunPainter.h" -#include "src/core/SkMatrixProvider.h" -#include "src/gpu/GrClip.h" -#include "src/gpu/GrContextPriv.h" -#include "src/gpu/GrDrawingManager.h" -#include "src/gpu/GrMemoryPool.h" -#include "src/gpu/GrRecordingContextPriv.h" -#include "src/gpu/SkGr.h" -#include "src/gpu/ops/GrAtlasTextOp.h" -#include "src/gpu/text/GrAtlasManager.h" -#include "src/gpu/text/GrTextContext.h" - -static constexpr int kMaxBatchLookBack = 10; - -SkAtlasTextTarget::SkAtlasTextTarget(sk_sp<SkAtlasTextContext> context, int width, int height, - void* handle) - : fHandle(handle) - , fContext(std::move(context)) - , fWidth(width) - , fHeight(height) - , fMatrixStack(sizeof(SkMatrix), 4) - , fSaveCnt(0) { - fMatrixStack.push_back(); - this->accessCTM()->reset(); -} - -SkAtlasTextTarget::~SkAtlasTextTarget() { fContext->renderer()->targetDeleted(fHandle); } - -int SkAtlasTextTarget::save() { - const auto& currCTM = this->ctm(); - *static_cast<SkMatrix*>(fMatrixStack.push_back()) = currCTM; - return fSaveCnt++; -} - -void SkAtlasTextTarget::restore() { - if (fSaveCnt) { - fMatrixStack.pop_back(); - fSaveCnt--; - } -} - -void SkAtlasTextTarget::restoreToCount(int count) { - while (fSaveCnt > count) { - this->restore(); - } -} - -void SkAtlasTextTarget::translate(SkScalar dx, SkScalar dy) { - this->accessCTM()->preTranslate(dx, dy); -} - -void SkAtlasTextTarget::scale(SkScalar sx, SkScalar sy) { this->accessCTM()->preScale(sx, sy); } - -void SkAtlasTextTarget::rotate(SkScalar degrees) { this->accessCTM()->preRotate(degrees); } - -void SkAtlasTextTarget::rotate(SkScalar degrees, SkScalar px, SkScalar py) { - this->accessCTM()->preRotate(degrees, px, py); -} - -void SkAtlasTextTarget::skew(SkScalar sx, SkScalar sy) { this->accessCTM()->preSkew(sx, sy); } - -void SkAtlasTextTarget::concat(const SkMatrix& matrix) { this->accessCTM()->preConcat(matrix); } - -////////////////////////////////////////////////////////////////////////////// - -static const GrColorInfo kColorInfo(GrColorType::kRGBA_8888, kPremul_SkAlphaType, nullptr); -static const SkSurfaceProps kProps( - SkSurfaceProps::kUseDistanceFieldFonts_Flag, kUnknown_SkPixelGeometry); - -////////////////////////////////////////////////////////////////////////////// - -class SkInternalAtlasTextTarget : public GrTextTarget, public SkAtlasTextTarget { -public: - SkInternalAtlasTextTarget(sk_sp<SkAtlasTextContext> context, int width, int height, - void* handle) - : GrTextTarget(width, height, kColorInfo) - , SkAtlasTextTarget(std::move(context), width, height, handle) - , fGlyphPainter(kProps, kColorInfo) {} - - ~SkInternalAtlasTextTarget() override { - this->deleteOps(); - } - - /** GrTextTarget overrides */ - - void addDrawOp(const GrClip&, std::unique_ptr<GrAtlasTextOp> op) override; - - void drawShape(const GrClip&, - const SkPaint&, - const SkMatrixProvider&, - const GrStyledShape&) override { - SkDebugf("Path glyph??"); - } - - void makeGrPaint(GrMaskFormat, - const SkPaint& skPaint, - const SkMatrixProvider&, - GrPaint* grPaint) override { - grPaint->setColor4f(skPaint.getColor4f().premul()); - } - - GrContext* getContext() override { - return this->context()->internal().grContext(); - } - - SkGlyphRunListPainter* glyphPainter() override { - return &fGlyphPainter; - } - - /** SkAtlasTextTarget overrides */ - - void drawText(const SkGlyphID[], const SkPoint[], int glyphCnt, uint32_t color, - const SkAtlasTextFont&) override; - void flush() override; - -private: - void deleteOps(); - - GrRecordingContext::Arenas arenas() { - return fContext->internal().grContext()->GrRecordingContext::priv().arenas(); - } - - uint32_t fColor; - using SkAtlasTextTarget::fWidth; - using SkAtlasTextTarget::fHeight; - SkTArray<std::unique_ptr<GrAtlasTextOp>, true> fOps; - SkGlyphRunListPainter fGlyphPainter; -}; - -////////////////////////////////////////////////////////////////////////////// - -std::unique_ptr<SkAtlasTextTarget> SkAtlasTextTarget::Make(sk_sp<SkAtlasTextContext> context, - int width, int height, void* handle) { - return std::unique_ptr<SkAtlasTextTarget>( - new SkInternalAtlasTextTarget(std::move(context), width, height, handle)); -} - -////////////////////////////////////////////////////////////////////////////// - -void SkInternalAtlasTextTarget::drawText(const SkGlyphID glyphs[], const SkPoint positions[], - int glyphCnt, uint32_t color, - const SkAtlasTextFont& font) { - SkPaint paint; - paint.setAntiAlias(true); - - // The atlas text context does munging of the paint color. We store the client's color here - // and then overwrite the generated op's color when addDrawOp() is called. - fColor = color; - - SkSurfaceProps props(SkSurfaceProps::kUseDistanceFieldFonts_Flag, kUnknown_SkPixelGeometry); - auto grContext = this->context()->internal().grContext(); - auto atlasTextContext = grContext->priv().drawingManager()->getTextContext(); - SkGlyphRunBuilder builder; - builder.drawGlyphsWithPositions(paint, font.makeFont(), - SkSpan<const SkGlyphID>{glyphs, SkTo<size_t>(glyphCnt)}, - positions); - auto glyphRunList = builder.useGlyphRunList(); - if (!glyphRunList.empty()) { - SkSimpleMatrixProvider matrixProvider(this->ctm()); - atlasTextContext->drawGlyphRunList(grContext, this, GrNoClip(), matrixProvider, props, - glyphRunList); - } -} - -void SkInternalAtlasTextTarget::addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) { - SkASSERT(clip.quickContains(SkRect::MakeIWH(fWidth, fHeight))); - // The SkAtlasTextRenderer currently only handles grayscale SDF glyphs. - if (op->maskType() != GrAtlasTextOp::kGrayscaleDistanceField_MaskType) { - return; - } - const GrCaps& caps = *this->context()->internal().grContext()->priv().caps(); - op->finalizeForTextTarget(fColor, caps); - int n = std::min(kMaxBatchLookBack, fOps.count()); - - GrRecordingContext::Arenas arenas = this->arenas(); - for (int i = 0; i < n; ++i) { - GrAtlasTextOp* other = fOps.fromBack(i).get(); - if (other->combineIfPossible(op.get(), &arenas, caps) == GrOp::CombineResult::kMerged) { - arenas.opMemoryPool()->release(std::move(op)); - return; - } - if (GrRectsOverlap(op->bounds(), other->bounds())) { - break; - } - } - fOps.emplace_back(std::move(op)); -} - -void SkInternalAtlasTextTarget::deleteOps() { - GrOpMemoryPool* pool = this->arenas().opMemoryPool(); - for (int i = 0; i < fOps.count(); ++i) { - if (fOps[i]) { - pool->release(std::move(fOps[i])); - } - } - fOps.reset(); -} - -void SkInternalAtlasTextTarget::flush() { - for (int i = 0; i < fOps.count(); ++i) { - fOps[i]->executeForTextTarget(this); - } - this->context()->internal().flush(); - this->deleteOps(); -} - -void GrAtlasTextOp::finalizeForTextTarget(uint32_t color, const GrCaps& caps) { - // TODO4F: Odd handling of client colors among AtlasTextTarget and AtlasTextRenderer - SkPMColor4f color4f = SkPMColor4f::FromBytes_RGBA(color); - for (int i = 0; i < fGeoCount; ++i) { - fGeoData[i].fColor = color4f; - } - // Atlas text doesn't use MSAA, so no need to handle mixed samples. - // Also, no need to support normalized F16 with manual clamp? - this->finalize(caps, nullptr /* applied clip */, false /* mixed samples */, GrClampType::kAuto); -} - -void GrAtlasTextOp::executeForTextTarget(SkAtlasTextTarget* target) { - auto& context = target->context()->internal(); - auto atlasManager = context.grContext()->priv().getAtlasManager(); - auto resourceProvider = context.grContext()->priv().resourceProvider(); - - unsigned int numProxies; - if (!atlasManager->getViews(kA8_GrMaskFormat, &numProxies)) { - return; - } - - for (int i = 0; i < fGeoCount; ++i) { - auto subRun = fGeoData[i].fSubRunPtr; - subRun->prepareGrGlyphs(context.grContext()->priv().getGrStrikeCache()); - // TODO4F: Preserve float colors - subRun->updateVerticesColorIfNeeded(fGeoData[i].fColor.toBytes_RGBA()); - subRun->translateVerticesIfNeeded(fGeoData[i].fDrawMatrix, fGeoData[i].fDrawOrigin); - GrTextBlob::VertexRegenerator regenerator(resourceProvider, subRun, &context, atlasManager); - int subRunEnd = subRun->fGlyphs.count(); - for (int subRunIndex = 0; subRunIndex < subRunEnd;) { - auto [ok, glyphsRegenerated] = regenerator.regenerate(subRunIndex, subRunEnd); - if (!ok) { - break; - } - - context.recordDraw(subRun->quadStart(subRunIndex), glyphsRegenerated, - fGeoData[i].fDrawMatrix, target->handle()); - subRunIndex += glyphsRegenerated; - if (subRunIndex != subRunEnd) { - // Make space in the atlas so we can continue generating vertices. - context.flush(); - } - } - } -} diff --git a/chromium/third_party/skia/src/atlastext/SkInternalAtlasTextContext.cpp b/chromium/third_party/skia/src/atlastext/SkInternalAtlasTextContext.cpp deleted file mode 100644 index afab657f748..00000000000 --- a/chromium/third_party/skia/src/atlastext/SkInternalAtlasTextContext.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "include/atlastext/SkAtlasTextContext.h" -#include "include/atlastext/SkAtlasTextRenderer.h" -#include "include/gpu/GrContext.h" -#include "src/atlastext/SkInternalAtlasTextContext.h" -#include "src/gpu/GrContextPriv.h" -#include "src/gpu/text/GrAtlasManager.h" -#include "src/gpu/text/GrStrikeCache.h" - -SkAtlasTextRenderer* SkGetAtlasTextRendererFromInternalContext( - class SkInternalAtlasTextContext& internal) { - return internal.renderer(); -} - -////////////////////////////////////////////////////////////////////////////// - -std::unique_ptr<SkInternalAtlasTextContext> SkInternalAtlasTextContext::Make( - sk_sp<SkAtlasTextRenderer> renderer) { - return std::unique_ptr<SkInternalAtlasTextContext>( - new SkInternalAtlasTextContext(std::move(renderer))); -} - -SkInternalAtlasTextContext::SkInternalAtlasTextContext(sk_sp<SkAtlasTextRenderer> renderer) - : fRenderer(std::move(renderer)) { - GrContextOptions options; - options.fAllowMultipleGlyphCacheTextures = GrContextOptions::Enable::kNo; - options.fMinDistanceFieldFontSize = 0.f; - options.fGlyphsAsPathsFontSize = SK_ScalarInfinity; - options.fDistanceFieldGlyphVerticesAlwaysHaveW = GrContextOptions::Enable::kYes; - fGrContext = GrContext::MakeMock(nullptr, options); -} - -SkInternalAtlasTextContext::~SkInternalAtlasTextContext() { - if (fDistanceFieldAtlas.fProxy) { -#ifdef SK_DEBUG - auto atlasManager = fGrContext->priv().getAtlasManager(); - if (atlasManager) { - unsigned int numProxies; - atlasManager->getViews(kA8_GrMaskFormat, &numProxies); - SkASSERT(1 == numProxies); - } -#endif - fRenderer->deleteTexture(fDistanceFieldAtlas.fTextureHandle); - } -} - -GrTextBlobCache* SkInternalAtlasTextContext::textBlobCache() { - return fGrContext->priv().getTextBlobCache(); -} - -GrDeferredUploadToken SkInternalAtlasTextContext::addInlineUpload( - GrDeferredTextureUploadFn&& upload) { - auto token = fTokenTracker.nextDrawToken(); - fInlineUploads.append(&fArena, InlineUpload{std::move(upload), token}); - return token; -} - -GrDeferredUploadToken SkInternalAtlasTextContext::addASAPUpload( - GrDeferredTextureUploadFn&& upload) { - fASAPUploads.append(&fArena, std::move(upload)); - return fTokenTracker.nextTokenToFlush(); -} - -void SkInternalAtlasTextContext::recordDraw(const void* srcVertexData, int glyphCnt, - const SkMatrix& matrix, void* targetHandle) { - auto vertexDataSize = sizeof(SkAtlasTextRenderer::SDFVertex) * 4 * glyphCnt; - auto vertexData = fArena.makeArrayDefault<char>(vertexDataSize); - memcpy(vertexData, srcVertexData, vertexDataSize); - for (int i = 0; i < 4 * glyphCnt; ++i) { - auto* vertex = reinterpret_cast<SkAtlasTextRenderer::SDFVertex*>(vertexData) + i; - // GrTextContext encodes a texture index into the lower bit of each texture coord. - // This isn't expected by SkAtlasTextRenderer subclasses. - vertex->fTextureCoordX /= 2; - vertex->fTextureCoordY /= 2; - matrix.mapHomogeneousPoints(&vertex->fPosition, &vertex->fPosition, 1); - } - fDraws.append(&fArena, - Draw{glyphCnt, fTokenTracker.issueDrawToken(), targetHandle, vertexData}); -} - -void SkInternalAtlasTextContext::flush() { - auto* atlasManager = fGrContext->priv().getAtlasManager(); - if (!fDistanceFieldAtlas.fProxy) { - unsigned int numProxies; - fDistanceFieldAtlas.fProxy = - atlasManager->getViews(kA8_GrMaskFormat, &numProxies)->asTextureProxy(); - SkASSERT(1 == numProxies); - fDistanceFieldAtlas.fTextureHandle = - fRenderer->createTexture(SkAtlasTextRenderer::AtlasFormat::kA8, - fDistanceFieldAtlas.fProxy->width(), - fDistanceFieldAtlas.fProxy->height()); - } - GrDeferredTextureUploadWritePixelsFn writePixelsFn = - [this](GrTextureProxy* proxy, int left, int top, int width, int height, - GrColorType colorType, const void* data, size_t rowBytes) -> bool { - SkASSERT(GrColorType::kAlpha_8 == colorType); - SkASSERT(proxy == this->fDistanceFieldAtlas.fProxy); - void* handle = fDistanceFieldAtlas.fTextureHandle; - this->fRenderer->setTextureData(handle, data, left, top, width, height, rowBytes); - return true; - }; - for (const auto& upload : fASAPUploads) { - upload(writePixelsFn); - } - auto inlineUpload = fInlineUploads.begin(); - for (const auto& draw : fDraws) { - while (inlineUpload != fInlineUploads.end() && inlineUpload->fToken == draw.fToken) { - inlineUpload->fUpload(writePixelsFn); - ++inlineUpload; - } - auto vertices = reinterpret_cast<const SkAtlasTextRenderer::SDFVertex*>(draw.fVertexData); - fRenderer->drawSDFGlyphs(draw.fTargetHandle, fDistanceFieldAtlas.fTextureHandle, vertices, - draw.fGlyphCnt); - fTokenTracker.flushToken(); - } - fASAPUploads.reset(); - fInlineUploads.reset(); - fDraws.reset(); - fArena.reset(); -} diff --git a/chromium/third_party/skia/src/atlastext/SkInternalAtlasTextContext.h b/chromium/third_party/skia/src/atlastext/SkInternalAtlasTextContext.h deleted file mode 100644 index 81b6df02e54..00000000000 --- a/chromium/third_party/skia/src/atlastext/SkInternalAtlasTextContext.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2017 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkInternalAtlasTextContext_DEFINED -#define SkInternalAtlasTextContext_DEFINED - -#include "include/core/SkRefCnt.h" -#include "src/core/SkArenaAlloc.h" -#include "src/core/SkArenaAllocList.h" -#include "src/gpu/GrDeferredUpload.h" - -class GrContext; -class GrStrikeCache; -class GrTextBlobCache; - -class SkAtlasTextRenderer; -class SkMatrix; - -/** - * The implementation of SkAtlasTextContext. This exists to hide the details from the public class. - * and to be able to use other private types. - */ -class SkInternalAtlasTextContext : public GrDeferredUploadTarget { -public: - static std::unique_ptr<SkInternalAtlasTextContext> Make(sk_sp<SkAtlasTextRenderer>); - - ~SkInternalAtlasTextContext() override; - - SkAtlasTextRenderer* renderer() const { return fRenderer.get(); } - - GrContext* grContext() const { return fGrContext.get(); } - GrTextBlobCache* textBlobCache(); - - const GrTokenTracker* tokenTracker() final { return &fTokenTracker; } - GrDeferredUploadToken addInlineUpload(GrDeferredTextureUploadFn&&) final; - GrDeferredUploadToken addASAPUpload(GrDeferredTextureUploadFn&&) final; - - void recordDraw(const void* vertexData, int glyphCnt, const SkMatrix&, void* targetHandle); - - void flush(); - -private: - class DeferredUploader; - SkInternalAtlasTextContext() = delete; - SkInternalAtlasTextContext(const SkInternalAtlasTextContext&) = delete; - SkInternalAtlasTextContext& operator=(const SkInternalAtlasTextContext&) = delete; - - SkInternalAtlasTextContext(sk_sp<SkAtlasTextRenderer>); - - sk_sp<SkAtlasTextRenderer> fRenderer; - - struct AtlasTexture { - void* fTextureHandle = nullptr; - GrTextureProxy* fProxy = nullptr; - }; - - struct Draw { - int fGlyphCnt; - GrDeferredUploadToken fToken; - void* fTargetHandle; - const void* fVertexData; - }; - - struct InlineUpload { - GrDeferredTextureUploadFn fUpload; - GrDeferredUploadToken fToken; - }; - - GrTokenTracker fTokenTracker; - SkArenaAllocList<InlineUpload> fInlineUploads; - SkArenaAllocList<Draw> fDraws; - SkArenaAllocList<GrDeferredTextureUploadFn> fASAPUploads; - SkArenaAlloc fArena{1024 * 40}; - sk_sp<GrContext> fGrContext; - AtlasTexture fDistanceFieldAtlas; -}; - -#endif diff --git a/chromium/third_party/skia/src/codec/SkBmpCodec.cpp b/chromium/third_party/skia/src/codec/SkBmpCodec.cpp index 615c8a42125..c113f6da153 100644 --- a/chromium/third_party/skia/src/codec/SkBmpCodec.cpp +++ b/chromium/third_party/skia/src/codec/SkBmpCodec.cpp @@ -394,7 +394,7 @@ SkCodec::Result SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, inputFormat = kRLE_BmpInputFormat; break; } - // Fall through + [[fallthrough]]; case kPng_BmpCompressionMethod: // TODO: Decide if we intend to support this. // It is unsupported in the previous version and diff --git a/chromium/third_party/skia/src/codec/SkCodecPriv.h b/chromium/third_party/skia/src/codec/SkCodecPriv.h index 2f77fc70e22..b371a31483d 100644 --- a/chromium/third_party/skia/src/codec/SkCodecPriv.h +++ b/chromium/third_party/skia/src/codec/SkCodecPriv.h @@ -141,7 +141,7 @@ static inline size_t compute_row_bytes(int width, uint32_t bitsPerPixel) { * Get a byte from a buffer * This method is unsafe, the caller is responsible for performing a check */ -static inline uint8_t get_byte(uint8_t* buffer, uint32_t i) { +static inline uint8_t get_byte(const uint8_t* buffer, uint32_t i) { return buffer[i]; } @@ -149,7 +149,7 @@ static inline uint8_t get_byte(uint8_t* buffer, uint32_t i) { * Get a short from a buffer * This method is unsafe, the caller is responsible for performing a check */ -static inline uint16_t get_short(uint8_t* buffer, uint32_t i) { +static inline uint16_t get_short(const uint8_t* buffer, uint32_t i) { uint16_t result; memcpy(&result, &(buffer[i]), 2); #ifdef SK_CPU_BENDIAN @@ -163,7 +163,7 @@ static inline uint16_t get_short(uint8_t* buffer, uint32_t i) { * Get an int from a buffer * This method is unsafe, the caller is responsible for performing a check */ -static inline uint32_t get_int(uint8_t* buffer, uint32_t i) { +static inline uint32_t get_int(const uint8_t* buffer, uint32_t i) { uint32_t result; memcpy(&result, &(buffer[i]), 4); #ifdef SK_CPU_BENDIAN diff --git a/chromium/third_party/skia/src/codec/SkIcoCodec.cpp b/chromium/third_party/skia/src/codec/SkIcoCodec.cpp index e70a9cded42..0aaf5e0aa18 100644 --- a/chromium/third_party/skia/src/codec/SkIcoCodec.cpp +++ b/chromium/third_party/skia/src/codec/SkIcoCodec.cpp @@ -13,6 +13,7 @@ #include "src/codec/SkCodecPriv.h" #include "src/codec/SkIcoCodec.h" #include "src/codec/SkPngCodec.h" +#include "src/core/SkStreamPriv.h" #include "src/core/SkTSort.h" /* @@ -28,20 +29,35 @@ bool SkIcoCodec::IsIco(const void* buffer, size_t bytesRead) { std::unique_ptr<SkCodec> SkIcoCodec::MakeFromStream(std::unique_ptr<SkStream> stream, Result* result) { + // It is helpful to have the entire stream in a contiguous buffer. In some cases, + // this is already the case anyway, so this method is faster. In others, this is + // safer than the old method, which required allocating a block of memory whose + // byte size is stored in the stream as a uint32_t, and may result in a large or + // failed allocation. + sk_sp<SkData> data = nullptr; + if (stream->getMemoryBase()) { + // It is safe to make without copy because we'll hold onto the stream. + data = SkData::MakeWithoutCopy(stream->getMemoryBase(), stream->getLength()); + } else { + data = SkCopyStreamToData(stream.get()); + + // If we are forced to copy the stream to a data, we can go ahead and delete the stream. + stream.reset(nullptr); + } + // Header size constants constexpr uint32_t kIcoDirectoryBytes = 6; constexpr uint32_t kIcoDirEntryBytes = 16; // Read the directory header - std::unique_ptr<uint8_t[]> dirBuffer(new uint8_t[kIcoDirectoryBytes]); - if (stream->read(dirBuffer.get(), kIcoDirectoryBytes) != kIcoDirectoryBytes) { + if (data->size() < kIcoDirectoryBytes) { SkCodecPrintf("Error: unable to read ico directory header.\n"); *result = kIncompleteInput; return nullptr; } // Process the directory header - const uint16_t numImages = get_short(dirBuffer.get(), 4); + const uint16_t numImages = get_short(data->bytes(), 4); if (0 == numImages) { SkCodecPrintf("Error: No images embedded in ico.\n"); *result = kInvalidInput; @@ -66,8 +82,8 @@ std::unique_ptr<SkCodec> SkIcoCodec::MakeFromStream(std::unique_ptr<SkStream> st // Iterate over directory entries for (uint32_t i = 0; i < numImages; i++) { - uint8_t entryBuffer[kIcoDirEntryBytes]; - if (stream->read(entryBuffer, kIcoDirEntryBytes) != kIcoDirEntryBytes) { + const uint8_t* entryBuffer = data->bytes() + kIcoDirectoryBytes + i * kIcoDirEntryBytes; + if (data->size() < kIcoDirectoryBytes + (i+1) * kIcoDirEntryBytes) { SkCodecPrintf("Error: Dir entries truncated in ico.\n"); *result = kIncompleteInput; return nullptr; @@ -123,45 +139,36 @@ std::unique_ptr<SkCodec> SkIcoCodec::MakeFromStream(std::unique_ptr<SkStream> st // If we cannot skip, assume we have reached the end of the stream and // stop trying to make codecs - if (stream->skip(offset - bytesRead) != offset - bytesRead) { + if (offset >= data->size()) { SkCodecPrintf("Warning: could not skip to ico offset.\n"); break; } bytesRead = offset; - // Create a new stream for the embedded codec - SkAutoFree buffer(sk_malloc_canfail(size)); - if (!buffer) { - SkCodecPrintf("Warning: OOM trying to create embedded stream.\n"); - break; - } - - if (stream->read(buffer.get(), size) != size) { + if (offset + size > data->size()) { SkCodecPrintf("Warning: could not create embedded stream.\n"); *result = kIncompleteInput; break; } - sk_sp<SkData> data(SkData::MakeFromMalloc(buffer.release(), size)); - auto embeddedStream = SkMemoryStream::Make(data); + sk_sp<SkData> embeddedData(SkData::MakeSubset(data.get(), offset, size)); + auto embeddedStream = SkMemoryStream::Make(embeddedData); bytesRead += size; // Check if the embedded codec is bmp or png and create the codec std::unique_ptr<SkCodec> codec; Result dummyResult; - if (SkPngCodec::IsPng((const char*) data->bytes(), data->size())) { + if (SkPngCodec::IsPng(embeddedData->bytes(), embeddedData->size())) { codec = SkPngCodec::MakeFromStream(std::move(embeddedStream), &dummyResult); } else { codec = SkBmpCodec::MakeFromIco(std::move(embeddedStream), &dummyResult); } - // Save a valid codec if (nullptr != codec) { codecs->push_back().reset(codec.release()); } } - // Recognize if there are no valid codecs if (0 == codecs->count()) { SkCodecPrintf("Error: could not find any valid embedded ico codecs.\n"); return nullptr; @@ -183,15 +190,15 @@ std::unique_ptr<SkCodec> SkIcoCodec::MakeFromStream(std::unique_ptr<SkStream> st auto maxInfo = codecs->operator[](maxIndex)->getEncodedInfo().copy(); *result = kSuccess; - // The original stream is no longer needed, because the embedded codecs own their - // own streams. - return std::unique_ptr<SkCodec>(new SkIcoCodec(std::move(maxInfo), codecs.release())); + return std::unique_ptr<SkCodec>(new SkIcoCodec(std::move(maxInfo), std::move(stream), + codecs.release())); } -SkIcoCodec::SkIcoCodec(SkEncodedInfo&& info, SkTArray<std::unique_ptr<SkCodec>, true>* codecs) +SkIcoCodec::SkIcoCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream, + SkTArray<std::unique_ptr<SkCodec>, true>* codecs) // The source skcms_PixelFormat will not be used. The embedded // codec's will be used instead. - : INHERITED(std::move(info), skcms_PixelFormat(), nullptr) + : INHERITED(std::move(info), skcms_PixelFormat(), std::move(stream)) , fEmbeddedCodecs(codecs) , fCurrCodec(nullptr) {} diff --git a/chromium/third_party/skia/src/codec/SkIcoCodec.h b/chromium/third_party/skia/src/codec/SkIcoCodec.h index c1b27dc50d8..9888dc2b3b9 100644 --- a/chromium/third_party/skia/src/codec/SkIcoCodec.h +++ b/chromium/third_party/skia/src/codec/SkIcoCodec.h @@ -86,7 +86,8 @@ private: * Constructor called by NewFromStream * @param embeddedCodecs codecs for the embedded images, takes ownership */ - SkIcoCodec(SkEncodedInfo&& info, SkTArray<std::unique_ptr<SkCodec>, true>* embeddedCodecs); + SkIcoCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>, + SkTArray<std::unique_ptr<SkCodec>, true>* embeddedCodecs); std::unique_ptr<SkTArray<std::unique_ptr<SkCodec>, true>> fEmbeddedCodecs; diff --git a/chromium/third_party/skia/src/codec/SkPngCodec.cpp b/chromium/third_party/skia/src/codec/SkPngCodec.cpp index c17070c07c0..df77b3aac09 100644 --- a/chromium/third_party/skia/src/codec/SkPngCodec.cpp +++ b/chromium/third_party/skia/src/codec/SkPngCodec.cpp @@ -1018,8 +1018,7 @@ SkCodec::Result SkPngCodec::initializeXforms(const SkImageInfo& dstInfo, const O if (this->getEncodedInfo().bitsPerComponent() != 16) { break; } - - // Fall through + [[fallthrough]]; case SkEncodedInfo::kRGBA_Color: case SkEncodedInfo::kGray_Color: skipFormatConversion = this->colorXform(); diff --git a/chromium/third_party/skia/src/codec/SkWebpCodec.cpp b/chromium/third_party/skia/src/codec/SkWebpCodec.cpp index 6cea0c621c5..e9019572cdf 100644 --- a/chromium/third_party/skia/src/codec/SkWebpCodec.cpp +++ b/chromium/third_party/skia/src/codec/SkWebpCodec.cpp @@ -143,7 +143,7 @@ std::unique_ptr<SkCodec> SkWebpCodec::MakeFromStream(std::unique_ptr<SkStream> s // sense to guess kBGRA which is likely closer to the final // output. Otherwise, we might end up converting // BGRA->YUVA->BGRA. - // Fallthrough: + [[fallthrough]]; case 2: // This is the lossless format (BGRA). if (hasAlpha) { @@ -224,9 +224,7 @@ int SkWebpCodec::onGetRepetitionCount() { return kRepetitionCountInfinite; } -#ifndef SK_LEGACY_WEBP_LOOP_COUNT loopCount--; -#endif return loopCount; } diff --git a/chromium/third_party/skia/src/codec/SkWuffsCodec.cpp b/chromium/third_party/skia/src/codec/SkWuffsCodec.cpp index 88394b3c80b..d7e11eba242 100644 --- a/chromium/third_party/skia/src/codec/SkWuffsCodec.cpp +++ b/chromium/third_party/skia/src/codec/SkWuffsCodec.cpp @@ -35,7 +35,11 @@ #if defined(WUFFS_IMPLEMENTATION) #error "SkWuffsCodec should not #define WUFFS_IMPLEMENTATION" #endif +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 +#include "wuffs-v0.3.c" +#else #include "wuffs-v0.2.c" +#endif #if WUFFS_VERSION_BUILD_METADATA_COMMIT_COUNT < 1942 #error "Wuffs version is too old. Upgrade to the latest version." #endif @@ -84,6 +88,8 @@ static bool seek_buffer(wuffs_base__io_buffer* b, SkStream* s, uint64_t pos) { return true; } +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 +#else static SkEncodedInfo::Alpha wuffs_blend_to_skia_alpha(wuffs_base__animation_blend w) { return (w == WUFFS_BASE__ANIMATION_BLEND__OPAQUE) ? SkEncodedInfo::kOpaque_Alpha : SkEncodedInfo::kUnpremul_Alpha; @@ -93,6 +99,7 @@ static SkCodecAnimation::Blend wuffs_blend_to_skia_blend(wuffs_base__animation_b return (w == WUFFS_BASE__ANIMATION_BLEND__SRC) ? SkCodecAnimation::Blend::kBG : SkCodecAnimation::Blend::kPriorFrame; } +#endif static SkCodecAnimation::DisposalMethod wuffs_disposal_to_skia_disposal( wuffs_base__animation_disposal w) { @@ -116,8 +123,25 @@ static SkCodec::Result reset_and_decode_image_config(wuffs_gif__decoder* d SkStream* s) { // Calling decoder->initialize will memset most or all of it to zero, // depending on SK_WUFFS_INITIALIZE_FLAGS. - const char* status = + wuffs_base__status status = decoder->initialize(sizeof__wuffs_gif__decoder(), WUFFS_VERSION, SK_WUFFS_INITIALIZE_FLAGS); +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + if (status.repr != nullptr) { + SkCodecPrintf("initialize: %s", status.message()); + return SkCodec::kInternalError; + } + while (true) { + status = decoder->decode_image_config(imgcfg, b); + if (status.repr == nullptr) { + break; + } else if (status.repr != wuffs_base__suspension__short_read) { + SkCodecPrintf("decode_image_config: %s", status.message()); + return SkCodec::kErrorInInput; + } else if (!fill_buffer(b, s)) { + return SkCodec::kIncompleteInput; + } + } +#else if (status != nullptr) { SkCodecPrintf("initialize: %s", status); return SkCodec::kInternalError; @@ -133,12 +157,13 @@ static SkCodec::Result reset_and_decode_image_config(wuffs_gif__decoder* d return SkCodec::kIncompleteInput; } } +#endif // A GIF image's natural color model is indexed color: 1 byte per pixel, // indexing a 256-element palette. // // For Skia, we override that to decode to 4 bytes per pixel, BGRA or RGBA. - wuffs_base__pixel_format pixfmt = 0; + uint32_t pixfmt = WUFFS_BASE__PIXEL_FORMAT__INVALID; switch (kN32_SkColorType) { case kBGRA_8888_SkColorType: pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL; @@ -266,12 +291,12 @@ private: // RGB565). But as an optimization, we use one pass decoding (it's faster // and uses less memory) if applicable (see the assignment to // fIncrDecOnePass that calculates when we can do so). - Result onStartIncrementalDecodeOnePass(const SkImageInfo& dstInfo, - uint8_t* dst, - size_t rowBytes, - const SkCodec::Options& options, - wuffs_base__pixel_format pixelFormat, - size_t bytesPerPixel); + Result onStartIncrementalDecodeOnePass(const SkImageInfo& dstInfo, + uint8_t* dst, + size_t rowBytes, + const SkCodec::Options& options, + uint32_t pixelFormat, + size_t bytesPerPixel); Result onStartIncrementalDecodeTwoPass(); Result onIncrementalDecodeOnePass(); Result onIncrementalDecodeTwoPass(); @@ -334,12 +359,23 @@ private: SkWuffsFrame::SkWuffsFrame(wuffs_base__frame_config* fc) : INHERITED(fc->index()), fIOPosition(fc->io_position()), - fReportedAlpha(wuffs_blend_to_skia_alpha(fc->blend())) { +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + fReportedAlpha(fc->opaque_within_bounds() ? SkEncodedInfo::kOpaque_Alpha + : SkEncodedInfo::kUnpremul_Alpha) +#else + fReportedAlpha(wuffs_blend_to_skia_alpha(fc->blend())) +#endif +{ wuffs_base__rect_ie_u32 r = fc->bounds(); this->setXYWH(r.min_incl_x, r.min_incl_y, r.width(), r.height()); this->setDisposalMethod(wuffs_disposal_to_skia_disposal(fc->disposal())); this->setDuration(fc->duration() / WUFFS_BASE__FLICKS_PER_MILLISECOND); +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + this->setBlend(fc->overwrite_instead_of_blend() ? SkCodecAnimation::Blend::kBG + : SkCodecAnimation::Blend::kPriorFrame); +#else this->setBlend(wuffs_blend_to_skia_blend(fc->blend())); +#endif } SkCodec::FrameInfo SkWuffsFrame::frameInfo(bool fullyReceived) const { @@ -482,8 +518,8 @@ SkCodec::Result SkWuffsCodec::onStartIncrementalDecode(const SkImageInfo& d return SkCodec::kErrorInInput; } - wuffs_base__pixel_format pixelFormat = WUFFS_BASE__PIXEL_FORMAT__INVALID; - size_t bytesPerPixel = 0; + uint32_t pixelFormat = WUFFS_BASE__PIXEL_FORMAT__INVALID; + size_t bytesPerPixel = 0; switch (dstInfo.colorType()) { case kBGRA_8888_SkColorType: @@ -527,11 +563,11 @@ SkCodec::Result SkWuffsCodec::onStartIncrementalDecode(const SkImageInfo& d return SkCodec::kSuccess; } -SkCodec::Result SkWuffsCodec::onStartIncrementalDecodeOnePass(const SkImageInfo& dstInfo, - uint8_t* dst, - size_t rowBytes, - const SkCodec::Options& options, - wuffs_base__pixel_format pixelFormat, +SkCodec::Result SkWuffsCodec::onStartIncrementalDecodeOnePass(const SkImageInfo& dstInfo, + uint8_t* dst, + size_t rowBytes, + const SkCodec::Options& options, + uint32_t pixelFormat, size_t bytesPerPixel) { wuffs_base__pixel_config pixelConfig; pixelConfig.set(pixelFormat, WUFFS_BASE__PIXEL_SUBSAMPLING__NONE, dstInfo.width(), @@ -543,11 +579,18 @@ SkCodec::Result SkWuffsCodec::onStartIncrementalDecodeOnePass(const SkImageInfo& table.height = dstInfo.height(); table.stride = rowBytes; - const char* status = fPixelBuffer.set_from_table(&pixelConfig, table); + wuffs_base__status status = fPixelBuffer.set_from_table(&pixelConfig, table); +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + if (status.repr != nullptr) { + SkCodecPrintf("set_from_table: %s", status.message()); + return SkCodec::kInternalError; + } +#else if (status != nullptr) { SkCodecPrintf("set_from_table: %s", status); return SkCodec::kInternalError; } +#endif SkSampler::Fill(dstInfo, dst, rowBytes, options.fZeroInitialized); return SkCodec::kSuccess; @@ -571,16 +614,27 @@ SkCodec::Result SkWuffsCodec::onStartIncrementalDecodeTwoPass() { already_zeroed = true; } - const char* status = fPixelBuffer.set_from_slice( + wuffs_base__status status = fPixelBuffer.set_from_slice( &fPixelConfig, wuffs_base__make_slice_u8(fTwoPassPixbufPtr.get(), fTwoPassPixbufLen)); +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + if (status.repr != nullptr) { + SkCodecPrintf("set_from_slice: %s", status.message()); + return SkCodec::kInternalError; + } +#else if (status != nullptr) { SkCodecPrintf("set_from_slice: %s", status); return SkCodec::kInternalError; } +#endif if (!already_zeroed) { +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + uint32_t src_bits_per_pixel = fPixelConfig.pixel_format().bits_per_pixel(); +#else uint32_t src_bits_per_pixel = wuffs_base__pixel_format__bits_per_pixel(fPixelConfig.pixel_format()); +#endif if ((src_bits_per_pixel == 0) || (src_bits_per_pixel % 8 != 0)) { return SkCodec::kInternalError; } @@ -683,8 +737,12 @@ SkCodec::Result SkWuffsCodec::onIncrementalDecodeTwoPass() { } } +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + uint32_t src_bits_per_pixel = fPixelBuffer.pixcfg.pixel_format().bits_per_pixel(); +#else uint32_t src_bits_per_pixel = wuffs_base__pixel_format__bits_per_pixel(fPixelBuffer.pixcfg.pixel_format()); +#endif if ((src_bits_per_pixel == 0) || (src_bits_per_pixel % 8 != 0)) { return SkCodec::kInternalError; } @@ -755,7 +813,7 @@ SkCodec::Result SkWuffsCodec::onIncrementalDecodeTwoPass() { SkRasterClip rc(SkIRect::MakeSize(this->dstInfo().dimensions())); draw.fRC = &rc; - SkMatrix translate = SkMatrix::MakeTrans(dirty_rect.min_incl_x, dirty_rect.min_incl_y); + SkMatrix translate = SkMatrix::Translate(dirty_rect.min_incl_x, dirty_rect.min_incl_y); draw.drawBitmap(src, translate, nullptr, paint); } @@ -821,7 +879,11 @@ void SkWuffsCodec::onGetFrameCountInternal() { const char* status = this->decodeFrameConfig(WhichDecoder::kFrameCount); if (status == nullptr) { // No-op. +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + } else if (status == wuffs_base__note__end_of_data) { +#else } else if (status == wuffs_base__warning__end_of_data) { +#endif break; } else { return; @@ -893,11 +955,17 @@ SkCodec::Result SkWuffsCodec::seekFrame(WhichDecoder which, int frameIndex) { if (!seek_buffer(&fIOBuffer, fStream.get(), pos)) { return SkCodec::kInternalError; } - const char* status = + wuffs_base__status status = fDecoders[which]->restart_frame(frameIndex, fIOBuffer.reader_io_position()); +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + if (status.repr != nullptr) { + return SkCodec::kInternalError; + } +#else if (status != nullptr) { return SkCodec::kInternalError; } +#endif return SkCodec::kSuccess; } @@ -921,8 +989,17 @@ SkCodec::Result SkWuffsCodec::resetDecoder(WhichDecoder which) { const char* SkWuffsCodec::decodeFrameConfig(WhichDecoder which) { while (true) { - const char* status = + wuffs_base__status status = fDecoders[which]->decode_frame_config(&fFrameConfigs[which], &fIOBuffer); +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + if ((status.repr == wuffs_base__suspension__short_read) && + fill_buffer(&fIOBuffer, fStream.get())) { + continue; + } + fDecoderIsSuspended[which] = !status.is_complete(); + this->updateNumFullyReceivedFrames(which); + return status.repr; +#else if ((status == wuffs_base__suspension__short_read) && fill_buffer(&fIOBuffer, fStream.get())) { continue; @@ -930,11 +1007,24 @@ const char* SkWuffsCodec::decodeFrameConfig(WhichDecoder which) { fDecoderIsSuspended[which] = !wuffs_base__status__is_complete(status); this->updateNumFullyReceivedFrames(which); return status; +#endif } } const char* SkWuffsCodec::decodeFrame(WhichDecoder which) { while (true) { +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + wuffs_base__status status = fDecoders[which]->decode_frame( + &fPixelBuffer, &fIOBuffer, WUFFS_BASE__PIXEL_BLEND__SRC, + wuffs_base__make_slice_u8(fWorkbufPtr.get(), fWorkbufLen), NULL); + if ((status.repr == wuffs_base__suspension__short_read) && + fill_buffer(&fIOBuffer, fStream.get())) { + continue; + } + fDecoderIsSuspended[which] = !status.is_complete(); + this->updateNumFullyReceivedFrames(which); + return status.repr; +#else const char* status = fDecoders[which]->decode_frame( &fPixelBuffer, &fIOBuffer, wuffs_base__make_slice_u8(fWorkbufPtr.get(), fWorkbufLen), NULL); @@ -945,6 +1035,7 @@ const char* SkWuffsCodec::decodeFrame(WhichDecoder which) { fDecoderIsSuspended[which] = !wuffs_base__status__is_complete(status); this->updateNumFullyReceivedFrames(which); return status; +#endif } } @@ -1028,7 +1119,11 @@ std::unique_ptr<SkCodec> SkWuffsCodec_MakeFromStream(std::unique_ptr<SkStream> s reinterpret_cast<uint8_t*>(workbuf_ptr_raw), &sk_free); SkEncodedInfo::Color color = +#ifdef SK_FAVOR_WUFFS_V_0_3_OVER_V_0_2 + (imgcfg.pixcfg.pixel_format().repr == WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL) +#else (imgcfg.pixcfg.pixel_format() == WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL) +#endif ? SkEncodedInfo::kBGRA_Color : SkEncodedInfo::kRGBA_Color; diff --git a/chromium/third_party/skia/src/core/SkArenaAlloc.h b/chromium/third_party/skia/src/core/SkArenaAlloc.h index 6ff7c6be9f6..22aecb52de6 100644 --- a/chromium/third_party/skia/src/core/SkArenaAlloc.h +++ b/chromium/third_party/skia/src/core/SkArenaAlloc.h @@ -101,12 +101,9 @@ public: template <typename T> T* makeArrayDefault(size_t count) { - AssertRelease(SkTFitsIn<uint32_t>(count)); - uint32_t safeCount = ToU32(count); - T* array = (T*)this->commonArrayAlloc<T>(safeCount); - - // If T is primitive then no initialization takes place. - for (size_t i = 0; i < safeCount; i++) { + T* array = this->allocUninitializedArray<T>(count); + for (size_t i = 0; i < count; i++) { + // Default initialization: if T is primitive then the value is left uninitialized. new (&array[i]) T; } return array; @@ -114,18 +111,23 @@ public: template <typename T> T* makeArray(size_t count) { - AssertRelease(SkTFitsIn<uint32_t>(count)); - uint32_t safeCount = ToU32(count); - T* array = (T*)this->commonArrayAlloc<T>(safeCount); - - // If T is primitive then the memory is initialized. For example, an array of chars will - // be zeroed. - for (size_t i = 0; i < safeCount; i++) { + T* array = this->allocUninitializedArray<T>(count); + for (size_t i = 0; i < count; i++) { + // Value initialization: if T is primitive then the value is zero-initialized. new (&array[i]) T(); } return array; } + template <typename T, typename Initializer> + T* makeInitializedArray(size_t count, Initializer initializer) { + T* array = this->allocUninitializedArray<T>(count); + for (size_t i = 0; i < count; i++) { + new (&array[i]) T(initializer(i)); + } + return array; + } + // Only use makeBytesAlignedTo if none of the typed variants are impractical to use. void* makeBytesAlignedTo(size_t size, size_t align) { AssertRelease(SkTFitsIn<uint32_t>(size)); @@ -172,7 +174,10 @@ private: char* allocObjectWithFooter(uint32_t sizeIncludingFooter, uint32_t alignment); template <typename T> - char* commonArrayAlloc(uint32_t count) { + T* allocUninitializedArray(size_t countZ) { + AssertRelease(SkTFitsIn<uint32_t>(countZ)); + uint32_t count = ToU32(countZ); + char* objStart; AssertRelease(count <= std::numeric_limits<uint32_t>::max() / sizeof(T)); uint32_t arraySize = ToU32(count * sizeof(T)); @@ -208,7 +213,7 @@ private: padding); } - return objStart; + return (T*)objStart; } char* fDtorCursor; diff --git a/chromium/third_party/skia/src/core/SkBitmapDevice.cpp b/chromium/third_party/skia/src/core/SkBitmapDevice.cpp index 190182f390d..96e28a5d9f5 100644 --- a/chromium/third_party/skia/src/core/SkBitmapDevice.cpp +++ b/chromium/third_party/skia/src/core/SkBitmapDevice.cpp @@ -54,9 +54,9 @@ class SkDrawTiler { SkDraw fDraw; // fCurr... are only used if fNeedTiling - SkTLazy<SkPostConcatMatrixProvider> fTileMatrixProvider; - SkRasterClip fTileRC; - SkIPoint fOrigin; + SkTLazy<SkPostTranslateMatrixProvider> fTileMatrixProvider; + SkRasterClip fTileRC; + SkIPoint fOrigin; bool fDone, fNeedsTiling; @@ -164,9 +164,9 @@ private: SkASSERT_RELEASE(success); // now don't use bounds, since fDst has the clipped dimensions. - fDraw.fMatrixProvider = fTileMatrixProvider.init( - fDevice->asMatrixProvider(), - SkMatrix::MakeTrans(SkIntToScalar(-fOrigin.x()), SkIntToScalar(-fOrigin.y()))); + fDraw.fMatrixProvider = fTileMatrixProvider.init(fDevice->asMatrixProvider(), + SkIntToScalar(-fOrigin.x()), + SkIntToScalar(-fOrigin.y())); fDevice->fRCStack.rc().translate(-fOrigin.x(), -fOrigin.y(), &fTileRC); fTileRC.op(SkIRect::MakeWH(fDraw.fDst.width(), fDraw.fDst.height()), SkRegion::kIntersect_Op); @@ -574,7 +574,7 @@ void SkBitmapDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPain draw.fRC = &fRCStack.rc(); paint.writable()->setShader(src->fBitmap.makeShader()); draw.drawBitmap(*src->fCoverage.get(), - SkMatrix::MakeTrans(SkIntToScalar(x),SkIntToScalar(y)), nullptr, *paint); + SkMatrix::Translate(SkIntToScalar(x),SkIntToScalar(y)), nullptr, *paint); } else { BDDraw(this).drawSprite(src->fBitmap, x, y, *paint); } @@ -593,32 +593,7 @@ void SkBitmapDevice::drawAtlas(const SkImage* atlas, const SkRSXform xform[], /////////////////////////////////////////////////////////////////////////////// -namespace { - -class SkAutoDeviceClipRestore { -public: - SkAutoDeviceClipRestore(SkBaseDevice* device, const SkIRect& clip) - : fDevice(device) - , fPrevLocalToDevice(device->localToDevice44()) { - fDevice->save(); - fDevice->setLocalToDevice(SkM44()); - fDevice->clipRect(SkRect::Make(clip), SkClipOp::kIntersect, false); - fDevice->setLocalToDevice(fPrevLocalToDevice); - } - - ~SkAutoDeviceClipRestore() { - fDevice->restoreLocal(fPrevLocalToDevice); - } - -private: - SkBaseDevice* fDevice; - const SkM44 fPrevLocalToDevice; -}; - -} // anonymous ns - -void SkBitmapDevice::drawSpecial(SkSpecialImage* src, int x, int y, const SkPaint& origPaint, - SkImage* clipImage, const SkMatrix& clipMatrix) { +void SkBitmapDevice::drawSpecial(SkSpecialImage* src, int x, int y, const SkPaint& origPaint) { SkASSERT(!src->isTextureBacked()); SkASSERT(!origPaint.getMaskFilter()); @@ -628,7 +603,7 @@ void SkBitmapDevice::drawSpecial(SkSpecialImage* src, int x, int y, const SkPain if (SkImageFilter* filter = paint->getImageFilter()) { SkIPoint offset = SkIPoint::Make(0, 0); const SkMatrix matrix = SkMatrix::Concat( - SkMatrix::MakeTrans(SkIntToScalar(-x), SkIntToScalar(-y)), this->localToDevice()); + SkMatrix::Translate(SkIntToScalar(-x), SkIntToScalar(-y)), this->localToDevice()); const SkIRect clipBounds = fRCStack.rc().getBounds().makeOffset(-x, -y); sk_sp<SkImageFilterCache> cache(this->getImageFilterCache()); SkImageFilter_Base::Context ctx(matrix, clipBounds, cache.get(), fBitmap.colorType(), @@ -645,68 +620,10 @@ void SkBitmapDevice::drawSpecial(SkSpecialImage* src, int x, int y, const SkPain y += offset.y(); } - if (!clipImage) { - SkBitmap resultBM; - if (src->getROPixels(&resultBM)) { - BDDraw(this).drawSprite(resultBM, x, y, *paint); - } - return; + SkBitmap resultBM; + if (src->getROPixels(&resultBM)) { + BDDraw(this).drawSprite(resultBM, x, y, *paint); } - - // Clip image case. - sk_sp<SkImage> srcImage(src->asImage()); - if (!srcImage) { - return; - } - - const SkMatrix totalMatrix = SkMatrix::Concat(this->localToDevice(), clipMatrix); - SkRect clipBounds; - totalMatrix.mapRect(&clipBounds, SkRect::Make(clipImage->bounds())); - const SkIRect srcBounds = srcImage->bounds().makeOffset(x, y); - - SkIRect maskBounds = fRCStack.rc().getBounds(); - if (!maskBounds.intersect(clipBounds.roundOut()) || !maskBounds.intersect(srcBounds)) { - return; - } - - sk_sp<SkImage> mask; - SkMatrix maskMatrix, shaderMatrix; - SkTLazy<SkAutoDeviceClipRestore> autoClipRestore; - - SkMatrix totalInverse; - if (clipImage->isAlphaOnly() && totalMatrix.invert(&totalInverse)) { - // If the mask is already in A8 format, we can draw it directly - // (while compensating in the shader matrix). - mask = sk_ref_sp(clipImage); - maskMatrix = totalMatrix; - shaderMatrix = SkMatrix::Concat(totalInverse, SkMatrix::MakeTrans(x, y)); - - // If the mask is not fully contained within the src layer, we must clip. - if (!srcBounds.contains(clipBounds)) { - autoClipRestore.init(this, srcBounds); - } - - maskBounds.offsetTo(0, 0); - } else { - // Otherwise, we convert the mask to A8 explicitly. - sk_sp<SkSurface> surf = SkSurface::MakeRaster(SkImageInfo::MakeA8(maskBounds.width(), - maskBounds.height())); - SkCanvas* canvas = surf->getCanvas(); - canvas->translate(-maskBounds.x(), -maskBounds.y()); - canvas->concat(totalMatrix); - canvas->drawImage(clipImage, 0, 0); - - mask = surf->makeImageSnapshot(); - maskMatrix = SkMatrix::I(); - shaderMatrix = SkMatrix::MakeTrans(x - maskBounds.x(), y - maskBounds.y()); - } - - SkAutoDeviceTransformRestore adr(this, maskMatrix); - paint.writable()->setShader(srcImage->makeShader(&shaderMatrix)); - this->drawImageRect(mask.get(), nullptr, - SkRect::MakeXYWH(maskBounds.x(), maskBounds.y(), - mask->width(), mask->height()), - *paint, SkCanvas::kFast_SrcRectConstraint); } sk_sp<SkSpecialImage> SkBitmapDevice::makeSpecial(const SkBitmap& bitmap) { diff --git a/chromium/third_party/skia/src/core/SkBitmapDevice.h b/chromium/third_party/skia/src/core/SkBitmapDevice.h index f6e14216ee3..7c359ea886a 100644 --- a/chromium/third_party/skia/src/core/SkBitmapDevice.h +++ b/chromium/third_party/skia/src/core/SkBitmapDevice.h @@ -101,8 +101,7 @@ protected: /////////////////////////////////////////////////////////////////////////// - void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&, - SkImage*, const SkMatrix&) override; + void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&) override; sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override; sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override; sk_sp<SkSpecialImage> snapSpecial(const SkIRect&, bool = false) override; diff --git a/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp b/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp index d444b56c913..8fa1a0ba871 100755 --- a/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp +++ b/chromium/third_party/skia/src/core/SkBitmapProcState_matrixProcs.cpp @@ -64,7 +64,7 @@ static void decal_nofilter_scale(uint32_t dst[], SkFixed fx, SkFixed dx, int cou SkASSERT(count <= 2); switch (count) { - case 2: ((uint16_t*)dst)[1] = SkToU16((fx + dx) >> 16); + case 2: ((uint16_t*)dst)[1] = SkToU16((fx + dx) >> 16); [[fallthrough]]; case 1: ((uint16_t*)dst)[0] = SkToU16((fx + 0) >> 16); } } @@ -475,7 +475,7 @@ SkBitmapProcState::MatrixProc SkBitmapProcState::chooseMatrixProc(bool translate // Check for our special case translate methods when there is no scale/affine/perspective. if (translate_only_matrix && kNone_SkFilterQuality == fFilterQuality) { switch (fTileModeX) { - default: SkASSERT(false); + default: SkASSERT(false); [[fallthrough]]; case SkTileMode::kClamp: return clampx_nofilter_trans<int_clamp>; case SkTileMode::kRepeat: return repeatx_nofilter_trans<int_repeat>; case SkTileMode::kMirror: return mirrorx_nofilter_trans<int_mirror>; diff --git a/chromium/third_party/skia/src/core/SkBlitter.cpp b/chromium/third_party/skia/src/core/SkBlitter.cpp index 23373abe769..55fb32602d5 100644 --- a/chromium/third_party/skia/src/core/SkBlitter.cpp +++ b/chromium/third_party/skia/src/core/SkBlitter.cpp @@ -655,10 +655,7 @@ bool SkBlitter::UseRasterPipelineBlitter(const SkPixmap& device, const SkPaint& // The legacy blitters cannot handle any of these complex features (anymore). if (device.alphaType() == kUnpremul_SkAlphaType || - matrix.hasPerspective() || - paint.getColorFilter() || paint.getBlendMode() > SkBlendMode::kLastCoeffMode || - paint.getFilterQuality() == kHigh_SkFilterQuality || (mf && mf->getFormat() == SkMask::k3D_Format)) { return true; } @@ -739,19 +736,31 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, paint.writable()->setDither(false); } - SkMatrix ctm = matrixProvider.localToDevice(); if (gUseSkVMBlitter) { - if (auto blitter = SkCreateSkVMBlitter(device, *paint, ctm, alloc, clipShader)) { + if (auto blitter = SkCreateSkVMBlitter(device, *paint, matrixProvider, + alloc, clipShader)) { return blitter; } } + // Same basic idea used a few times: try SkRP, then try SkVM, then give up with a null-blitter. + // (Setting gUseSkVMBlitter is the only way we prefer SkVM over SkRP at the moment.) + auto create_SkRP_or_SkVMBlitter = [&]() -> SkBlitter* { + if (auto blitter = SkCreateRasterPipelineBlitter(device, *paint, matrixProvider, + alloc, clipShader)) { + return blitter; + } + if (auto blitter = SkCreateSkVMBlitter(device, *paint, matrixProvider, + alloc, clipShader)) { + return blitter; + } + return alloc->make<SkNullBlitter>(); + }; + + SkMatrix ctm = matrixProvider.localToDevice(); // We'll end here for many interesting cases: color spaces, color filters, most color types. if (UseRasterPipelineBlitter(device, *paint, ctm) || clipShader) { - auto blitter = - SkCreateRasterPipelineBlitter(device, *paint, matrixProvider, alloc, clipShader); - SkASSERT(blitter); - return blitter; + return create_SkRP_or_SkVMBlitter(); } // Everything but legacy kN32_SkColorType and kRGB_565_SkColorType should already be handled. @@ -768,12 +777,9 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, {*paint, ctm, nullptr, device.colorType(), device.colorSpace()}, alloc); - // Creating the context isn't always possible... we'll just fall back to raster pipeline. + // Creating the context isn't always possible... try fallbacks before giving up. if (!shaderContext) { - auto blitter = SkCreateRasterPipelineBlitter(device, *paint, matrixProvider, alloc, - clipShader); - SkASSERT(blitter); - return blitter; + return create_SkRP_or_SkVMBlitter(); } } @@ -793,8 +799,7 @@ SkBlitter* SkBlitter::Choose(const SkPixmap& device, if (shaderContext && SkRGB565_Shader_Blitter::Supports(device, *paint)) { return alloc->make<SkRGB565_Shader_Blitter>(device, *paint, shaderContext); } else { - return SkCreateRasterPipelineBlitter(device, *paint, matrixProvider, alloc, - clipShader); + return create_SkRP_or_SkVMBlitter(); } default: diff --git a/chromium/third_party/skia/src/core/SkBlitter_Sprite.cpp b/chromium/third_party/skia/src/core/SkBlitter_Sprite.cpp index df7d9a70258..05f25bec16c 100644 --- a/chromium/third_party/skia/src/core/SkBlitter_Sprite.cpp +++ b/chromium/third_party/skia/src/core/SkBlitter_Sprite.cpp @@ -134,7 +134,7 @@ public: : kPremul_SkAlphaType; fAlloc->make<SkColorSpaceXformSteps>(srcCS, srcAT, dstCS, kPremul_SkAlphaType) - ->apply(&p, fSource.colorType()); + ->apply(&p); } if (fPaintColor.fA != 1.0f) { p.append(SkRasterPipeline::scale_1_float, &fPaintColor.fA); @@ -142,6 +142,9 @@ public: bool is_opaque = fSource.isOpaque() && fPaintColor.fA == 1.0f; fBlitter = SkCreateRasterPipelineBlitter(fDst, paint, p, is_opaque, fAlloc, fClipShader); + if (!fBlitter) { + fBlitter = fAlloc->make<SkNullBlitter>(); + } } void blitRect(int x, int y, int width, int height) override { diff --git a/chromium/third_party/skia/src/core/SkBlurMF.cpp b/chromium/third_party/skia/src/core/SkBlurMF.cpp index 14be316a231..9665ab4d6eb 100644 --- a/chromium/third_party/skia/src/core/SkBlurMF.cpp +++ b/chromium/third_party/skia/src/core/SkBlurMF.cpp @@ -21,7 +21,6 @@ #if SK_SUPPORT_GPU #include "include/private/GrRecordingContext.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrFragmentProcessor.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRenderTargetContext.h" @@ -58,7 +57,7 @@ public: bool directFilterMaskGPU(GrRecordingContext*, GrRenderTargetContext* renderTargetContext, GrPaint&&, - const GrClip&, + const GrClip*, const SkMatrix& viewMatrix, const GrStyledShape& shape) const override; GrSurfaceProxyView filterMaskGPU(GrRecordingContext*, @@ -437,7 +436,7 @@ SkBlurMaskFilterImpl::filterRRectToNine(const SkRRect& rrect, const SkMatrix& ma case SkRRect::kRect_Type: // We should have caught this earlier. SkASSERT(false); - // Fall through. + [[fallthrough]]; case SkRRect::kOval_Type: // The nine patch special case does not handle ovals, and we // already have code for rectangles. @@ -722,7 +721,7 @@ void SkBlurMaskFilterImpl::flatten(SkWriteBuffer& buffer) const { bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrRecordingContext* context, GrRenderTargetContext* renderTargetContext, GrPaint&& paint, - const GrClip& clip, + const GrClip* clip, const SkMatrix& viewMatrix, const GrStyledShape& shape) const { SkASSERT(renderTargetContext); @@ -764,10 +763,12 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrRecordingContext* context, if (devRRect.isRect() || SkRRectPriv::IsCircle(devRRect)) { if (devRRect.isRect()) { - fp = GrRectBlurEffect::Make(context, *context->priv().caps()->shaderCaps(), - devRRect.rect(), xformedSigma); + fp = GrRectBlurEffect::Make( + /*inputFP=*/nullptr, context, *context->priv().caps()->shaderCaps(), + devRRect.rect(), xformedSigma); } else { - fp = GrCircleBlurFragmentProcessor::Make(context, devRRect.rect(), xformedSigma); + fp = GrCircleBlurFragmentProcessor::Make(/*inputFP=*/nullptr, context, devRRect.rect(), + xformedSigma); } if (!fp) { @@ -791,7 +792,8 @@ bool SkBlurMaskFilterImpl::directFilterMaskGPU(GrRecordingContext* context, return true; } - fp = GrRRectBlurEffect::Make(context, fSigma, xformedSigma, srcRRect, devRRect); + fp = GrRRectBlurEffect::Make(/*inputFP=*/nullptr, context, fSigma, xformedSigma, + srcRRect, devRRect); if (!fp) { return false; } @@ -854,15 +856,13 @@ bool SkBlurMaskFilterImpl::canFilterMaskGPU(const GrStyledShape& shape, } // We prefer to blur paths with small blur radii on the CPU. - if (ctm.rectStaysRect()) { - static const SkScalar kMIN_GPU_BLUR_SIZE = SkIntToScalar(64); - static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32); + static const SkScalar kMIN_GPU_BLUR_SIZE = SkIntToScalar(64); + static const SkScalar kMIN_GPU_BLUR_SIGMA = SkIntToScalar(32); - if (devSpaceShapeBounds.width() <= kMIN_GPU_BLUR_SIZE && - devSpaceShapeBounds.height() <= kMIN_GPU_BLUR_SIZE && - xformedSigma <= kMIN_GPU_BLUR_SIGMA) { - return false; - } + if (devSpaceShapeBounds.width() <= kMIN_GPU_BLUR_SIZE && + devSpaceShapeBounds.height() <= kMIN_GPU_BLUR_SIZE && + xformedSigma <= kMIN_GPU_BLUR_SIGMA) { + return false; } return true; @@ -917,7 +917,7 @@ GrSurfaceProxyView SkBlurMaskFilterImpl::filterMaskGPU(GrRecordingContext* conte paint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); } - renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), + renderTargetContext->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::Make(clipRect)); } diff --git a/chromium/third_party/skia/src/core/SkCanvas.cpp b/chromium/third_party/skia/src/core/SkCanvas.cpp index 2d73b3e06c9..8f7d2eac457 100644 --- a/chromium/third_party/skia/src/core/SkCanvas.cpp +++ b/chromium/third_party/skia/src/core/SkCanvas.cpp @@ -191,17 +191,12 @@ struct DeviceCM { SkRasterClip fClip; std::unique_ptr<const SkPaint> fPaint; // may be null (in the future) SkMatrix fStashedMatrix; // original CTM; used by imagefilter in saveLayer - sk_sp<SkImage> fClipImage; - SkMatrix fClipMatrix; - DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed, - const SkImage* clipImage, const SkMatrix* clipMatrix) + DeviceCM(sk_sp<SkBaseDevice> device, const SkPaint* paint, const SkMatrix& stashed) : fNext(nullptr) , fDevice(std::move(device)) , fPaint(paint ? std::make_unique<SkPaint>(*paint) : nullptr) , fStashedMatrix(stashed) - , fClipImage(sk_ref_sp(const_cast<SkImage*>(clipImage))) - , fClipMatrix(clipMatrix ? *clipMatrix : SkMatrix::I()) {} void reset(const SkIRect& bounds) { @@ -506,11 +501,12 @@ void SkCanvas::init(sk_sp<SkBaseDevice> device) { SkASSERT(sizeof(DeviceCM) <= sizeof(fDeviceCMStorage)); fMCRec->fLayer = (DeviceCM*)fDeviceCMStorage; - new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix.asM33(), nullptr, nullptr); + new (fDeviceCMStorage) DeviceCM(device, nullptr, fMCRec->fMatrix.asM33()); fMCRec->fTopLayer = fMCRec->fLayer; fSurfaceBase = nullptr; + fDeviceClipBounds = {0, 0, 0, 0}; if (device) { // The root device and the canvas should always have the same pixel geometry @@ -917,7 +913,7 @@ void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filt if (special) { // The image is drawn at 1-1 scale with integer translation, so no filtering is needed. SkPaint p; - dst->drawSpecial(special.get(), 0, 0, p, nullptr, SkMatrix::I()); + dst->drawSpecial(special.get(), 0, 0, p); } return; } @@ -930,7 +926,7 @@ void SkCanvas::DrawDeviceWithFilter(SkBaseDevice* src, const SkImageFilter* filt toRoot = SkMatrix::I(); layerMatrix = ctm; } else if (ctm.decomposeScale(&scale, &toRoot)) { - layerMatrix = SkMatrix::MakeScale(scale.fWidth, scale.fHeight); + layerMatrix = SkMatrix::Scale(scale.fWidth, scale.fHeight); } else { // Perspective, for now, do no scaling of the layer itself. // TODO (michaelludwig) - perhaps it'd be better to explore a heuristic scale pulled from @@ -1176,7 +1172,7 @@ void SkCanvas::internalSaveLayer(const SaveLayerRec& rec, SaveLayerStrategy stra } newDevice->setMarkerStack(fMarkerStack.get()); } - DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix, rec.fClipMask, rec.fClipMatrix); + DeviceCM* layer = new DeviceCM(newDevice, paint, stashedMatrix); // only have a "next" if this new layer doesn't affect the clip (rare) layer->fNext = BoundsAffectsClip(saveLayerFlags) ? nullptr : fMCRec->fTopLayer; @@ -1280,8 +1276,7 @@ void SkCanvas::internalRestore() { paint.setBlendMode(SkBlendMode::kDstOver); const int x = backImage->fLoc.x(); const int y = backImage->fLoc.y(); - this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint, - nullptr, SkMatrix::I()); + this->getTopDevice()->drawSpecial(backImage->fImage.get(), x, y, paint); } /* Time to draw the layer's offscreen. We can't call the public drawSprite, @@ -1293,8 +1288,7 @@ void SkCanvas::internalRestore() { layer->fDevice->setImmutable(); // At this point, 'layer' has been removed from the device stack, so the devices that // internalDrawDevice sees are the destinations that 'layer' is drawn into. - this->internalDrawDevice(layer->fDevice.get(), layer->fPaint.get(), - layer->fClipImage.get(), layer->fClipMatrix); + this->internalDrawDevice(layer->fDevice.get(), layer->fPaint.get()); // restore what we smashed in internalSaveLayer this->internalSetMatrix(layer->fStashedMatrix); delete layer; @@ -1404,8 +1398,7 @@ static void check_drawdevice_colorspaces(SkColorSpace* src, SkColorSpace* dst) { SkASSERT(src == dst); } -void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, const SkPaint* paint, - SkImage* clipImage, const SkMatrix& clipMatrix) { +void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, const SkPaint* paint) { SkPaint tmp; if (nullptr == paint) { paint = &tmp; @@ -1423,13 +1416,12 @@ void SkCanvas::internalDrawDevice(SkBaseDevice* srcDev, const SkPaint* paint, // so it should always be possible to use the relative origin. Once drawDevice() and // drawSpecial() take an SkMatrix, this can switch to getRelativeTransform() instead. SkIPoint pos = srcDev->getOrigin() - dstDev->getOrigin(); - if (filter || clipImage) { + if (filter) { sk_sp<SkSpecialImage> specialImage = srcDev->snapSpecial(); if (specialImage) { check_drawdevice_colorspaces(dstDev->imageInfo().colorSpace(), specialImage->getColorSpace()); - dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint, - clipImage, clipMatrix); + dstDev->drawSpecial(specialImage.get(), pos.x(), pos.y(), *paint); } } else { dstDev->drawDevice(srcDev, pos.x(), pos.y(), *paint); @@ -1659,6 +1651,7 @@ void SkCanvas::clipShader(sk_sp<SkShader> sh, SkClipOp op) { this->clipRect({0,0,0,0}); } } else { + this->checkForDeferredSave(); this->onClipShader(std::move(sh), op); } } @@ -1967,6 +1960,17 @@ void SkCanvas::drawVertices(const SkVertices* vertices, SkBlendMode mode, const } } +#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK + // Preserve legacy behavior for Android: ignore the SkShader if there are no texCoords present + if (paint.getShader() && + !(vertices->priv().hasTexCoords() || vertices->priv().hasCustomData())) { + SkPaint noShaderPaint(paint); + noShaderPaint.setShader(nullptr); + this->onDrawVerticesObject(vertices, mode, noShaderPaint); + return; + } +#endif + this->onDrawVerticesObject(vertices, mode, paint); } @@ -2497,8 +2501,7 @@ void SkCanvas::onDrawImage(const SkImage* image, SkScalar x, SkScalar y, const S iter.fDevice->localToDevice().mapXY(x, y, &pt); iter.fDevice->drawSpecial(special.get(), SkScalarRoundToInt(pt.fX), - SkScalarRoundToInt(pt.fY), pnt, - nullptr, SkMatrix::I()); + SkScalarRoundToInt(pt.fY), pnt); } else { iter.fDevice->drawImageRect( image, nullptr, SkRect::MakeXYWH(x, y, image->width(), image->height()), pnt, @@ -2682,7 +2685,7 @@ void SkCanvas::drawDrawable(SkDrawable* dr, SkScalar x, SkScalar y) { #endif RETURN_ON_NULL(dr); if (x || y) { - SkMatrix matrix = SkMatrix::MakeTrans(x, y); + SkMatrix matrix = SkMatrix::Translate(x, y); this->onDrawDrawable(dr, &matrix); } else { this->onDrawDrawable(dr, nullptr); @@ -2816,7 +2819,7 @@ void SkCanvas::onDrawEdgeAAImageSet(const ImageSetEntry imageSet[], int count, // methods, rather than actually drawing themselves. ////////////////////////////////////////////////////////////////////////////// -void SkCanvas::drawColor(SkColor c, SkBlendMode mode) { +void SkCanvas::drawColor(const SkColor4f& c, SkBlendMode mode) { SkPaint paint; paint.setColor(c); paint.setBlendMode(mode); diff --git a/chromium/third_party/skia/src/core/SkClipStack.cpp b/chromium/third_party/skia/src/core/SkClipStack.cpp index 349fdc6758f..0556b28313a 100644 --- a/chromium/third_party/skia/src/core/SkClipStack.cpp +++ b/chromium/third_party/skia/src/core/SkClipStack.cpp @@ -9,6 +9,9 @@ #include "include/core/SkPath.h" #include "src/core/SkClipOpPriv.h" #include "src/core/SkClipStack.h" +#include "src/core/SkRectPriv.h" +#include "src/shaders/SkShaderBase.h" + #include <atomic> #include <new> @@ -21,15 +24,22 @@ SkClipStack::Element::Element(const Element& that) { case DeviceSpaceType::kEmpty: fDeviceSpaceRRect.setEmpty(); fDeviceSpacePath.reset(); + fShader.reset(); break; case DeviceSpaceType::kRect: // Rect uses rrect case DeviceSpaceType::kRRect: fDeviceSpacePath.reset(); + fShader.reset(); fDeviceSpaceRRect = that.fDeviceSpaceRRect; break; case DeviceSpaceType::kPath: + fShader.reset(); fDeviceSpacePath.set(that.getDeviceSpacePath()); break; + case DeviceSpaceType::kShader: + fDeviceSpacePath.reset(); + fShader = that.fShader; + break; } fSaveCount = that.fSaveCount; @@ -60,6 +70,8 @@ bool SkClipStack::Element::operator== (const Element& element) const { return false; } switch (fDeviceSpaceType) { + case DeviceSpaceType::kShader: + return this->getShader() == element.getShader(); case DeviceSpaceType::kPath: return this->getDeviceSpacePath() == element.getDeviceSpacePath(); case DeviceSpaceType::kRRect: @@ -76,12 +88,18 @@ bool SkClipStack::Element::operator== (const Element& element) const { const SkRect& SkClipStack::Element::getBounds() const { static const SkRect kEmpty = {0, 0, 0, 0}; + static const SkRect kInfinite = SkRectPriv::MakeLargeS32(); switch (fDeviceSpaceType) { case DeviceSpaceType::kRect: // fallthrough case DeviceSpaceType::kRRect: return fDeviceSpaceRRect.getBounds(); case DeviceSpaceType::kPath: return fDeviceSpacePath.get()->getBounds(); + case DeviceSpaceType::kShader: + // Shaders have infinite bounds since any pixel could have clipped or full coverage + // (which is different from wide-open, where every pixel has 1.0 coverage, or empty + // where every pixel has 0.0 coverage). + return kInfinite; case DeviceSpaceType::kEmpty: return kEmpty; default: @@ -99,6 +117,7 @@ bool SkClipStack::Element::contains(const SkRect& rect) const { case DeviceSpaceType::kPath: return fDeviceSpacePath.get()->conservativelyContainsRect(rect); case DeviceSpaceType::kEmpty: + case DeviceSpaceType::kShader: return false; default: SkDEBUGFAIL("Unexpected type."); @@ -116,6 +135,7 @@ bool SkClipStack::Element::contains(const SkRRect& rrect) const { case DeviceSpaceType::kPath: return fDeviceSpacePath.get()->conservativelyContainsRect(rrect.getBounds()); case DeviceSpaceType::kEmpty: + case DeviceSpaceType::kShader: return false; default: SkDEBUGFAIL("Unexpected type."); @@ -140,6 +160,9 @@ void SkClipStack::Element::invertShapeFillType() { case DeviceSpaceType::kPath: fDeviceSpacePath.get()->toggleInverseFillType(); break; + case DeviceSpaceType::kShader: + fShader = as_SB(fShader)->makeInvertAlpha(); + break; case DeviceSpaceType::kEmpty: // Should this set to an empty, inverse filled path? break; @@ -219,6 +242,13 @@ void SkClipStack::Element::initAsPath(int saveCount, const SkPath& path, const S this->initCommon(saveCount, op, doAA); } +void SkClipStack::Element::initShader(int saveCount, sk_sp<SkShader> shader) { + SkASSERT(shader); + fDeviceSpaceType = DeviceSpaceType::kShader; + fShader = std::move(shader); + this->initCommon(saveCount, SkClipOp::kIntersect, false); +} + void SkClipStack::Element::asDeviceSpacePath(SkPath* path) const { switch (fDeviceSpaceType) { case DeviceSpaceType::kEmpty: @@ -235,6 +265,10 @@ void SkClipStack::Element::asDeviceSpacePath(SkPath* path) const { case DeviceSpaceType::kPath: *path = *fDeviceSpacePath.get(); break; + case DeviceSpaceType::kShader: + path->reset(); + path->addRect(SkRectPriv::MakeLargeS32()); + break; } path->setIsVolatile(true); } @@ -246,6 +280,7 @@ void SkClipStack::Element::setEmpty() { fIsIntersectionOfRects = false; fDeviceSpaceRRect.setEmpty(); fDeviceSpacePath.reset(); + fShader.reset(); fGenID = kEmptyGenID; SkDEBUGCODE(this->checkEmpty();) } @@ -257,6 +292,7 @@ void SkClipStack::Element::checkEmpty() const { SkASSERT(kEmptyGenID == fGenID); SkASSERT(fDeviceSpaceRRect.isEmpty()); SkASSERT(!fDeviceSpacePath.isValid()); + SkASSERT(!fShader); } bool SkClipStack::Element::canBeIntersectedInPlace(int saveCount, SkClipOp op) const { @@ -356,7 +392,7 @@ void SkClipStack::Element::combineBoundsXOR(int combination, const SkRect& prevF // The only pixels that can survive are within the // union of the two bounding boxes since the extensions // to infinity of both clips cancel out - // fall through! + [[fallthrough]]; case kPrev_Cur_FillCombo: // The most conservative bound for xor is the // union of the two bounds. If the two clips exactly overlapped @@ -501,6 +537,14 @@ void SkClipStack::Element::updateBoundAndGenID(const Element* prior) { fFiniteBoundType = kNormal_BoundsType; } break; + case DeviceSpaceType::kShader: + // A shader is infinite. We don't act as wide-open here (which is an empty bounds with + // the inside out type). This is because when the bounds is empty and inside-out, we + // know there's full coverage everywhere. With a shader, there's *unknown* coverage + // everywhere. + fFiniteBound = SkRectPriv::MakeLargeS32(); + fFiniteBoundType = kNormal_BoundsType; + break; case DeviceSpaceType::kEmpty: SkDEBUGFAIL("We shouldn't get here with an empty element."); break; @@ -758,6 +802,15 @@ void SkClipStack::pushElement(const Element& element) { case Element::DeviceSpaceType::kEmpty: SkDEBUGCODE(prior->checkEmpty();) return; + case Element::DeviceSpaceType::kShader: + if (Element::DeviceSpaceType::kShader == element.getDeviceSpaceType()) { + prior->fShader = SkShaders::Blend(SkBlendMode::kSrcIn, + element.fShader, prior->fShader); + Element* priorPrior = (Element*) iter.prev(); + prior->updateBoundAndGenID(priorPrior); + return; + } + break; case Element::DeviceSpaceType::kRect: if (Element::DeviceSpaceType::kRect == element.getDeviceSpaceType()) { if (prior->rectRectIntersectAllowed(element.getDeviceSpaceRect(), @@ -777,7 +830,7 @@ void SkClipStack::pushElement(const Element& element) { } break; } - // fallthrough + [[fallthrough]]; default: if (!SkRect::Intersects(prior->getBounds(), element.getBounds())) { prior->setEmpty(); @@ -827,6 +880,14 @@ void SkClipStack::clipPath(const SkPath& path, const SkMatrix& matrix, SkClipOp } } +void SkClipStack::clipShader(sk_sp<SkShader> shader) { + Element element(fSaveCount, std::move(shader)); + this->pushElement(element); + // clipShader should not be used with expanding clip ops, so we shouldn't need to worry about + // the clip restriction rect either. + SkASSERT(fClipRestrictionRect.isEmpty()); +} + void SkClipStack::clipEmpty() { Element* element = (Element*) fDeque.back(); @@ -1002,7 +1063,8 @@ uint32_t SkClipStack::getTopmostGenID() const { } const Element* back = static_cast<const Element*>(fDeque.back()); - if (kInsideOut_BoundsType == back->fFiniteBoundType && back->fFiniteBound.isEmpty()) { + if (kInsideOut_BoundsType == back->fFiniteBoundType && back->fFiniteBound.isEmpty() && + Element::DeviceSpaceType::kShader != back->fDeviceSpaceType) { return kWideOpenGenID; } @@ -1015,12 +1077,14 @@ void SkClipStack::Element::dump() const { "empty", "rect", "rrect", - "path" + "path", + "shader" }; static_assert(0 == static_cast<int>(DeviceSpaceType::kEmpty), "enum mismatch"); static_assert(1 == static_cast<int>(DeviceSpaceType::kRect), "enum mismatch"); static_assert(2 == static_cast<int>(DeviceSpaceType::kRRect), "enum mismatch"); static_assert(3 == static_cast<int>(DeviceSpaceType::kPath), "enum mismatch"); + static_assert(4 == static_cast<int>(DeviceSpaceType::kShader), "enum mismatch"); static_assert(SK_ARRAY_COUNT(kTypeStrings) == kTypeCnt, "enum mismatch"); static const char* kOpStrings[] = { @@ -1056,6 +1120,9 @@ void SkClipStack::Element::dump() const { case DeviceSpaceType::kPath: this->getDeviceSpacePath().dump(nullptr, true, false); break; + case DeviceSpaceType::kShader: + // SkShaders don't provide much introspection that's worth while. + break; } } diff --git a/chromium/third_party/skia/src/core/SkClipStack.h b/chromium/third_party/skia/src/core/SkClipStack.h index 6a12c2fdb93..fdbc59b72c9 100644 --- a/chromium/third_party/skia/src/core/SkClipStack.h +++ b/chromium/third_party/skia/src/core/SkClipStack.h @@ -13,6 +13,7 @@ #include "include/core/SkRRect.h" #include "include/core/SkRect.h" #include "include/core/SkRegion.h" +#include "include/core/SkShader.h" #include "include/private/SkDeque.h" #include "src/core/SkClipOpPriv.h" #include "src/core/SkMessageBus.h" @@ -59,8 +60,10 @@ public: kRRect, //!< This element combines a device space path with the current clip. kPath, + //!< This element does not have geometry, but applies a shader to the clip + kShader, - kLastType = kPath + kLastType = kShader }; static const int kTypeCnt = (int)DeviceSpaceType::kLastType + 1; @@ -83,6 +86,10 @@ public: this->initPath(0, path, m, op, doAA); } + Element(sk_sp<SkShader> shader) { + this->initShader(0, std::move(shader)); + } + ~Element(); bool operator== (const Element& element) const; @@ -113,6 +120,14 @@ public: return fDeviceSpaceRRect.getBounds(); } + //!<Call if getDeviceSpaceType() is kShader to get a reference to the clip shader. + sk_sp<SkShader> refShader() const { + return fShader; + } + const SkShader* getShader() const { + return fShader.get(); + } + //!< Call if getDeviceSpaceType() is not kEmpty to get the set operation used to combine //!< this element. SkClipOp getOp() const { return fOp; } @@ -195,6 +210,7 @@ public: SkTLazy<SkPath> fDeviceSpacePath; SkRRect fDeviceSpaceRRect; + sk_sp<SkShader> fShader; int fSaveCount; // save count of stack when this element was added. SkClipOp fOp; DeviceSpaceType fDeviceSpaceType; @@ -239,11 +255,16 @@ public: this->initPath(saveCount, path, m, op, doAA); } + Element(int saveCount, sk_sp<SkShader> shader) { + this->initShader(saveCount, std::move(shader)); + } + void initCommon(int saveCount, SkClipOp op, bool doAA); void initRect(int saveCount, const SkRect&, const SkMatrix&, SkClipOp, bool doAA); void initRRect(int saveCount, const SkRRect&, const SkMatrix&, SkClipOp, bool doAA); void initPath(int saveCount, const SkPath&, const SkMatrix&, SkClipOp, bool doAA); void initAsPath(int saveCount, const SkPath&, const SkMatrix&, SkClipOp, bool doAA); + void initShader(int saveCount, sk_sp<SkShader>); void setEmpty(); @@ -345,6 +366,7 @@ public: void clipRect(const SkRect&, const SkMatrix& matrix, SkClipOp, bool doAA); void clipRRect(const SkRRect&, const SkMatrix& matrix, SkClipOp, bool doAA); void clipPath(const SkPath&, const SkMatrix& matrix, SkClipOp, bool doAA); + void clipShader(sk_sp<SkShader>); // An optimized version of clipDevRect(emptyRect, kIntersect, ...) void clipEmpty(); void setDeviceClipRestriction(const SkIRect& rect) { @@ -513,4 +535,3 @@ private: }; #endif - diff --git a/chromium/third_party/skia/src/core/SkClipStackDevice.cpp b/chromium/third_party/skia/src/core/SkClipStackDevice.cpp index ab2fcd85ac2..2021852f363 100644 --- a/chromium/third_party/skia/src/core/SkClipStackDevice.cpp +++ b/chromium/third_party/skia/src/core/SkClipStackDevice.cpp @@ -39,12 +39,16 @@ void SkClipStackDevice::onClipPath(const SkPath& path, SkClipOp op, bool aa) { fClipStack.clipPath(path, this->localToDevice(), op, aa); } +void SkClipStackDevice::onClipShader(sk_sp<SkShader> shader) { + fClipStack.clipShader(std::move(shader)); +} + void SkClipStackDevice::onClipRegion(const SkRegion& rgn, SkClipOp op) { SkIPoint origin = this->getOrigin(); SkRegion tmp; SkPath path; rgn.getBoundaryPath(&path); - path.transform(SkMatrix::MakeTrans(-origin)); + path.transform(SkMatrix::Translate(-origin)); fClipStack.clipPath(path, SkMatrix::I(), op, false); } diff --git a/chromium/third_party/skia/src/core/SkClipStackDevice.h b/chromium/third_party/skia/src/core/SkClipStackDevice.h index e7fb96a4055..7cbf2133949 100644 --- a/chromium/third_party/skia/src/core/SkClipStackDevice.h +++ b/chromium/third_party/skia/src/core/SkClipStackDevice.h @@ -27,6 +27,7 @@ protected: void onClipRect(const SkRect& rect, SkClipOp, bool aa) override; void onClipRRect(const SkRRect& rrect, SkClipOp, bool aa) override; void onClipPath(const SkPath& path, SkClipOp, bool aa) override; + void onClipShader(sk_sp<SkShader>) override; void onClipRegion(const SkRegion& deviceRgn, SkClipOp) override; void onSetDeviceClipRestriction(SkIRect* mutableClipRestriction) override; bool onClipIsAA() const override; diff --git a/chromium/third_party/skia/src/core/SkColorFilter.cpp b/chromium/third_party/skia/src/core/SkColorFilter.cpp index e3af3f46feb..829a56957a2 100644 --- a/chromium/third_party/skia/src/core/SkColorFilter.cpp +++ b/chromium/third_party/skia/src/core/SkColorFilter.cpp @@ -5,13 +5,13 @@ * found in the LICENSE file. */ -#include "include/core/SkColorFilter.h" #include "include/core/SkRefCnt.h" #include "include/core/SkString.h" #include "include/core/SkUnPreMultiply.h" #include "include/private/SkNx.h" #include "include/private/SkTDArray.h" #include "src/core/SkArenaAlloc.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkColorSpacePriv.h" #include "src/core/SkColorSpaceXformSteps.h" #include "src/core/SkMatrixProvider.h" @@ -26,28 +26,48 @@ #include "src/gpu/effects/generated/GrMixerEffect.h" #endif -bool SkColorFilter::onAsAColorMode(SkColor*, SkBlendMode*) const { +bool SkColorFilter::asColorMode(SkColor* color, SkBlendMode* mode) const { + return as_CFB(this)->onAsAColorMode(color, mode); +} + +bool SkColorFilter::asAColorMode(SkColor* color, SkBlendMode* mode) const { + return as_CFB(this)->onAsAColorMode(color, mode); +} + +bool SkColorFilter::asAColorMatrix(float matrix[20]) const { + return as_CFB(this)->onAsAColorMatrix(matrix); +} + +uint32_t SkColorFilter::getFlags() const { return as_CFB(this)->onGetFlags(); } + +bool SkColorFilter::isAlphaUnchanged() const { + return SkToBool(this->getFlags() & kAlphaUnchanged_Flag); +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + +bool SkColorFilterBase::onAsAColorMode(SkColor*, SkBlendMode*) const { return false; } -bool SkColorFilter::onAsAColorMatrix(float matrix[20]) const { +bool SkColorFilterBase::onAsAColorMatrix(float matrix[20]) const { return false; } #if SK_SUPPORT_GPU -std::unique_ptr<GrFragmentProcessor> SkColorFilter::asFragmentProcessor(GrRecordingContext*, +std::unique_ptr<GrFragmentProcessor> SkColorFilterBase::asFragmentProcessor(GrRecordingContext*, const GrColorInfo&) const { return nullptr; } #endif -bool SkColorFilter::appendStages(const SkStageRec& rec, bool shaderIsOpaque) const { +bool SkColorFilterBase::appendStages(const SkStageRec& rec, bool shaderIsOpaque) const { return this->onAppendStages(rec, shaderIsOpaque); } -skvm::Color SkColorFilter::program(skvm::Builder* p, skvm::Color c, - SkColorSpace* dstCS, - skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { +skvm::Color SkColorFilterBase::program(skvm::Builder* p, skvm::Color c, + SkColorSpace* dstCS, + skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { skvm::F32 original = c.a; if ((c = this->onProgram(p,c, dstCS, uniforms,alloc))) { if (this->getFlags() & kAlphaUnchanged_Flag) { @@ -80,7 +100,7 @@ SkColor4f SkColorFilter::filterColor4f(const SkColor4f& origSrcColor, SkColorSpa SkStageRec rec = { &pipeline, &alloc, kRGBA_F32_SkColorType, dstCS, dummyPaint, nullptr, matrixProvider }; - this->onAppendStages(rec, color.fA == 1); + as_CFB(this)->onAppendStages(rec, color.fA == 1); SkPMColor4f dst; SkRasterPipeline_MemoryCtx dstPtr = { &dst, 0 }; @@ -91,16 +111,16 @@ SkColor4f SkColorFilter::filterColor4f(const SkColor4f& origSrcColor, SkColorSpa /////////////////////////////////////////////////////////////////////////////////////////////////// -class SkComposeColorFilter : public SkColorFilter { +class SkComposeColorFilter : public SkColorFilterBase { public: - uint32_t getFlags() const override { + uint32_t onGetFlags() const override { // Can only claim alphaunchanged support if both our proxys do. - return fOuter->getFlags() & fInner->getFlags(); + return fOuter->onGetFlags() & fInner->onGetFlags(); } bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override { bool innerIsOpaque = shaderIsOpaque; - if (!(fInner->getFlags() & kAlphaUnchanged_Flag)) { + if (!fInner->isAlphaUnchanged()) { innerIsOpaque = false; } return fInner->appendStages(rec, shaderIsOpaque) && @@ -127,6 +147,8 @@ public: } #endif + SK_FLATTENABLE_HOOKS(SkComposeColorFilter) + protected: void flatten(SkWriteBuffer& buffer) const override { buffer.writeFlattenable(fOuter.get()); @@ -134,14 +156,13 @@ protected: } private: - SK_FLATTENABLE_HOOKS(SkComposeColorFilter) - SkComposeColorFilter(sk_sp<SkColorFilter> outer, sk_sp<SkColorFilter> inner) - : fOuter(std::move(outer)) - , fInner(std::move(inner)) {} + : fOuter(as_CFB_sp(std::move(outer))) + , fInner(as_CFB_sp(std::move(inner))) + {} - sk_sp<SkColorFilter> fOuter; - sk_sp<SkColorFilter> fInner; + sk_sp<SkColorFilterBase> fOuter; + sk_sp<SkColorFilterBase> fInner; friend class SkColorFilter; @@ -164,7 +185,7 @@ sk_sp<SkColorFilter> SkColorFilter::makeComposed(sk_sp<SkColorFilter> inner) con /////////////////////////////////////////////////////////////////////////////////////////////////// -class SkSRGBGammaColorFilter : public SkColorFilter { +class SkSRGBGammaColorFilter : public SkColorFilterBase { public: enum class Direction { kLinearToSRGB, @@ -203,9 +224,7 @@ public: rec.fPipeline->append(SkRasterPipeline::unpremul); } - // TODO: is it valuable to thread this through appendStages()? - bool shaderIsNormalized = false; - fSteps.apply(rec.fPipeline, shaderIsNormalized); + fSteps.apply(rec.fPipeline); if (!shaderIsOpaque) { rec.fPipeline->append(SkRasterPipeline::premul); @@ -218,19 +237,19 @@ public: return premul(fSteps.program(p, uniforms, unpremul(c))); } + SK_FLATTENABLE_HOOKS(SkSRGBGammaColorFilter) + protected: void flatten(SkWriteBuffer& buffer) const override { buffer.write32(static_cast<uint32_t>(fDir)); } private: - SK_FLATTENABLE_HOOKS(SkSRGBGammaColorFilter) - const Direction fDir; SkColorSpaceXformSteps fSteps; friend class SkColorFilter; - typedef SkColorFilter INHERITED; + typedef SkColorFilterBase INHERITED; }; sk_sp<SkFlattenable> SkSRGBGammaColorFilter::CreateProc(SkReadBuffer& buffer) { @@ -257,18 +276,20 @@ sk_sp<SkColorFilter> SkColorFilters::SRGBToLinearGamma() { /////////////////////////////////////////////////////////////////////////////////////////////////// -class SkMixerColorFilter : public SkColorFilter { +class SkMixerColorFilter : public SkColorFilterBase { public: SkMixerColorFilter(sk_sp<SkColorFilter> cf0, sk_sp<SkColorFilter> cf1, float weight) - : fCF0(std::move(cf0)), fCF1(std::move(cf1)), fWeight(weight) + : fCF0(as_CFB_sp(std::move(cf0))) + , fCF1(as_CFB_sp(std::move(cf1))) + , fWeight(weight) { SkASSERT(fCF0); SkASSERT(fWeight >= 0 && fWeight <= 1); } - uint32_t getFlags() const override { - uint32_t f0 = fCF0->getFlags(); - uint32_t f1 = fCF1 ? fCF1->getFlags() : ~0U; + uint32_t onGetFlags() const override { + uint32_t f0 = fCF0->onGetFlags(); + uint32_t f1 = fCF1 ? fCF1->onGetFlags() : ~0U; return f0 & f1; } @@ -321,6 +342,8 @@ public: } #endif + SK_FLATTENABLE_HOOKS(SkMixerColorFilter) + protected: void flatten(SkWriteBuffer& buffer) const override { buffer.writeFlattenable(fCF0.get()); @@ -329,15 +352,13 @@ protected: } private: - SK_FLATTENABLE_HOOKS(SkMixerColorFilter) - - sk_sp<SkColorFilter> fCF0; - sk_sp<SkColorFilter> fCF1; - const float fWeight; + sk_sp<SkColorFilterBase> fCF0; + sk_sp<SkColorFilterBase> fCF1; + const float fWeight; friend class SkColorFilter; - typedef SkColorFilter INHERITED; + typedef SkColorFilterBase INHERITED; }; sk_sp<SkFlattenable> SkMixerColorFilter::CreateProc(SkReadBuffer& buffer) { @@ -376,7 +397,7 @@ sk_sp<SkColorFilter> SkColorFilters::Lerp(float weight, sk_sp<SkColorFilter> cf0 #include "src/core/SkModeColorFilter.h" -void SkColorFilter::RegisterFlattenables() { +void SkColorFilterBase::RegisterFlattenables() { SK_REGISTER_FLATTENABLE(SkComposeColorFilter); SK_REGISTER_FLATTENABLE(SkModeColorFilter); SK_REGISTER_FLATTENABLE(SkSRGBGammaColorFilter); diff --git a/chromium/third_party/skia/src/core/SkColorFilterBase.h b/chromium/third_party/skia/src/core/SkColorFilterBase.h new file mode 100644 index 00000000000..8d2fd7053b2 --- /dev/null +++ b/chromium/third_party/skia/src/core/SkColorFilterBase.h @@ -0,0 +1,108 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkColorFilterBase_DEFINED +#define SkColorFilterBase_DEFINED + +#include "include/core/SkColorFilter.h" + +class GrColorInfo; +class GrFragmentProcessor; +class GrRecordingContext; +class SkArenaAlloc; +class SkBitmap; +class SkColorSpace; +struct SkStageRec; +using GrFPResult = std::tuple<bool, std::unique_ptr<GrFragmentProcessor>>; + +namespace skvm { + class Builder; + struct F32; + struct Uniforms; + struct Color; +} + +class SkColorFilterBase : public SkColorFilter { +public: + bool appendStages(const SkStageRec& rec, bool shaderIsOpaque) const; + + skvm::Color program(skvm::Builder*, skvm::Color, + SkColorSpace* dstCS, skvm::Uniforms*, SkArenaAlloc*) const; + + /** Returns the flags for this filter. Override in subclasses to return custom flags. + */ + virtual uint32_t onGetFlags() const { return 0; } + +#if SK_SUPPORT_GPU + /** + * A subclass may implement this factory function to work with the GPU backend. It returns + * a GrFragmentProcessor that implements the color filter in GPU shader code. + * + * The fragment processor receives a premultiplied input color and produces a premultiplied + * output color. + * + * A null return indicates that the color filter isn't implemented for the GPU backend. + */ + virtual std::unique_ptr<GrFragmentProcessor> asFragmentProcessor( + GrRecordingContext*, const GrColorInfo& dstColorInfo) const; +#endif + + bool affectsTransparentBlack() const { + return this->filterColor(SK_ColorTRANSPARENT) != SK_ColorTRANSPARENT; + } + + static void RegisterFlattenables(); + + static SkFlattenable::Type GetFlattenableType() { + return kSkColorFilter_Type; + } + + SkFlattenable::Type getFlattenableType() const override { + return kSkColorFilter_Type; + } + + static sk_sp<SkColorFilter> Deserialize(const void* data, size_t size, + const SkDeserialProcs* procs = nullptr) { + return sk_sp<SkColorFilter>(static_cast<SkColorFilter*>( + SkFlattenable::Deserialize( + kSkColorFilter_Type, data, size, procs).release())); + } + +protected: + SkColorFilterBase() {} + + virtual bool onAsAColorMatrix(float[20]) const; + virtual bool onAsAColorMode(SkColor* color, SkBlendMode* bmode) const; + +private: + virtual bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const = 0; + + virtual skvm::Color onProgram(skvm::Builder*, skvm::Color, + SkColorSpace* dstCS, skvm::Uniforms*, SkArenaAlloc*) const = 0; + + friend class SkColorFilter; + + typedef SkFlattenable INHERITED; +}; + +static inline SkColorFilterBase* as_CFB(SkColorFilter* filter) { + return static_cast<SkColorFilterBase*>(filter); +} + +static inline const SkColorFilterBase* as_CFB(const SkColorFilter* filter) { + return static_cast<const SkColorFilterBase*>(filter); +} + +static inline const SkColorFilterBase* as_CFB(const sk_sp<SkColorFilter>& filter) { + return static_cast<SkColorFilterBase*>(filter.get()); +} + +static inline sk_sp<SkColorFilterBase> as_CFB_sp(sk_sp<SkColorFilter> filter) { + return sk_sp<SkColorFilterBase>(static_cast<SkColorFilterBase*>(filter.release())); +} + +#endif diff --git a/chromium/third_party/skia/src/core/SkColorFilter_Matrix.cpp b/chromium/third_party/skia/src/core/SkColorFilter_Matrix.cpp index 89544188c1b..83b2cb297b4 100644 --- a/chromium/third_party/skia/src/core/SkColorFilter_Matrix.cpp +++ b/chromium/third_party/skia/src/core/SkColorFilter_Matrix.cpp @@ -26,7 +26,7 @@ static uint16_t ComputeFlags(const float matrix[20]) { && SkScalarNearlyZero (srcA[2]) && SkScalarNearlyEqual(srcA[3], 1) && SkScalarNearlyZero (srcA[4]) - ? SkColorFilter::kAlphaUnchanged_Flag : 0; + ? SkColorFilterBase::kAlphaUnchanged_Flag : 0; } SkColorFilter_Matrix::SkColorFilter_Matrix(const float array[20], Domain domain) @@ -35,8 +35,8 @@ SkColorFilter_Matrix::SkColorFilter_Matrix(const float array[20], Domain domain) memcpy(fMatrix, array, 20 * sizeof(float)); } -uint32_t SkColorFilter_Matrix::getFlags() const { - return this->INHERITED::getFlags() | fFlags; +uint32_t SkColorFilter_Matrix::onGetFlags() const { + return this->INHERITED::onGetFlags() | fFlags; } void SkColorFilter_Matrix::flatten(SkWriteBuffer& buffer) const { @@ -131,20 +131,19 @@ std::unique_ptr<GrFragmentProcessor> SkColorFilter_Matrix::asFragmentProcessor( GrRecordingContext*, const GrColorInfo&) const { switch (fDomain) { case Domain::kRGBA: - return GrColorMatrixFragmentProcessor::Make(fMatrix, + return GrColorMatrixFragmentProcessor::Make(/* inputFP = */ nullptr, + fMatrix, /* premulInput = */ true, /* clampRGBOutput = */ true, /* premulOutput = */ true); case Domain::kHSLA: { - std::unique_ptr<GrFragmentProcessor> series[] = { - GrRGBToHSLFilterEffect::Make(), - GrColorMatrixFragmentProcessor::Make(fMatrix, - /* premulInput = */ false, - /* clampRGBOutput = */ false, - /* premulOutput = */ false), - GrHSLToRGBFilterEffect::Make(), - }; - return GrFragmentProcessor::RunInSeries(series, SK_ARRAY_COUNT(series)); + auto fp = GrRGBToHSLFilterEffect::Make(/* inputFP = */ nullptr); + fp = GrColorMatrixFragmentProcessor::Make(std::move(fp), fMatrix, + /* premulInput = */ false, + /* clampRGBOutput = */ false, + /* premulOutput = */ false); + fp = GrHSLToRGBFilterEffect::Make(std::move(fp)); + return fp; } } diff --git a/chromium/third_party/skia/src/core/SkColorFilter_Matrix.h b/chromium/third_party/skia/src/core/SkColorFilter_Matrix.h index a2a3e664e71..401919af227 100644 --- a/chromium/third_party/skia/src/core/SkColorFilter_Matrix.h +++ b/chromium/third_party/skia/src/core/SkColorFilter_Matrix.h @@ -8,16 +8,15 @@ #ifndef SkColorFilter_Matrix_DEFINED #define SkColorFilter_Matrix_DEFINED -#include "include/core/SkColorFilter.h" -#include "include/core/SkFlattenable.h" +#include "src/core/SkColorFilterBase.h" -class SkColorFilter_Matrix : public SkColorFilter { +class SkColorFilter_Matrix : public SkColorFilterBase { public: enum class Domain : uint8_t { kRGBA, kHSLA }; explicit SkColorFilter_Matrix(const float array[20], Domain); - uint32_t getFlags() const override; + uint32_t onGetFlags() const override; #if SK_SUPPORT_GPU std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(GrRecordingContext*, @@ -41,7 +40,7 @@ private: uint16_t fFlags; Domain fDomain; - typedef SkColorFilter INHERITED; + typedef SkColorFilterBase INHERITED; }; #endif diff --git a/chromium/third_party/skia/src/core/SkColorSpaceXformSteps.cpp b/chromium/third_party/skia/src/core/SkColorSpaceXformSteps.cpp index 133d661f4d7..1d90dc2cd28 100644 --- a/chromium/third_party/skia/src/core/SkColorSpaceXformSteps.cpp +++ b/chromium/third_party/skia/src/core/SkColorSpaceXformSteps.cpp @@ -65,9 +65,6 @@ SkColorSpaceXformSteps::SkColorSpaceXformSteps(const SkColorSpace* src, SkAlphaT src-> transferFn(&this->srcTF ); dst->invTransferFn(&this->dstTFInv); - this->srcTF_is_sRGB = src->gammaCloseToSRGB(); - this->dstTF_is_sRGB = dst->gammaCloseToSRGB(); - // If we linearize then immediately reencode with the same transfer function, skip both. if ( this->flags.linearize && !this->flags.gamut_transform && @@ -131,29 +128,12 @@ void SkColorSpaceXformSteps::apply(float* rgba) const { } } -void SkColorSpaceXformSteps::apply(SkRasterPipeline* p, bool src_is_normalized) const { -#if defined(SK_LEGACY_SRGB_STAGE_CHOICE) - src_is_normalized = true; -#endif - if (flags.unpremul) { p->append(SkRasterPipeline::unpremul); } - if (flags.linearize) { - if (src_is_normalized && srcTF_is_sRGB) { - p->append(SkRasterPipeline::from_srgb); - } else { - p->append_transfer_function(srcTF); - } - } - if (flags.gamut_transform) { - p->append(SkRasterPipeline::matrix_3x3, &src_to_dst_matrix); - } - if (flags.encode) { - if (src_is_normalized && dstTF_is_sRGB) { - p->append(SkRasterPipeline::to_srgb); - } else { - p->append_transfer_function(dstTFInv); - } - } - if (flags.premul) { p->append(SkRasterPipeline::premul); } +void SkColorSpaceXformSteps::apply(SkRasterPipeline* p) const { + if (flags.unpremul) { p->append(SkRasterPipeline::unpremul); } + if (flags.linearize) { p->append_transfer_function(srcTF); } + if (flags.gamut_transform) { p->append(SkRasterPipeline::matrix_3x3, &src_to_dst_matrix); } + if (flags.encode) { p->append_transfer_function(dstTFInv); } + if (flags.premul) { p->append(SkRasterPipeline::premul); } } skvm::Color sk_program_transfer_fn(skvm::Builder* p, skvm::Uniforms* uniforms, diff --git a/chromium/third_party/skia/src/core/SkColorSpaceXformSteps.h b/chromium/third_party/skia/src/core/SkColorSpaceXformSteps.h index 7d15259e30f..03c9aab638d 100644 --- a/chromium/third_party/skia/src/core/SkColorSpaceXformSteps.h +++ b/chromium/third_party/skia/src/core/SkColorSpaceXformSteps.h @@ -42,17 +42,11 @@ struct SkColorSpaceXformSteps { dst.colorSpace(), dst.alphaType()) {} void apply(float rgba[4]) const; - void apply(SkRasterPipeline*, bool src_is_normalized) const; + void apply(SkRasterPipeline*) const; skvm::Color program(skvm::Builder*, skvm::Uniforms*, skvm::Color) const; - void apply(SkRasterPipeline* p, SkColorType srcCT) const { - return this->apply(p, SkColorTypeIsNormalized(srcCT)); - } - Flags flags; - bool srcTF_is_sRGB, - dstTF_is_sRGB; skcms_TransferFunction srcTF, // Apply for linearize. dstTFInv; // Apply for encode. float src_to_dst_matrix[9]; // Apply this 3x3 column-major matrix for gamut_transform. diff --git a/chromium/third_party/skia/src/core/SkConvertPixels.cpp b/chromium/third_party/skia/src/core/SkConvertPixels.cpp index 2eb840c3ace..c3dd1d2236f 100644 --- a/chromium/third_party/skia/src/core/SkConvertPixels.cpp +++ b/chromium/third_party/skia/src/core/SkConvertPixels.cpp @@ -211,7 +211,7 @@ static void convert_with_pipeline(const SkImageInfo& dstInfo, void* dstRow, size SkRasterPipeline_<256> pipeline; pipeline.append_load(srcInfo.colorType(), &src); - steps.apply(&pipeline, srcInfo.colorType()); + steps.apply(&pipeline); pipeline.append_gamut_clamp_if_normalized(dstInfo); diff --git a/chromium/third_party/skia/src/core/SkCoreBlitters.h b/chromium/third_party/skia/src/core/SkCoreBlitters.h index 700ca64ab7e..18d468be639 100644 --- a/chromium/third_party/skia/src/core/SkCoreBlitters.h +++ b/chromium/third_party/skia/src/core/SkCoreBlitters.h @@ -164,12 +164,10 @@ private: /////////////////////////////////////////////////////////////////////////////// -// Neither of these ever returns nullptr, but this first factory may return a SkNullBlitter. SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap&, const SkPaint&, const SkMatrixProvider& matrixProvider, SkArenaAlloc*, sk_sp<SkShader> clipShader); // Use this if you've pre-baked a shader pipeline, including modulating with paint alpha. -// This factory never returns an SkNullBlitter. SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap&, const SkPaint&, const SkRasterPipeline& shaderPipeline, bool shader_is_opaque, @@ -177,7 +175,7 @@ SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap&, const SkPaint&, SkBlitter* SkCreateSkVMBlitter(const SkPixmap&, const SkPaint&, - const SkMatrix& ctm, + const SkMatrixProvider&, SkArenaAlloc*, sk_sp<SkShader> clipShader); diff --git a/chromium/third_party/skia/src/core/SkDeferredDisplayList.cpp b/chromium/third_party/skia/src/core/SkDeferredDisplayList.cpp index 5f892241acd..961bc00c682 100644 --- a/chromium/third_party/skia/src/core/SkDeferredDisplayList.cpp +++ b/chromium/third_party/skia/src/core/SkDeferredDisplayList.cpp @@ -20,10 +20,12 @@ class SkSurfaceCharacterization; #endif SkDeferredDisplayList::SkDeferredDisplayList(const SkSurfaceCharacterization& characterization, + sk_sp<GrRenderTargetProxy> targetProxy, sk_sp<LazyProxyData> lazyProxyData) : fCharacterization(characterization) #if SK_SUPPORT_GPU - , fLazyProxyData(std::move(lazyProxyData)) + , fTargetProxy(std::move(targetProxy)) + , fLazyProxyData(std::move(lazyProxyData)) #endif { } diff --git a/chromium/third_party/skia/src/core/SkDeferredDisplayListPriv.h b/chromium/third_party/skia/src/core/SkDeferredDisplayListPriv.h index 271a69bea69..5c8ceb11cb5 100644 --- a/chromium/third_party/skia/src/core/SkDeferredDisplayListPriv.h +++ b/chromium/third_party/skia/src/core/SkDeferredDisplayListPriv.h @@ -22,6 +22,10 @@ public: return fDDL->fRenderTasks.count(); } + GrRenderTargetProxy* targetProxy() const { + return fDDL->fTargetProxy.get(); + } + const SkDeferredDisplayList::LazyProxyData* lazyProxyData() const { return fDDL->fLazyProxyData.get(); } diff --git a/chromium/third_party/skia/src/core/SkDeferredDisplayListRecorder.cpp b/chromium/third_party/skia/src/core/SkDeferredDisplayListRecorder.cpp index 1b284527803..cbe1f84edf6 100644 --- a/chromium/third_party/skia/src/core/SkDeferredDisplayListRecorder.cpp +++ b/chromium/third_party/skia/src/core/SkDeferredDisplayListRecorder.cpp @@ -97,6 +97,7 @@ SkDeferredDisplayListRecorder::~SkDeferredDisplayListRecorder() { bool SkDeferredDisplayListRecorder::init() { SkASSERT(fContext); + SkASSERT(!fTargetProxy); SkASSERT(!fLazyProxyData); SkASSERT(!fSurface); @@ -141,6 +142,9 @@ bool SkDeferredDisplayListRecorder::init() { GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone; if (usesGLFBO0) { surfaceFlags |= GrInternalSurfaceFlags::kGLRTFBOIDIs0; + } else if (fCharacterization.sampleCount() > 1 && !caps->msaaResolvesAutomatically() && + fCharacterization.isTextureable()) { + surfaceFlags |= GrInternalSurfaceFlags::kRequiresManualMSAAResolve; } // FIXME: Why do we use GrMipMapped::kNo instead of SkSurfaceCharacterization::fIsMipMapped? static constexpr GrProxyProvider::TextureInfo kTextureInfo{GrMipMapped::kNo, @@ -152,7 +156,7 @@ bool SkDeferredDisplayListRecorder::init() { GrSwizzle readSwizzle = caps->getReadSwizzle(fCharacterization.backendFormat(), grColorType); - sk_sp<GrRenderTargetProxy> proxy = proxyProvider->createLazyRenderTargetProxy( + fTargetProxy = proxyProvider->createLazyRenderTargetProxy( [lazyProxyData](GrResourceProvider* resourceProvider, const GrSurfaceProxy::LazySurfaceDesc&) { // The proxy backing the destination surface had better have been instantiated @@ -174,14 +178,14 @@ bool SkDeferredDisplayListRecorder::init() { fCharacterization.vulkanSecondaryCBCompatible(), GrSurfaceProxy::UseAllocator::kYes); - if (!proxy) { + if (!fTargetProxy) { return false; } GrSwizzle writeSwizzle = caps->getWriteSwizzle(fCharacterization.backendFormat(), grColorType); - GrSurfaceProxyView readView(proxy, fCharacterization.origin(), readSwizzle); - GrSurfaceProxyView writeView(std::move(proxy), fCharacterization.origin(), writeSwizzle); + GrSurfaceProxyView readView(fTargetProxy, fCharacterization.origin(), readSwizzle); + GrSurfaceProxyView writeView(fTargetProxy, fCharacterization.origin(), writeSwizzle); auto rtc = std::make_unique<GrRenderTargetContext>(fContext.get(), std::move(readView), std::move(writeView), grColorType, @@ -215,7 +219,9 @@ std::unique_ptr<SkDeferredDisplayList> SkDeferredDisplayListRecorder::detach() { } auto ddl = std::unique_ptr<SkDeferredDisplayList>( - new SkDeferredDisplayList(fCharacterization, std::move(fLazyProxyData))); + new SkDeferredDisplayList(fCharacterization, + std::move(fTargetProxy), + std::move(fLazyProxyData))); fContext->priv().moveRenderTasksToDDL(ddl.get()); diff --git a/chromium/third_party/skia/src/core/SkDevice.cpp b/chromium/third_party/skia/src/core/SkDevice.cpp index ca253822d1e..148ab89599a 100644 --- a/chromium/third_party/skia/src/core/SkDevice.cpp +++ b/chromium/third_party/skia/src/core/SkDevice.cpp @@ -96,8 +96,10 @@ bool SkBaseDevice::getLocalToMarker(uint32_t id, SkM44* localToMarker) const { // The marker stack stores CTM snapshots, which are "marker to global" matrices. // We ask for the (cached) inverse, which is a "global to marker" matrix. SkM44 globalToMarker; - if (fMarkerStack && fMarkerStack->findMarkerInverse(id, &globalToMarker)) { + // ID 0 is special, and refers to the CTM (local-to-global) + if (fMarkerStack && (id == 0 || fMarkerStack->findMarkerInverse(id, &globalToMarker))) { if (localToMarker) { + // globalToMarker will still be the identity if id is zero *localToMarker = globalToMarker * SkM44(fDeviceToGlobal) * fLocalToDevice; } return true; @@ -313,8 +315,7 @@ void SkBaseDevice::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix, Sk /////////////////////////////////////////////////////////////////////////////////////////////////// -void SkBaseDevice::drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&, - SkImage*, const SkMatrix&) {} +void SkBaseDevice::drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&) {} sk_sp<SkSpecialImage> SkBaseDevice::makeSpecial(const SkBitmap&) { return nullptr; } sk_sp<SkSpecialImage> SkBaseDevice::makeSpecial(const SkImage*) { return nullptr; } sk_sp<SkSpecialImage> SkBaseDevice::snapSpecial(const SkIRect&, bool) { return nullptr; } diff --git a/chromium/third_party/skia/src/core/SkDevice.h b/chromium/third_party/skia/src/core/SkDevice.h index 58be51f985e..b46b3a4257a 100644 --- a/chromium/third_party/skia/src/core/SkDevice.h +++ b/chromium/third_party/skia/src/core/SkDevice.h @@ -295,8 +295,7 @@ protected: virtual void drawDrawable(SkDrawable*, const SkMatrix*, SkCanvas*); - virtual void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&, - SkImage* clipImage, const SkMatrix& clipMatrix); + virtual void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&); virtual sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&); virtual sk_sp<SkSpecialImage> makeSpecial(const SkImage*); // Get a view of the entire device's current contents as an image. diff --git a/chromium/third_party/skia/src/core/SkDraw.cpp b/chromium/third_party/skia/src/core/SkDraw.cpp index 99c8bd82840..48858d1c9b2 100644 --- a/chromium/third_party/skia/src/core/SkDraw.cpp +++ b/chromium/third_party/skia/src/core/SkDraw.cpp @@ -511,7 +511,7 @@ void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count, break; } } - // couldn't take fast path so fall through! + [[fallthrough]]; // couldn't take fast path case SkCanvas::kPolygon_PointMode: { count -= 1; SkPath path; diff --git a/chromium/third_party/skia/src/core/SkDraw.h b/chromium/third_party/skia/src/core/SkDraw.h index a9f778ad705..f7ed596dbcf 100644 --- a/chromium/third_party/skia/src/core/SkDraw.h +++ b/chromium/third_party/skia/src/core/SkDraw.h @@ -82,6 +82,7 @@ public: void paintPaths(SkDrawableGlyphBuffer* drawables, SkScalar scale, + SkPoint origin, const SkPaint& paint) const override; void paintMasks(SkDrawableGlyphBuffer* drawables, const SkPaint& paint) const override; diff --git a/chromium/third_party/skia/src/core/SkDraw_atlas.cpp b/chromium/third_party/skia/src/core/SkDraw_atlas.cpp index fbc934690aa..077486f926b 100644 --- a/chromium/third_party/skia/src/core/SkDraw_atlas.cpp +++ b/chromium/third_party/skia/src/core/SkDraw_atlas.cpp @@ -101,24 +101,25 @@ void SkDraw::drawAtlas(const SkImage* atlas, const SkRSXform xform[], const SkRe isOpaque = false; } - auto blitter = SkCreateRasterPipelineBlitter(fDst, p, pipeline, isOpaque, &alloc, - fRC->clipShader()); - SkPath scratchPath; - - for (int i = 0; i < count; ++i) { - if (colors) { - SkColor4f c4 = SkColor4f::FromColor(colors[i]); - steps.apply(c4.vec()); - load_color(uniformCtx, c4.premul().vec()); - } + if (auto blitter = SkCreateRasterPipelineBlitter(fDst, p, pipeline, isOpaque, &alloc, + fRC->clipShader())) { + SkPath scratchPath; - SkMatrix mx; - mx.setRSXform(xform[i]); - mx.preTranslate(-textures[i].fLeft, -textures[i].fTop); - mx.postConcat(fMatrixProvider->localToDevice()); + for (int i = 0; i < count; ++i) { + if (colors) { + SkColor4f c4 = SkColor4f::FromColor(colors[i]); + steps.apply(c4.vec()); + load_color(uniformCtx, c4.premul().vec()); + } - if (updator->update(mx, nullptr)) { - fill_rect(mx, *fRC, textures[i], blitter, &scratchPath); + SkMatrix mx; + mx.setRSXform(xform[i]); + mx.preTranslate(-textures[i].fLeft, -textures[i].fTop); + mx.postConcat(fMatrixProvider->localToDevice()); + + if (updator->update(mx, nullptr)) { + fill_rect(mx, *fRC, textures[i], blitter, &scratchPath); + } } } } diff --git a/chromium/third_party/skia/src/core/SkDraw_text.cpp b/chromium/third_party/skia/src/core/SkDraw_text.cpp index 1d138c43be8..953be1a9b27 100644 --- a/chromium/third_party/skia/src/core/SkDraw_text.cpp +++ b/chromium/third_party/skia/src/core/SkDraw_text.cpp @@ -112,11 +112,13 @@ void SkDraw::paintMasks(SkDrawableGlyphBuffer* drawables, const SkPaint& paint) void SkDraw::paintPaths(SkDrawableGlyphBuffer* drawables, SkScalar scale, + SkPoint origin, const SkPaint& paint) const { for (auto [variant, pos] : drawables->drawable()) { const SkPath* path = variant.path(); SkMatrix m; - m.setScaleTranslate(scale, scale, pos.x(), pos.y()); + SkPoint translate = origin + pos; + m.setScaleTranslate(scale, scale, translate.x(), translate.y()); this->drawPath(*path, paint, &m, false); } } diff --git a/chromium/third_party/skia/src/core/SkDraw_vertices.cpp b/chromium/third_party/skia/src/core/SkDraw_vertices.cpp index 9f605db64a8..fe8d496f48e 100644 --- a/chromium/third_party/skia/src/core/SkDraw_vertices.cpp +++ b/chromium/third_party/skia/src/core/SkDraw_vertices.cpp @@ -268,11 +268,13 @@ void SkDraw::draw_fixed_vertices(const SkVertices* vertices, SkBlendMode bmode, const uint16_t* indices = info.indices(); const SkColor* colors = info.colors(); - // make textures and shader mutually consistent + // No need for texCoords without shader. If shader is present without explicit texCoords, + // use positions instead. SkShader* shader = paint.getShader(); - if (!(shader && textures)) { - shader = nullptr; + if (!shader) { textures = nullptr; + } else if (!textures) { + textures = positions; } // We can simplify things for certain blendmodes. This is for speed, and SkComposeShader @@ -328,14 +330,16 @@ void SkDraw::draw_fixed_vertices(const SkVertices* vertices, SkBlendMode bmode, p.setShader(sk_ref_sp(shader)); if (!textures) { // only tricolor shader - auto blitter = SkCreateRasterPipelineBlitter(fDst, p, *fMatrixProvider, outerAlloc, - this->fRC->clipShader()); - while (vertProc(&state)) { - if (triShader && - !triShader->update(ctmInv, positions, dstColors, state.f0, state.f1, state.f2)) { - continue; + if (auto blitter = SkCreateRasterPipelineBlitter(fDst, p, *fMatrixProvider, outerAlloc, + this->fRC->clipShader())) { + while (vertProc(&state)) { + if (triShader && + !triShader->update(ctmInv, positions, dstColors, + state.f0, state.f1, state.f2)) { + continue; + } + fill_triangle(state, blitter, *fRC, dev2, dev3); } - fill_triangle(state, blitter, *fRC, dev2, dev3); } return; } @@ -351,19 +355,28 @@ void SkDraw::draw_fixed_vertices(const SkVertices* vertices, SkBlendMode bmode, // all opaque (and the blendmode will keep them that way } - auto blitter = SkCreateRasterPipelineBlitter(fDst, p, pipeline, isOpaque, outerAlloc, - fRC->clipShader()); - while (vertProc(&state)) { - if (triShader && !triShader->update(ctmInv, positions, dstColors, - state.f0, state.f1, state.f2)) { - continue; + // Positions as texCoords? The local matrix is always identity, so update once + if (textures == positions) { + SkMatrix localM; + if (!updater->update(ctm, &localM)) { + return; } + } - SkMatrix localM; - if (texture_to_matrix(state, positions, textures, &localM) && - updater->update(ctm, &localM)) - { - fill_triangle(state, blitter, *fRC, dev2, dev3); + if (auto blitter = SkCreateRasterPipelineBlitter(fDst, p, pipeline, isOpaque, outerAlloc, + fRC->clipShader())) { + while (vertProc(&state)) { + if (triShader && !triShader->update(ctmInv, positions, dstColors, + state.f0, state.f1, state.f2)) { + continue; + } + + SkMatrix localM; + if ((textures == positions) || + (texture_to_matrix(state, positions, textures, &localM) && + updater->update(ctm, &localM))) { + fill_triangle(state, blitter, *fRC, dev2, dev3); + } } } } else { @@ -378,7 +391,7 @@ void SkDraw::draw_fixed_vertices(const SkVertices* vertices, SkBlendMode bmode, const SkMatrixProvider* matrixProvider = fMatrixProvider; SkTLazy<SkPreConcatMatrixProvider> preConcatMatrixProvider; - if (textures) { + if (textures && (textures != positions)) { SkMatrix localM; if (!texture_to_matrix(state, positions, textures, &localM)) { continue; @@ -386,9 +399,10 @@ void SkDraw::draw_fixed_vertices(const SkVertices* vertices, SkBlendMode bmode, matrixProvider = preConcatMatrixProvider.init(*matrixProvider, localM); } - auto blitter = SkCreateRasterPipelineBlitter(fDst, p, *matrixProvider, &innerAlloc, - this->fRC->clipShader()); - fill_triangle(state, blitter, *fRC, dev2, dev3); + if (auto blitter = SkCreateRasterPipelineBlitter(fDst, p, *matrixProvider, &innerAlloc, + this->fRC->clipShader())) { + fill_triangle(state, blitter, *fRC, dev2, dev3); + } } } } diff --git a/chromium/third_party/skia/src/core/SkDrawable.cpp b/chromium/third_party/skia/src/core/SkDrawable.cpp index 62b02729726..5e12fa59131 100644 --- a/chromium/third_party/skia/src/core/SkDrawable.cpp +++ b/chromium/third_party/skia/src/core/SkDrawable.cpp @@ -43,7 +43,7 @@ void SkDrawable::draw(SkCanvas* canvas, const SkMatrix* matrix) { } void SkDrawable::draw(SkCanvas* canvas, SkScalar x, SkScalar y) { - SkMatrix matrix = SkMatrix::MakeTrans(x, y); + SkMatrix matrix = SkMatrix::Translate(x, y); this->draw(canvas, &matrix); } diff --git a/chromium/third_party/skia/src/core/SkFont.cpp b/chromium/third_party/skia/src/core/SkFont.cpp index 9a4767520c6..6e066dd4157 100644 --- a/chromium/third_party/skia/src/core/SkFont.cpp +++ b/chromium/third_party/skia/src/core/SkFont.cpp @@ -270,7 +270,7 @@ void SkFont::getWidthsBounds(const SkGlyphID glyphIDs[], SkScalar scale = strikeSpec.strikeToSourceRatio(); if (bounds) { - SkMatrix scaleMat = SkMatrix::MakeScale(scale); + SkMatrix scaleMat = SkMatrix::Scale(scale, scale); SkRect* cursor = bounds; for (auto glyph : glyphs) { scaleMat.mapRectScaleTranslate(cursor++, glyph->rect()); @@ -316,7 +316,7 @@ void SkFont::getPaths(const SkGlyphID glyphIDs[], int count, void (*proc)(const SkPath*, const SkMatrix&, void*), void* ctx) const { SkFont font(*this); SkScalar scale = font.setupForAsPaths(nullptr); - const SkMatrix mx = SkMatrix::MakeScale(scale); + const SkMatrix mx = SkMatrix::Scale(scale, scale); SkStrikeSpec strikeSpec = SkStrikeSpec::MakeWithNoDevice(font); SkBulkGlyphMetricsAndPaths paths{strikeSpec}; diff --git a/chromium/third_party/skia/src/core/SkFontPriv.h b/chromium/third_party/skia/src/core/SkFontPriv.h index 6b7bd862b8d..5d07909440c 100644 --- a/chromium/third_party/skia/src/core/SkFontPriv.h +++ b/chromium/third_party/skia/src/core/SkFontPriv.h @@ -37,7 +37,7 @@ public: * Return a matrix that applies the paint's text values: size, scale, skew */ static SkMatrix MakeTextMatrix(SkScalar size, SkScalar scaleX, SkScalar skewX) { - SkMatrix m = SkMatrix::MakeScale(size * scaleX, size); + SkMatrix m = SkMatrix::Scale(size * scaleX, size); if (skewX) { m.postSkew(skewX, 0); } diff --git a/chromium/third_party/skia/src/core/SkGlyphBuffer.cpp b/chromium/third_party/skia/src/core/SkGlyphBuffer.cpp index 5cc0de8c3de..6a8e0c59a4f 100644 --- a/chromium/third_party/skia/src/core/SkGlyphBuffer.cpp +++ b/chromium/third_party/skia/src/core/SkGlyphBuffer.cpp @@ -25,15 +25,12 @@ void SkDrawableGlyphBuffer::ensureSize(size_t size) { fDrawableSize = 0; } -void SkDrawableGlyphBuffer::startSource( - const SkZip<const SkGlyphID, const SkPoint>& source, SkPoint origin) { +void SkDrawableGlyphBuffer::startSource(const SkZip<const SkGlyphID, const SkPoint>& source) { fInputSize = source.size(); fDrawableSize = 0; - // Map all the positions. auto positions = source.get<1>(); - SkMatrix::MakeTrans(origin.x(), origin.y()).mapPoints( - fPositions, positions.data(), positions.size()); + memcpy(fPositions, positions.data(), positions.size() * sizeof(SkPoint)); // Convert from SkGlyphIDs to SkPackedGlyphIDs. SkGlyphVariant* packedIDCursor = fMultiBuffer; @@ -43,22 +40,35 @@ void SkDrawableGlyphBuffer::startSource( SkDEBUGCODE(fPhase = kInput); } -void SkDrawableGlyphBuffer::startPaths(const SkZip<const SkGlyphID, const SkPoint> &source) { +void SkDrawableGlyphBuffer::startBitmapDevice( + const SkZip<const SkGlyphID, const SkPoint>& source, + SkPoint origin, const SkMatrix& viewMatrix, + const SkGlyphPositionRoundingSpec& roundingSpec) { fInputSize = source.size(); fDrawableSize = 0; + // Map the positions including subpixel position. auto positions = source.get<1>(); - memcpy(fPositions, positions.data(), positions.size() * sizeof(SkPoint)); + SkMatrix matrix = viewMatrix; + matrix.preTranslate(origin.x(), origin.y()); + SkPoint halfSampleFreq = roundingSpec.halfAxisSampleFreq; + matrix.postTranslate(halfSampleFreq.x(), halfSampleFreq.y()); + matrix.mapPoints(fPositions, positions.data(), positions.size()); - // Convert from SkGlyphIDs to SkPackedGlyphIDs. + // Mask for controlling axis alignment. + SkIPoint mask = roundingSpec.ignorePositionFieldMask; + + // Convert glyph ids and positions to packed glyph ids. + SkZip<const SkGlyphID, const SkPoint> withMappedPos = + SkMakeZip(source.get<0>(), fPositions.get()); SkGlyphVariant* packedIDCursor = fMultiBuffer; - for (auto t : source) { - *packedIDCursor++ = SkPackedGlyphID{std::get<0>(t)}; + for (auto [glyphID, pos] : withMappedPos) { + *packedIDCursor++ = SkPackedGlyphID{glyphID, pos, mask}; } SkDEBUGCODE(fPhase = kInput); } -void SkDrawableGlyphBuffer::startDevice( +void SkDrawableGlyphBuffer::startGPUDevice( const SkZip<const SkGlyphID, const SkPoint>& source, SkPoint origin, const SkMatrix& viewMatrix, const SkGlyphPositionRoundingSpec& roundingSpec) { @@ -69,6 +79,9 @@ void SkDrawableGlyphBuffer::startDevice( auto positions = source.get<1>(); SkMatrix matrix = viewMatrix; matrix.preTranslate(origin.x(), origin.y()); + + // Q = [M][T](0,0). + SkPoint Q = matrix.mapXY(0, 0); SkPoint halfSampleFreq = roundingSpec.halfAxisSampleFreq; matrix.postTranslate(halfSampleFreq.x(), halfSampleFreq.y()); matrix.mapPoints(fPositions, positions.data(), positions.size()); @@ -83,9 +96,16 @@ void SkDrawableGlyphBuffer::startDevice( for (auto [glyphID, pos] : withMappedPos) { *packedIDCursor++ = SkPackedGlyphID{glyphID, pos, mask}; } + + for (SkPoint& pos : SkSpan<SkPoint>(fPositions, source.size())) { + SkPoint P = SkPoint::Make(SkScalarFloorToScalar(pos.x()), SkScalarFloorToScalar(pos.y())); + pos = P - Q; + } + SkDEBUGCODE(fPhase = kInput); } + void SkDrawableGlyphBuffer::reset() { SkDEBUGCODE(fPhase = kReset); if (fMaxSize > 200) { diff --git a/chromium/third_party/skia/src/core/SkGlyphBuffer.h b/chromium/third_party/skia/src/core/SkGlyphBuffer.h index fe4da38c910..8458afdbc52 100644 --- a/chromium/third_party/skia/src/core/SkGlyphBuffer.h +++ b/chromium/third_party/skia/src/core/SkGlyphBuffer.h @@ -143,14 +143,34 @@ class SkDrawableGlyphBuffer { public: void ensureSize(size_t size); - // Load the buffer with SkPackedGlyphIDs and positions in source space. - void startSource(const SkZip<const SkGlyphID, const SkPoint>& source, SkPoint origin); - - // Use the original glyphIDs and positions. - void startPaths(const SkZip<const SkGlyphID, const SkPoint>& source); + // Load the buffer with SkPackedGlyphIDs and positions at (0, 0) ready to finish positioning + // during drawing. + void startSource(const SkZip<const SkGlyphID, const SkPoint>& source); // Load the buffer with SkPackedGlyphIDs and positions using the device transform. - void startDevice( + void startBitmapDevice( + const SkZip<const SkGlyphID, const SkPoint>& source, + SkPoint origin, const SkMatrix& viewMatrix, + const SkGlyphPositionRoundingSpec& roundingSpec); + + // Load the buffer with SkPackedGlyphIDs, calculating positions so they can be constant. + // + // A final device position is computed in the following manner: + // [x,y] = Floor[M][T][x',y']^t + // M is complicated but includes the rounding offsets for subpixel positioning. + // T is the translation matrix derived from the text blob origin. + // The final position is {Floor(x), Floor(y)}. If we want to move this position around in + // device space given a start origin T in source space and a end position T' in source space + // and new device matrix M', we need to calculate a suitable device space translation V. We + // know that V must be integer. + // V = [M'][T'](0,0)^t - [M][T](0,0)^t. + // V = Q' - Q + // So all the positions Ps are translated by V to translate from T to T' in source space. We can + // generate Ps such that we just need to add any Q' to the constant Ps to get a final positions. + // So, a single point P = {Floor(x)-Q_x, Floor(y)-Q_y}; this does not have to be integer. + // This allows positioning to be P + Q', which given ideal numbers would be an integer. Since + // the addition is done with floating point, it must be rounded. + void startGPUDevice( const SkZip<const SkGlyphID, const SkPoint>& source, SkPoint origin, const SkMatrix& viewMatrix, const SkGlyphPositionRoundingSpec& roundingSpec); diff --git a/chromium/third_party/skia/src/core/SkGlyphRunPainter.cpp b/chromium/third_party/skia/src/core/SkGlyphRunPainter.cpp index 8ef928db375..a8227f93437 100644 --- a/chromium/third_party/skia/src/core/SkGlyphRunPainter.cpp +++ b/chromium/third_party/skia/src/core/SkGlyphRunPainter.cpp @@ -15,8 +15,9 @@ #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/SkGr.h" +#include "src/gpu/ops/GrAtlasTextOp.h" +#include "src/gpu/text/GrSDFTOptions.h" #include "src/gpu/text/GrTextBlobCache.h" -#include "src/gpu/text/GrTextContext.h" #endif #include "include/core/SkColorFilter.h" @@ -47,7 +48,7 @@ SkGlyphRunListPainter::SkGlyphRunListPainter(const SkSurfaceProps& props, , fColorType{colorType}, fScalerContextFlags{flags} , fStrikeCache{strikeCache} {} -// TODO: unify with code in GrTextContext.cpp +// TODO: unify with code in GrSDFTOptions.cpp static SkScalerContextFlags compute_scaler_context_flags(const SkColorSpace* cs) { // If we're doing linear blending, then we can disable the gamma hacks. // Otherwise, leave them on. In either case, we still want the contrast boost: @@ -106,7 +107,7 @@ void SkGlyphRunListPainter::drawForBitmapDevice( auto strike = strikeSpec.findOrCreateStrike(); - fDrawable.startSource(fRejects.source(), drawOrigin); + fDrawable.startSource(fRejects.source()); strike->prepareForPathDrawing(&fDrawable, &fRejects); fRejects.flipRejectsToSource(); @@ -115,7 +116,8 @@ void SkGlyphRunListPainter::drawForBitmapDevice( SkPaint pathPaint = runPaint; pathPaint.setAntiAlias(runFont.hasSomeAntiAliasing()); - bitmapDevice->paintPaths(&fDrawable, strikeSpec.strikeToSourceRatio(), pathPaint); + bitmapDevice->paintPaths( + &fDrawable, strikeSpec.strikeToSourceRatio(), drawOrigin, pathPaint); } if (!fRejects.source().empty()) { SkStrikeSpec strikeSpec = SkStrikeSpec::MakeMask( @@ -123,7 +125,7 @@ void SkGlyphRunListPainter::drawForBitmapDevice( auto strike = strikeSpec.findOrCreateStrike(); - fDrawable.startDevice( + fDrawable.startBitmapDevice( fRejects.source(), drawOrigin, deviceMatrix, strike->roundingSpec()); strike->prepareForDrawingMasksCPU(&fDrawable); bitmapDevice->paintMasks(&fDrawable, runPaint); @@ -139,7 +141,7 @@ void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunLi const SkMatrix& drawMatrix, const SkSurfaceProps& props, bool contextSupportsDistanceFieldText, - const GrTextContext::Options& options, + const GrSDFTOptions& options, SkGlyphRunPainterInterface* process) { SkPoint origin = glyphRunList.origin(); @@ -151,8 +153,8 @@ void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunLi const SkFont& runFont = glyphRun.font(); - bool useSDFT = GrTextContext::CanDrawAsDistanceFields( - runPaint, runFont, drawMatrix, props, contextSupportsDistanceFieldText, options); + bool useSDFT = options.canDrawAsDistanceFields( + runPaint, runFont, drawMatrix, props, contextSupportsDistanceFieldText); bool usePaths = useSDFT ? false : SkStrikeSpec::ShouldDrawAsPath(runPaint, runFont, drawMatrix); @@ -167,7 +169,7 @@ void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunLi if (!strikeSpec.isEmpty()) { SkScopedStrikeForGPU strike = strikeSpec.findOrCreateScopedStrike(fStrikeCache); - fDrawable.startSource(fRejects.source(), origin); + fDrawable.startSource(fRejects.source()); strike->prepareForSDFTDrawing(&fDrawable, &fRejects); fRejects.flipRejectsToSource(); @@ -188,7 +190,7 @@ void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunLi SkScopedStrikeForGPU strike = strikeSpec.findOrCreateScopedStrike(fStrikeCache); - fDrawable.startDevice(fRejects.source(), origin, drawMatrix, strike->roundingSpec()); + fDrawable.startGPUDevice(fRejects.source(), origin, drawMatrix, strike->roundingSpec()); strike->prepareForMaskDrawing(&fDrawable, &fRejects); fRejects.flipRejectsToSource(); @@ -212,7 +214,7 @@ void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunLi if (!strikeSpec.isEmpty()) { SkScopedStrikeForGPU strike = strikeSpec.findOrCreateScopedStrike(fStrikeCache); - fDrawable.startPaths(fRejects.source()); + fDrawable.startSource(fRejects.source()); strike->prepareForPathDrawing(&fDrawable, &fRejects); fRejects.flipRejectsToSource(); maxDimensionInSourceSpace = @@ -235,7 +237,7 @@ void SkGlyphRunListPainter::processGlyphRunList(const SkGlyphRunList& glyphRunLi if (!strikeSpec.isEmpty()) { SkScopedStrikeForGPU strike = strikeSpec.findOrCreateScopedStrike(fStrikeCache); - fDrawable.startSource(fRejects.source(), origin); + fDrawable.startSource(fRejects.source()); strike->prepareForMaskDrawing(&fDrawable, &fRejects); fRejects.flipRejectsToSource(); SkASSERT(fRejects.source().empty()); @@ -257,158 +259,6 @@ auto SkGlyphRunListPainter::ensureBuffers(const SkGlyphRunList& glyphRunList) -> return ScopedBuffers(this, size); } -#if SK_SUPPORT_GPU -// -- GrTextContext -------------------------------------------------------------------------------- -SkPMColor4f generate_filtered_color(const SkPaint& paint, const GrColorInfo& colorInfo) { - SkColor4f filteredColor = paint.getColor4f(); - if (auto* xform = colorInfo.colorSpaceXformFromSRGB()) { - filteredColor = xform->apply(filteredColor); - } - if (paint.getColorFilter() != nullptr) { - filteredColor = paint.getColorFilter()->filterColor4f(filteredColor, colorInfo.colorSpace(), - colorInfo.colorSpace()); - } - return filteredColor.premul(); -} - -void GrTextContext::drawGlyphRunList(GrRecordingContext* context, - GrTextTarget* target, - const GrClip& clip, - const SkMatrixProvider& matrixProvider, - const SkSurfaceProps& props, - const SkGlyphRunList& glyphRunList) const { - auto contextPriv = context->priv(); - // If we have been abandoned, then don't draw - if (contextPriv.abandoned()) { - return; - } - GrTextBlobCache* textBlobCache = contextPriv.getTextBlobCache(); - - // Get the first paint to use as the key paint. - const SkPaint& blobPaint = glyphRunList.paint(); - - const GrColorInfo& colorInfo = target->colorInfo(); - // This is the color the op will use to draw. - SkPMColor4f drawingColor = generate_filtered_color(blobPaint, colorInfo); - // When creating the a new blob, use the GrColor calculated from the drawingColor. - GrColor initialVertexColor = drawingColor.toBytes_RGBA(); - - SkPoint drawOrigin = glyphRunList.origin(); - - SkMaskFilterBase::BlurRec blurRec; - // It might be worth caching these things, but its not clear at this time - // TODO for animated mask filters, this will fill up our cache. We need a safeguard here - const SkMaskFilter* mf = blobPaint.getMaskFilter(); - bool canCache = glyphRunList.canCache() && !(blobPaint.getPathEffect() || - (mf && !as_MFB(mf)->asABlur(&blurRec))); - SkScalerContextFlags scalerContextFlags = ComputeScalerContextFlags(colorInfo); - - sk_sp<GrTextBlob> cachedBlob; - GrTextBlob::Key key; - if (canCache) { - bool hasLCD = glyphRunList.anyRunsLCD(); - - // We canonicalize all non-lcd draws to use kUnknown_SkPixelGeometry - SkPixelGeometry pixelGeometry = hasLCD ? props.pixelGeometry() : kUnknown_SkPixelGeometry; - - // TODO we want to figure out a way to be able to use the canonical color on LCD text, - // see the note on ComputeCanonicalColor above. We pick a dummy value for LCD text to - // ensure we always match the same key - GrColor canonicalColor = hasLCD ? SK_ColorTRANSPARENT : - ComputeCanonicalColor(blobPaint, hasLCD); - - key.fPixelGeometry = pixelGeometry; - key.fUniqueID = glyphRunList.uniqueID(); - key.fStyle = blobPaint.getStyle(); - key.fHasBlur = SkToBool(mf); - key.fCanonicalColor = canonicalColor; - key.fScalerContextFlags = scalerContextFlags; - cachedBlob = textBlobCache->find(key); - } - - bool forceW = fOptions.fDistanceFieldVerticesAlwaysHaveW; - bool supportsSDFT = context->priv().caps()->shaderCaps()->supportsDistanceFieldText(); - SkGlyphRunListPainter* painter = target->glyphPainter(); - const SkMatrix& drawMatrix(matrixProvider.localToDevice()); - if (cachedBlob) { - if (cachedBlob->mustRegenerate(blobPaint, glyphRunList.anyRunsSubpixelPositioned(), - blurRec, drawMatrix, drawOrigin)) { - // We have to remake the blob because changes may invalidate our masks. - // TODO we could probably get away reuse most of the time if the pointer is unique, - // but we'd have to clear the subrun information - textBlobCache->remove(cachedBlob.get()); - cachedBlob = textBlobCache->makeCachedBlob(glyphRunList, key, blurRec, drawMatrix, - initialVertexColor, forceW); - - painter->processGlyphRunList( - glyphRunList, drawMatrix, props, supportsSDFT, fOptions, cachedBlob.get()); - } else { - textBlobCache->makeMRU(cachedBlob.get()); - } - } else { - if (canCache) { - cachedBlob = textBlobCache->makeCachedBlob(glyphRunList, key, blurRec, drawMatrix, - initialVertexColor, forceW); - } else { - cachedBlob = textBlobCache->makeBlob(glyphRunList, drawMatrix, - initialVertexColor, forceW); - } - painter->processGlyphRunList( - glyphRunList, drawMatrix, props, supportsSDFT, fOptions, cachedBlob.get()); - } - - cachedBlob->addOp(target, props, blobPaint, drawingColor, clip, matrixProvider, drawOrigin); -} - -#if GR_TEST_UTILS - -#include "src/gpu/GrRecordingContextPriv.h" -#include "src/gpu/GrRenderTargetContext.h" - -std::unique_ptr<GrDrawOp> GrTextContext::createOp_TestingOnly(GrRecordingContext* context, - GrTextContext* textContext, - GrRenderTargetContext* rtc, - const SkPaint& skPaint, - const SkFont& font, - const SkMatrixProvider& mtxProvider, - const char* text, - int x, - int y) { - auto direct = context->priv().asDirectContext(); - if (!direct) { - return nullptr; - } - - static SkSurfaceProps surfaceProps(SkSurfaceProps::kLegacyFontHost_InitType); - - size_t textLen = (int)strlen(text); - - SkPMColor4f filteredColor = generate_filtered_color(skPaint, rtc->colorInfo()); - GrColor color = filteredColor.toBytes_RGBA(); - const SkMatrix& drawMatrix(mtxProvider.localToDevice()); - - auto drawOrigin = SkPoint::Make(x, y); - SkGlyphRunBuilder builder; - builder.drawTextUTF8(skPaint, font, text, textLen, drawOrigin); - - auto glyphRunList = builder.useGlyphRunList(); - sk_sp<GrTextBlob> blob; - if (!glyphRunList.empty()) { - blob = direct->priv().getTextBlobCache()->makeBlob(glyphRunList, drawMatrix, color, false); - SkGlyphRunListPainter* painter = rtc->textTarget()->glyphPainter(); - painter->processGlyphRunList( - glyphRunList, drawMatrix, surfaceProps, - context->priv().caps()->shaderCaps()->supportsDistanceFieldText(), - textContext->fOptions, blob.get()); - } - - return blob->test_makeOp(mtxProvider, drawOrigin, skPaint, filteredColor, surfaceProps, - rtc->textTarget()); -} - -#endif // GR_TEST_UTILS -#endif // SK_SUPPORT_GPU - SkGlyphRunListPainter::ScopedBuffers::ScopedBuffers(SkGlyphRunListPainter* painter, size_t size) : fPainter{painter} { fPainter->fDrawable.ensureSize(size); diff --git a/chromium/third_party/skia/src/core/SkGlyphRunPainter.h b/chromium/third_party/skia/src/core/SkGlyphRunPainter.h index 6b64566b9e1..3394239533b 100644 --- a/chromium/third_party/skia/src/core/SkGlyphRunPainter.h +++ b/chromium/third_party/skia/src/core/SkGlyphRunPainter.h @@ -16,7 +16,7 @@ #include "src/core/SkTextBlobPriv.h" #if SK_SUPPORT_GPU -#include "src/gpu/text/GrTextContext.h" +#include "src/gpu/text/GrSDFTOptions.h" class GrColorInfo; class GrRenderTargetContext; #endif @@ -70,7 +70,8 @@ public: virtual ~BitmapDevicePainter() = default; virtual void paintPaths( - SkDrawableGlyphBuffer* drawables, SkScalar scale, const SkPaint& paint) const = 0; + SkDrawableGlyphBuffer* drawables, SkScalar scale, SkPoint origin, + const SkPaint& paint) const = 0; virtual void paintMasks(SkDrawableGlyphBuffer* drawables, const SkPaint& paint) const = 0; }; @@ -86,7 +87,7 @@ public: const SkMatrix& drawMatrix, const SkSurfaceProps& props, bool contextSupportsDistanceFieldText, - const GrTextContext::Options& options, + const GrSDFTOptions& options, SkGlyphRunPainterInterface* process); #endif // SK_SUPPORT_GPU diff --git a/chromium/third_party/skia/src/core/SkGpuBlurUtils.cpp b/chromium/third_party/skia/src/core/SkGpuBlurUtils.cpp index e578ad6d7b8..2dadacc68e0 100644 --- a/chromium/third_party/skia/src/core/SkGpuBlurUtils.cpp +++ b/chromium/third_party/skia/src/core/SkGpuBlurUtils.cpp @@ -12,7 +12,6 @@ #if SK_SUPPORT_GPU #include "include/private/GrRecordingContext.h" #include "src/gpu/GrCaps.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/GrRenderTargetContextPriv.h" @@ -25,50 +24,9 @@ using Direction = GrGaussianConvolutionFragmentProcessor::Direction; -static void scale_irect_roundout(SkIRect* rect, float xScale, float yScale) { - rect->fLeft = SkScalarFloorToInt(rect->fLeft * xScale); - rect->fTop = SkScalarFloorToInt(rect->fTop * yScale); - rect->fRight = SkScalarCeilToInt(rect->fRight * xScale); - rect->fBottom = SkScalarCeilToInt(rect->fBottom * yScale); -} - -static void scale_irect(SkIRect* rect, int xScale, int yScale) { - rect->fLeft *= xScale; - rect->fTop *= yScale; - rect->fRight *= xScale; - rect->fBottom *= yScale; -} - -#ifdef SK_DEBUG -static inline int is_even(int x) { return !(x & 1); } -#endif - -static void shrink_irect_by_2(SkIRect* rect, bool xAxis, bool yAxis) { - if (xAxis) { - SkASSERT(is_even(rect->fLeft) && is_even(rect->fRight)); - rect->fLeft /= 2; - rect->fRight /= 2; - } - if (yAxis) { - SkASSERT(is_even(rect->fTop) && is_even(rect->fBottom)); - rect->fTop /= 2; - rect->fBottom /= 2; - } -} - -static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int *radius) { - *scaleFactor = 1; - while (sigma > MAX_BLUR_SIGMA) { - *scaleFactor *= 2; - sigma *= 0.5f; - if (*scaleFactor > maxTextureSize) { - *scaleFactor = maxTextureSize; - sigma = MAX_BLUR_SIGMA; - } - } - *radius = static_cast<int>(ceilf(sigma * 3.0f)); - SkASSERT(*radius <= GrGaussianConvolutionFragmentProcessor::kMaxKernelRadius); - return sigma; +static int sigma_radius(float sigma) { + SkASSERT(sigma >= 0); + return static_cast<int>(ceilf(sigma * 3.0f)); } /** @@ -77,32 +35,24 @@ static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int */ static void convolve_gaussian_1d(GrRenderTargetContext* renderTargetContext, GrSurfaceProxyView srcView, + const SkIRect srcSubset, SkIVector rtcToSrcOffset, const SkIRect& rtcRect, SkAlphaType srcAlphaType, Direction direction, int radius, float sigma, - SkTileMode mode, - int bounds[2]) { + SkTileMode mode) { GrPaint paint; auto wm = SkTileModeToWrapMode(mode); - int realBounds[2]; - if (bounds) { - realBounds[0] = bounds[0]; realBounds[1] = bounds[1]; - } else { - auto proxy = srcView.proxy(); - realBounds[0] = 0; - realBounds[1] = direction == Direction::kX ? proxy->width() : proxy->height(); - } + auto srcRect = rtcRect.makeOffset(rtcToSrcOffset); std::unique_ptr<GrFragmentProcessor> conv(GrGaussianConvolutionFragmentProcessor::Make( - std::move(srcView), srcAlphaType, direction, radius, sigma, wm, realBounds, + std::move(srcView), srcAlphaType, direction, radius, sigma, wm, srcSubset, &srcRect, *renderTargetContext->caps())); paint.addColorFragmentProcessor(std::move(conv)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - auto srcRect = SkRect::Make(rtcRect.makeOffset(rtcToSrcOffset)); - renderTargetContext->fillRectToRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), - SkRect::Make(rtcRect), srcRect); + renderTargetContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(rtcRect), SkRect::Make(srcRect)); } static std::unique_ptr<GrRenderTargetContext> convolve_gaussian_2d(GrRecordingContext* context, @@ -138,7 +88,7 @@ static std::unique_ptr<GrRenderTargetContext> convolve_gaussian_2d(GrRecordingCo // 'dstBounds' is actually in 'srcView' proxy space. It represents the blurred area from src // space that we want to capture in the new RTC at {0, 0}. Hence, we use its size as the rect to // draw and it directly as the local rect. - renderTargetContext->fillRectToRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), + renderTargetContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::Make(dstBounds.size()), SkRect::Make(dstBounds)); return renderTargetContext; @@ -148,7 +98,7 @@ static std::unique_ptr<GrRenderTargetContext> convolve_gaussian(GrRecordingConte GrSurfaceProxyView srcView, GrColorType srcColorType, SkAlphaType srcAlphaType, - SkIRect* contentRect, + SkIRect srcBounds, SkIRect dstBounds, Direction direction, int radius, @@ -156,7 +106,7 @@ static std::unique_ptr<GrRenderTargetContext> convolve_gaussian(GrRecordingConte SkTileMode mode, sk_sp<SkColorSpace> finalCS, SkBackingFit fit) { - // Logically we're creating an infinite blur of 'contentRect' of 'srcView' with 'mode' tiling + // Logically we're creating an infinite blur of 'srcBounds' of 'srcView' with 'mode' tiling // and then capturing the 'dstBounds' portion in a new RTC where the top left of 'dstBounds' is // at {0, 0} in the new RTC. auto dstRenderTargetContext = GrRenderTargetContext::Make( @@ -165,193 +115,138 @@ static std::unique_ptr<GrRenderTargetContext> convolve_gaussian(GrRecordingConte if (!dstRenderTargetContext) { return nullptr; } - // This represents the translation from 'dstRenderTargetContext' coords to 'srcView' coords. auto rtcToSrcOffset = dstBounds.topLeft(); - if (SkTileMode::kClamp == mode && - contentRect->contains(SkIRect::MakeSize(srcView.proxy()->backingStoreDimensions()))) { + auto srcBackingBounds = SkIRect::MakeSize(srcView.proxy()->backingStoreDimensions()); + // We've implemented splitting the dst bounds up into areas that do and do not need to + // use shader based tiling but only for some modes... + bool canSplit = mode == SkTileMode::kDecal || mode == SkTileMode::kClamp; + // ...but it's not worth doing the splitting if we'll get HW tiling instead of shader tiling. + bool canHWTile = + srcBounds.contains(srcBackingBounds) && + !(mode == SkTileMode::kDecal && !context->priv().caps()->clampToBorderSupport()); + if (!canSplit || canHWTile) { auto dstRect = SkIRect::MakeSize(dstBounds.size()); - convolve_gaussian_1d(dstRenderTargetContext.get(), std::move(srcView), rtcToSrcOffset, - dstRect, srcAlphaType, direction, radius, sigma, SkTileMode::kClamp, - nullptr); - *contentRect = dstRect; + convolve_gaussian_1d(dstRenderTargetContext.get(), std::move(srcView), srcBounds, + rtcToSrcOffset, dstRect, srcAlphaType, direction, radius, sigma, mode); return dstRenderTargetContext; } - // 'left' and 'right' are the sub rects of 'contentTect' where 'mode' must be enforced. + // 'left' and 'right' are the sub rects of 'srcBounds' where 'mode' must be enforced. // 'mid' is the area where we can ignore the mode because the kernel does not reach to the - // edge of 'contentRect'. The names are derived from the Direction::kX case. - // TODO: When mode is kMirror or kRepeat it makes more sense to think of 'contentRect' - // as a tile and figure out the collection of mid/left/right rects that cover 'dstBounds'. - // Also if 'mid' is small and 'left' or 'right' is non-empty we should probably issue one - // draw that implements the mode in the shader rather than break it up in this fashion. + // edge of 'srcBounds'. SkIRect mid, left, right; - // 'top' and 'bottom' are areas of 'dstBounds' that are entirely above/below - // 'contentRect'. These are areas that we can simply clear in the dst. If 'contentRect' + // 'top' and 'bottom' are areas of 'dstBounds' that are entirely above/below 'srcBounds'. + // These are areas that we can simply clear in the dst in kDecal mode. If 'srcBounds' // straddles the top edge of 'dstBounds' then 'top' will be inverted and we will skip - // the clear. Similar for 'bottom'. The positional/directional labels above refer to the - // Direction::kX case and one should think of these as 'left' and 'right' for Direction::kY. + // processing for the rect. Similar for 'bottom'. The positional/directional labels above refer + // to the Direction::kX case and one should think of these as 'left' and 'right' for + // Direction::kY. SkIRect top, bottom; - int bounds[2]; if (Direction::kX == direction) { - bounds[0] = contentRect->left(); - bounds[1] = contentRect->right(); - - top = {dstBounds.left(), dstBounds.top() , dstBounds.right(), contentRect->top()}; - bottom = {dstBounds.left(), contentRect->bottom(), dstBounds.right(), dstBounds.bottom()}; - - // Inset for sub-rect of 'contentRect' where the x-dir kernel doesn't reach the edges. - // TODO: Consider clipping mid/left/right to dstBounds to increase likelihood of doing - // fewer draws below. - mid = contentRect->makeInset(radius, 0); - - left = {dstBounds.left(), mid.top(), mid.left() , mid.bottom()}; - right = {mid.right(), mid.top(), dstBounds.right(), mid.bottom()}; - - // The new 'contentRect' when we're done will be the area between the clears in the dst. - *contentRect = {dstBounds.left(), - std::max(contentRect->top(), dstBounds.top()), - dstBounds.right(), - std::min(dstBounds.bottom(), contentRect->bottom())}; + top = {dstBounds.left(), dstBounds.top() , dstBounds.right(), srcBounds.top() }; + bottom = {dstBounds.left(), srcBounds.bottom(), dstBounds.right(), dstBounds.bottom()}; + + // Inset for sub-rect of 'srcBounds' where the x-dir kernel doesn't reach the edges, clipped + // vertically to dstBounds. + int midA = std::max(srcBounds.top() , dstBounds.top() ); + int midB = std::min(srcBounds.bottom(), dstBounds.bottom()); + mid = {srcBounds.left() + radius, midA, srcBounds.right() - radius, midB}; + if (mid.isEmpty()) { + // There is no middle where the bounds can be ignored. Make the left span the whole + // width of dst and we will not draw mid or right. + left = {dstBounds.left(), mid.top(), dstBounds.right(), mid.bottom()}; + } else { + left = {dstBounds.left(), mid.top(), mid.left() , mid.bottom()}; + right = {mid.right(), mid.top(), dstBounds.right(), mid.bottom()}; + } } else { // This is the same as the x direction code if you turn your head 90 degrees CCW. Swap x and // y and swap top/bottom with left/right. - bounds[0] = contentRect->top(); - bounds[1] = contentRect->bottom(); - - top = {dstBounds.left(), dstBounds.top() , contentRect->left(), dstBounds.bottom()}; - bottom = {contentRect->right(), dstBounds.top() , dstBounds.right() , dstBounds.bottom()}; + top = {dstBounds.left(), dstBounds.top(), srcBounds.left() , dstBounds.bottom()}; + bottom = {srcBounds.right(), dstBounds.top(), dstBounds.right(), dstBounds.bottom()}; - mid = contentRect->makeInset(0, radius); + int midA = std::max(srcBounds.left() , dstBounds.left() ); + int midB = std::min(srcBounds.right(), dstBounds.right()); + mid = {midA, srcBounds.top() + radius, midB, srcBounds.bottom() - radius}; - left = {mid.left(), dstBounds.top(), mid.right(), mid.top() }; - right = {mid.left(), mid.bottom() , mid.right(), dstBounds.bottom()}; - - *contentRect = {std::max(contentRect->left(), dstBounds.left()), - dstBounds.top(), - std::min(contentRect->right(), dstBounds.right()), - dstBounds.bottom()}; + if (mid.isEmpty()) { + left = {mid.left(), dstBounds.top(), mid.right(), dstBounds.bottom()}; + } else { + left = {mid.left(), dstBounds.top(), mid.right(), mid.top() }; + right = {mid.left(), mid.bottom() , mid.right(), dstBounds.bottom()}; + } } - // Move all the rects from 'srcView' coord system to 'dstRenderTargetContext' coord system. - mid .offset(-rtcToSrcOffset); - top .offset(-rtcToSrcOffset); - bottom.offset(-rtcToSrcOffset); - left .offset(-rtcToSrcOffset); - right .offset(-rtcToSrcOffset); - contentRect->offset(-rtcToSrcOffset); + auto convolve = [&](SkIRect rect) { + // Transform rect into the render target's coord system. + rect.offset(-rtcToSrcOffset); + convolve_gaussian_1d(dstRenderTargetContext.get(), srcView, srcBounds, rtcToSrcOffset, rect, + srcAlphaType, direction, radius, sigma, mode); + }; + auto clear = [&](SkIRect rect) { + // Transform rect into the render target's coord system. + rect.offset(-rtcToSrcOffset); + dstRenderTargetContext->priv().clearAtLeast(rect, SK_PMColor4fTRANSPARENT); + }; + + // Doing mid separately will cause two draws to occur (left and right batch together). At + // small sizes of mid it is worse to issue more draws than to just execute the slightly + // more complicated shader that implements the tile mode across mid. This threshold is + // very arbitrary right now. It is believed that a 21x44 mid on a Moto G4 is a significant + // regression compared to doing one draw but it has not been locally evaluated or tuned. + // The optimal cutoff is likely to vary by GPU. + if (!mid.isEmpty() && mid.width()*mid.height() < 256*256) { + left.join(mid); + left.join(right); + mid = SkIRect::MakeEmpty(); + right = SkIRect::MakeEmpty(); + // It's unknown whether for kDecal it'd be better to expand the draw rather than a draw and + // up to two clears. + if (mode == SkTileMode::kClamp) { + left.join(top); + left.join(bottom); + top = SkIRect::MakeEmpty(); + bottom = SkIRect::MakeEmpty(); + } + } if (!top.isEmpty()) { - dstRenderTargetContext->clear(&top, SK_PMColor4fTRANSPARENT, - GrRenderTargetContext::CanClearFullscreen::kYes); + if (mode == SkTileMode::kDecal) { + clear(top); + } else { + convolve(top); + } } if (!bottom.isEmpty()) { - dstRenderTargetContext->clear(&bottom, SK_PMColor4fTRANSPARENT, - GrRenderTargetContext::CanClearFullscreen::kYes); + if (mode == SkTileMode::kDecal) { + clear(bottom); + } else { + convolve(bottom); + } } if (mid.isEmpty()) { - convolve_gaussian_1d(dstRenderTargetContext.get(), std::move(srcView), rtcToSrcOffset, - *contentRect, srcAlphaType, direction, radius, sigma, mode, bounds); + convolve(left); } else { - // Draw right and left margins with bounds; middle without. - convolve_gaussian_1d(dstRenderTargetContext.get(), srcView, rtcToSrcOffset, left, - srcAlphaType, direction, radius, sigma, mode, bounds); - convolve_gaussian_1d(dstRenderTargetContext.get(), srcView, rtcToSrcOffset, right, - srcAlphaType, direction, radius, sigma, mode, bounds); - convolve_gaussian_1d(dstRenderTargetContext.get(), std::move(srcView), rtcToSrcOffset, mid, - srcAlphaType, direction, radius, sigma, SkTileMode::kClamp, nullptr); + convolve(left); + convolve(right); + convolve(mid); } - return dstRenderTargetContext; } -// Returns a high quality scaled-down version of src. This is used to create an intermediate, -// shrunken version of the source image in the event that the requested blur sigma exceeds -// MAX_BLUR_SIGMA. -static GrSurfaceProxyView decimate(GrRecordingContext* context, - GrSurfaceProxyView srcView, - GrColorType srcColorType, - SkAlphaType srcAlphaType, - SkIPoint srcOffset, - SkIRect* contentRect, - int scaleFactorX, - int scaleFactorY, - SkTileMode mode, - sk_sp<SkColorSpace> finalCS) { - SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY)); - SkASSERT(scaleFactorX > 1 || scaleFactorY > 1); - - SkIRect srcRect = contentRect->makeOffset(srcOffset); - - scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); - scale_irect(&srcRect, scaleFactorX, scaleFactorY); - - SkIRect dstRect(srcRect); - - std::unique_ptr<GrRenderTargetContext> dstRenderTargetContext; - - for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { - shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY); - - dstRenderTargetContext = GrRenderTargetContext::Make( - context, srcColorType, finalCS, SkBackingFit::kApprox, - {dstRect.fRight, dstRect.fBottom}, 1, GrMipMapped::kNo, - srcView.proxy()->isProtected(), srcView.origin()); - if (!dstRenderTargetContext) { - return {}; - } - - GrPaint paint; - std::unique_ptr<GrFragmentProcessor> fp; - if (i == 1) { - GrSamplerState::WrapMode wrapMode = SkTileModeToWrapMode(mode); - const auto& caps = *context->priv().caps(); - GrSamplerState sampler(wrapMode, GrSamplerState::Filter::kBilerp); - fp = GrTextureEffect::MakeSubset(std::move(srcView), srcAlphaType, SkMatrix::I(), - sampler, SkRect::Make(*contentRect), caps); - srcRect.offset(-srcOffset); - } else { - fp = GrTextureEffect::Make(std::move(srcView), srcAlphaType, SkMatrix::I(), - GrSamplerState::Filter::kBilerp); - } - paint.addColorFragmentProcessor(std::move(fp)); - paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - - dstRenderTargetContext->fillRectToRect(GrFixedClip::Disabled(), std::move(paint), GrAA::kNo, - SkMatrix::I(), SkRect::Make(dstRect), - SkRect::Make(srcRect)); - - srcView = dstRenderTargetContext->readSurfaceView(); - if (!srcView.asTextureProxy()) { - return {}; - } - srcRect = dstRect; - } - - *contentRect = dstRect; - - SkASSERT(dstRenderTargetContext); - SkASSERT(srcView == dstRenderTargetContext->readSurfaceView()); - - return srcView; -} - // Expand the contents of 'srcRenderTargetContext' to fit in 'dstII'. At this point, we are // expanding an intermediate image, so there's no need to account for a proxy offset from the // original input. static std::unique_ptr<GrRenderTargetContext> reexpand(GrRecordingContext* context, std::unique_ptr<GrRenderTargetContext> src, - const SkIRect& srcBounds, - int scaleFactorX, - int scaleFactorY, + const SkRect& srcBounds, SkISize dstSize, sk_sp<SkColorSpace> colorSpace, SkBackingFit fit) { - const SkIRect srcRect = SkIRect::MakeWH(src->width(), src->height()); - GrSurfaceProxyView srcView = src->readSurfaceView(); if (!srcView.asTextureProxy()) { return nullptr; @@ -370,20 +265,14 @@ static std::unique_ptr<GrRenderTargetContext> reexpand(GrRecordingContext* conte } GrPaint paint; - const auto& caps = *context->priv().caps(); auto fp = GrTextureEffect::MakeSubset(std::move(srcView), srcAlphaType, SkMatrix::I(), - GrSamplerState::Filter::kBilerp, SkRect::Make(srcBounds), - caps); + GrSamplerState::Filter::kBilerp, srcBounds, srcBounds, + *context->priv().caps()); paint.addColorFragmentProcessor(std::move(fp)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - GrFixedClip clip(SkIRect::MakeSize(dstSize)); - - // TODO: using dstII as dstRect results in some image diffs - why? - SkIRect dstRect(srcRect); - scale_irect(&dstRect, scaleFactorX, scaleFactorY); - dstRenderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), - SkRect::Make(dstRect), SkRect::Make(srcRect)); + dstRenderTargetContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(dstSize), srcBounds); return dstRenderTargetContext; } @@ -393,7 +282,7 @@ static std::unique_ptr<GrRenderTargetContext> two_pass_gaussian(GrRecordingConte GrColorType srcColorType, SkAlphaType srcAlphaType, sk_sp<SkColorSpace> colorSpace, - SkIRect* srcBounds, + SkIRect srcBounds, SkIRect dstBounds, float sigmaX, float sigmaY, @@ -401,17 +290,90 @@ static std::unique_ptr<GrRenderTargetContext> two_pass_gaussian(GrRecordingConte int radiusY, SkTileMode mode, SkBackingFit fit) { + SkASSERT(sigmaX || sigmaY); std::unique_ptr<GrRenderTargetContext> dstRenderTargetContext; if (sigmaX > 0.0f) { SkBackingFit xFit = sigmaY > 0 ? SkBackingFit::kApprox : fit; + // Expand the dstBounds vertically to produce necessary content for the y-pass. Then we will + // clip these in a tile-mode dependent way to ensure the tile-mode gets implemented + // correctly. However, if we're not going to do a y-pass then we must use the original + // dstBounds without clipping to produce the correct output size. + SkIRect xPassDstBounds = dstBounds; + if (sigmaY) { + xPassDstBounds.outset(0, radiusY); + if (mode == SkTileMode::kRepeat || mode == SkTileMode::kMirror) { + int srcH = srcBounds.height(); + int srcTop = srcBounds.top(); + if (mode == SkTileMode::kMirror) { + srcTop -= srcH; + srcH *= 2; + } + + float floatH = srcH; + // First row above the dst rect where we should restart the tile mode. + int n = sk_float_floor2int_no_saturate((xPassDstBounds.top() - srcTop)/floatH); + int topClip = srcTop + n*srcH; + + // First row above below the dst rect where we should restart the tile mode. + n = sk_float_ceil2int_no_saturate( + (xPassDstBounds.bottom() - srcBounds.bottom())/floatH); + int bottomClip = srcBounds.bottom() + n*srcH; + + xPassDstBounds.fTop = std::max(xPassDstBounds.top(), topClip); + xPassDstBounds.fBottom = std::min(xPassDstBounds.bottom(), bottomClip); + } else { + if (xPassDstBounds.fBottom <= srcBounds.top()) { + if (mode == SkTileMode::kDecal) { + return nullptr; + } + xPassDstBounds.fTop = srcBounds.top(); + xPassDstBounds.fBottom = xPassDstBounds.fTop + 1; + } else if (xPassDstBounds.fTop >= srcBounds.bottom()) { + if (mode == SkTileMode::kDecal) { + return nullptr; + } + xPassDstBounds.fBottom = srcBounds.bottom(); + xPassDstBounds.fTop = xPassDstBounds.fBottom - 1; + } else { + xPassDstBounds.fTop = std::max(xPassDstBounds.fTop, srcBounds.top()); + xPassDstBounds.fBottom = std::min(xPassDstBounds.fBottom, srcBounds.bottom()); + } + int leftSrcEdge = srcBounds.fLeft - radiusX ; + int rightSrcEdge = srcBounds.fRight + radiusX; + if (mode == SkTileMode::kClamp) { + // In clamp the column just outside the src bounds has the same value as the + // column just inside, unlike decal. + leftSrcEdge += 1; + rightSrcEdge -= 1; + } + if (xPassDstBounds.fRight <= leftSrcEdge) { + if (mode == SkTileMode::kDecal) { + return nullptr; + } + xPassDstBounds.fLeft = xPassDstBounds.fRight - 1; + } else { + xPassDstBounds.fLeft = std::max(xPassDstBounds.fLeft, leftSrcEdge); + } + if (xPassDstBounds.fLeft >= rightSrcEdge) { + if (mode == SkTileMode::kDecal) { + return nullptr; + } + xPassDstBounds.fRight = xPassDstBounds.fLeft + 1; + } else { + xPassDstBounds.fRight = std::min(xPassDstBounds.fRight, rightSrcEdge); + } + } + } dstRenderTargetContext = convolve_gaussian( - context, std::move(srcView), srcColorType, srcAlphaType, srcBounds, dstBounds, + context, std::move(srcView), srcColorType, srcAlphaType, srcBounds, xPassDstBounds, Direction::kX, radiusX, sigmaX, mode, colorSpace, xFit); if (!dstRenderTargetContext) { return nullptr; } srcView = dstRenderTargetContext->readSurfaceView(); - dstBounds = SkIRect::MakeSize(dstBounds.size()); + SkIVector newDstBoundsOffset = dstBounds.topLeft() - xPassDstBounds.topLeft(); + dstBounds = SkIRect::MakeSize(dstBounds.size()).makeOffset(newDstBoundsOffset); + srcBounds = SkIRect::MakeSize(xPassDstBounds.size()); } if (sigmaY == 0.0f) { @@ -424,17 +386,33 @@ static std::unique_ptr<GrRenderTargetContext> two_pass_gaussian(GrRecordingConte namespace SkGpuBlurUtils { +std::unique_ptr<GrRenderTargetContext> LegacyGaussianBlur(GrRecordingContext* context, + GrSurfaceProxyView srcView, + GrColorType srcColorType, + SkAlphaType srcAlphaType, + sk_sp<SkColorSpace> colorSpace, + const SkIRect& dstBounds, + const SkIRect& srcBounds, + float sigmaX, + float sigmaY, + SkTileMode mode, + SkBackingFit fit); + std::unique_ptr<GrRenderTargetContext> GaussianBlur(GrRecordingContext* context, GrSurfaceProxyView srcView, GrColorType srcColorType, SkAlphaType srcAlphaType, sk_sp<SkColorSpace> colorSpace, - const SkIRect& dstBounds, - const SkIRect& srcBounds, + SkIRect dstBounds, + SkIRect srcBounds, float sigmaX, float sigmaY, SkTileMode mode, SkBackingFit fit) { +#ifdef SK_USE_LEGACY_GPU_BLUR + return LegacyGaussianBlur(context, srcView, srcColorType, srcAlphaType, std::move(colorSpace), + dstBounds, srcBounds, sigmaX, sigmaY, mode, fit); +#endif SkASSERT(context); TRACE_EVENT2("skia.gpu", "GaussianBlur", "sigmaX", sigmaX, "sigmaY", sigmaY); @@ -442,16 +420,72 @@ std::unique_ptr<GrRenderTargetContext> GaussianBlur(GrRecordingContext* context, return nullptr; } - int scaleFactorX, radiusX; - int scaleFactorY, radiusY; - int maxTextureSize = context->priv().caps()->maxTextureSize(); - sigmaX = adjust_sigma(sigmaX, maxTextureSize, &scaleFactorX, &radiusX); - sigmaY = adjust_sigma(sigmaY, maxTextureSize, &scaleFactorY, &radiusY); - SkASSERT(sigmaX || sigmaY); + int maxRenderTargetSize = context->priv().caps()->maxRenderTargetSize(); + if (dstBounds.width() > maxRenderTargetSize || dstBounds.height() > maxRenderTargetSize) { + return nullptr; + } - auto localSrcBounds = srcBounds; + // Attempt to reduce the srcBounds in order to detect that we can set the sigmas to zero or + // to reduce the amount of work to rescale the source if sigmas are large. TODO: Could consider + // how to minimize the required source bounds for repeat/mirror modes. + if (mode == SkTileMode::kClamp || mode == SkTileMode::kDecal) { + int radiusX = sigma_radius(sigmaX); + int radiusY = sigma_radius(sigmaY); + SkIRect reach = dstBounds.makeOutset(radiusX, radiusY); + SkIRect intersection; + if (!intersection.intersect(reach, srcBounds)) { + if (mode == SkTileMode::kDecal) { + return nullptr; + } else { + if (reach.fLeft >= srcBounds.fRight) { + srcBounds.fLeft = srcBounds.fRight - 1; + } else if (reach.fRight <= srcBounds.fLeft) { + srcBounds.fRight = srcBounds.fLeft + 1; + } + if (reach.fTop >= srcBounds.fBottom) { + srcBounds.fTop = srcBounds.fBottom - 1; + } else if (reach.fBottom <= srcBounds.fTop) { + srcBounds.fBottom = srcBounds.fTop + 1; + } + } + } else { + srcBounds = intersection; + } + } - if (scaleFactorX == 1 && scaleFactorY == 1) { + if (mode != SkTileMode::kDecal) { + // All non-decal tile modes are equivalent for one pixel width/height src and amount to a + // single color value repeated at each column/row. Applying the normalized kernel to that + // column/row yields that same color. So no blurring is necessary. + if (srcBounds.width() == 1) { + sigmaX = 0.f; + } + if (srcBounds.height() == 1) { + sigmaY = 0.f; + } + } + + // If we determined that there is no blurring necessary in either direction then just do a + // a draw that applies the tile mode. + if (!sigmaX && !sigmaY) { + auto result = GrRenderTargetContext::Make(context, srcColorType, std::move(colorSpace), fit, + dstBounds.size()); + GrSamplerState sampler(SkTileModeToWrapMode(mode), GrSamplerState::Filter::kNearest); + auto fp = GrTextureEffect::MakeSubset(std::move(srcView), srcAlphaType, SkMatrix::I(), + sampler, SkRect::Make(srcBounds), + SkRect::Make(dstBounds), *context->priv().caps()); + GrPaint paint; + paint.addColorFragmentProcessor(std::move(fp)); + result->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(dstBounds.size())); + return result; + } + + if (sigmaX <= MAX_BLUR_SIGMA && sigmaY <= MAX_BLUR_SIGMA) { + int radiusX = sigma_radius(sigmaX); + int radiusY = sigma_radius(sigmaY); + SkASSERT(radiusX <= GrGaussianConvolutionFragmentProcessor::kMaxKernelRadius); + SkASSERT(radiusY <= GrGaussianConvolutionFragmentProcessor::kMaxKernelRadius); // For really small blurs (certainly no wider than 5x5 on desktop GPUs) it is faster to just // launch a single non separable kernel vs two launches. const int kernelSize = (2 * radiusX + 1) * (2 * radiusY + 1); @@ -459,32 +493,64 @@ std::unique_ptr<GrRenderTargetContext> GaussianBlur(GrRecordingContext* context, // Apply the proxy offset to src bounds and offset directly return convolve_gaussian_2d(context, std::move(srcView), srcColorType, srcBounds, dstBounds, radiusX, radiusY, sigmaX, sigmaY, mode, - colorSpace, fit); + std::move(colorSpace), fit); } return two_pass_gaussian(context, std::move(srcView), srcColorType, srcAlphaType, - std::move(colorSpace), &localSrcBounds, dstBounds, sigmaX, sigmaY, + std::move(colorSpace), srcBounds, dstBounds, sigmaX, sigmaY, radiusX, radiusY, mode, fit); } - auto srcOffset = -dstBounds.topLeft(); - srcView = decimate(context, std::move(srcView), srcColorType, srcAlphaType, srcOffset, - &localSrcBounds, scaleFactorX, scaleFactorY, mode, colorSpace); - if (!srcView.proxy()) { + float scaleX = sigmaX > MAX_BLUR_SIGMA ? MAX_BLUR_SIGMA/sigmaX : 1.f; + float scaleY = sigmaY > MAX_BLUR_SIGMA ? MAX_BLUR_SIGMA/sigmaY : 1.f; + // We round down here so that when we recalculate sigmas we know they will be below + // MAX_BLUR_SIGMA. + SkISize rescaledSize = {sk_float_floor2int(srcBounds.width() *scaleX), + sk_float_floor2int(srcBounds.height()*scaleY)}; + if (rescaledSize.isEmpty()) { + // TODO: Handle this degenerate case. + return nullptr; + } + // Compute the sigmas using the actual scale factors used once we integerized the rescaledSize. + scaleX = static_cast<float>(rescaledSize.width()) /srcBounds.width(); + scaleY = static_cast<float>(rescaledSize.height())/srcBounds.height(); + sigmaX *= scaleX; + sigmaY *= scaleY; + + auto srcCtx = GrSurfaceContext::Make(context, srcView, srcColorType, srcAlphaType, colorSpace); + SkASSERT(srcCtx); + GrImageInfo rescaledII(srcColorType, srcAlphaType, colorSpace, rescaledSize); + srcCtx = srcCtx->rescale(rescaledII, srcCtx->origin(), srcBounds, SkSurface::RescaleGamma::kSrc, + kLow_SkFilterQuality); + if (!srcCtx) { return nullptr; } - SkASSERT(srcView.asTextureProxy()); - auto scaledDstBounds = SkIRect::MakeWH(sk_float_ceil(dstBounds.width() / (float)scaleFactorX), - sk_float_ceil(dstBounds.height() / (float)scaleFactorY)); - auto rtc = two_pass_gaussian(context, std::move(srcView), srcColorType, srcAlphaType, - colorSpace, &localSrcBounds, scaledDstBounds, sigmaX, sigmaY, - radiusX, radiusY, mode, SkBackingFit::kApprox); + srcView = srcCtx->readSurfaceView(); + // Drop the context so we don't hold the proxy longer than necessary. + srcCtx.reset(); + + // Compute the dst bounds in the scaled down space. First move the origin to be at the top + // left since we trimmed off everything above and to the left of the original src bounds during + // the rescale. + SkRect scaledDstBounds = SkRect::Make(dstBounds.makeOffset(-srcBounds.topLeft())); + scaledDstBounds.fLeft *= scaleX; + scaledDstBounds.fTop *= scaleY; + scaledDstBounds.fRight *= scaleX; + scaledDstBounds.fBottom *= scaleY; + // Turn the scaled down dst bounds into an integer pixel rect. + auto scaledDstBoundsI = scaledDstBounds.roundOut(); + + auto rtc = GaussianBlur(context, std::move(srcView), srcColorType, srcAlphaType, colorSpace, + scaledDstBoundsI, SkIRect::MakeSize(rescaledSize), sigmaX, sigmaY, mode, + fit); if (!rtc) { return nullptr; } - return reexpand(context, std::move(rtc), localSrcBounds, scaleFactorX, scaleFactorY, - dstBounds.size(), std::move(colorSpace), fit); + // We rounded out the integer scaled dst bounds. Select the fractional dst bounds from the + // integer dimension blurred result when we scale back up. + scaledDstBounds.offset(-scaledDstBoundsI.left(), -scaledDstBoundsI.top()); + return reexpand(context, std::move(rtc), scaledDstBounds, dstBounds.size(), + std::move(colorSpace), fit); } - } #endif diff --git a/chromium/third_party/skia/src/core/SkGpuBlurUtils.h b/chromium/third_party/skia/src/core/SkGpuBlurUtils.h index 3e78c4ceeca..63d8fedea19 100644 --- a/chromium/third_party/skia/src/core/SkGpuBlurUtils.h +++ b/chromium/third_party/skia/src/core/SkGpuBlurUtils.h @@ -18,36 +18,33 @@ struct SkRect; namespace SkGpuBlurUtils { /** - * Applies a 2D Gaussian blur to a given texture. The blurred result is returned - * as a renderTargetContext in case the caller wishes to draw into the result. - * - * The 'proxyOffset' is kept separate form 'srcBounds' because they exist in different - * coordinate spaces. 'srcBounds' exists in the content space of the special image, and - * 'proxyOffset' maps from the content space to the proxy's space. - * - * Note: one of sigmaX and sigmaY should be non-zero! - * @param context The GPU context - * @param srcView The source to be blurred. - * @param srcColorType The colorType of srcProxy - * @param srcAlphaType The alphaType of srcProxy - * @param colorSpace Color space of the source (used for the renderTargetContext result, - * too). - * @param dstBounds The destination bounds, relative to the source texture. - * @param srcBounds The source bounds, relative to the source texture's offset. No pixels - * will be sampled outside of this rectangle. - * @param sigmaX The blur's standard deviation in X. - * @param sigmaY The blur's standard deviation in Y. - * @param tileMode The mode to handle samples outside bounds. - * @param fit backing fit for the returned render target context - * @return The renderTargetContext containing the blurred result. - */ + * Applies a 2D Gaussian blur to a given texture. The blurred result is returned + * as a renderTargetContext in case the caller wishes to draw into the result. + * The GrSurfaceOrigin of the result will watch the GrSurfaceOrigin of srcView. The output + * color type, color space, and alpha type will be the same as the src. + * + * Note: one of sigmaX and sigmaY should be non-zero! + * @param context The GPU context + * @param srcView The source to be blurred. + * @param srcColorType The colorType of srcProxy + * @param srcAlphaType The alphaType of srcProxy + * @param colorSpace Color space of the source. + * @param dstBounds The destination bounds, relative to the source texture. + * @param srcBounds The source bounds, relative to the source texture's offset. No pixels + * will be sampled outside of this rectangle. + * @param sigmaX The blur's standard deviation in X. + * @param sigmaY The blur's standard deviation in Y. + * @param tileMode The mode to handle samples outside bounds. + * @param fit backing fit for the returned render target context + * @return The renderTargetContext containing the blurred result. + */ std::unique_ptr<GrRenderTargetContext> GaussianBlur(GrRecordingContext* context, GrSurfaceProxyView srcView, GrColorType srcColorType, SkAlphaType srcAlphaType, sk_sp<SkColorSpace> colorSpace, - const SkIRect& dstBounds, - const SkIRect& srcBounds, + SkIRect dstBounds, + SkIRect srcBounds, float sigmaX, float sigmaY, SkTileMode mode, diff --git a/chromium/third_party/skia/src/core/SkImageFilter.cpp b/chromium/third_party/skia/src/core/SkImageFilter.cpp index 80f4d0b62d6..f9a85ffa4db 100644 --- a/chromium/third_party/skia/src/core/SkImageFilter.cpp +++ b/chromium/third_party/skia/src/core/SkImageFilter.cpp @@ -26,7 +26,6 @@ #include "include/private/GrRecordingContext.h" #include "src/gpu/GrColorSpaceXform.h" #include "src/gpu/GrContextPriv.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/GrTextureProxy.h" @@ -114,7 +113,7 @@ bool SkImageFilter::asAColorFilter(SkColorFilter** filterPtr) const { if (!this->isColorFilterNode(filterPtr)) { return false; } - if (nullptr != this->getInput(0) || (*filterPtr)->affectsTransparentBlack()) { + if (nullptr != this->getInput(0) || as_CFB(*filterPtr)->affectsTransparentBlack()) { (*filterPtr)->unref(); return false; } @@ -231,14 +230,9 @@ skif::FilterResult<For::kOutput> SkImageFilter_Base::filterImage(const skif::Con result = this->onFilterImage(context); -#if SK_SUPPORT_GPU - if (context.gpuBacked() && result.image() && !result.image()->isTextureBacked()) { - // Keep the result on the GPU - this is still required for some - // image filters that don't support GPU in all cases - auto asTexture = result.image()->makeTextureImage(context.getContext()); - result = skif::FilterResult<For::kOutput>(std::move(asTexture), result.layerOrigin()); + if (context.gpuBacked()) { + SkASSERT(!result.image() || result.image()->isTextureBacked()); } -#endif if (context.cache()) { context.cache()->set(key, this, result); @@ -586,9 +580,8 @@ sk_sp<SkSpecialImage> SkImageFilter_Base::DrawWithFP(GrRecordingContext* context SkIRect dstIRect = SkIRect::MakeWH(bounds.width(), bounds.height()); SkRect srcRect = SkRect::Make(bounds); SkRect dstRect = SkRect::MakeWH(srcRect.width(), srcRect.height()); - GrFixedClip clip(dstIRect); - renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect, - srcRect); + renderTargetContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), + dstRect, srcRect); return SkSpecialImage::MakeDeferredFromGpu( context, dstIRect, kNeedNewImageUniqueID_SpecialImage, diff --git a/chromium/third_party/skia/src/core/SkImageFilterTypes.cpp b/chromium/third_party/skia/src/core/SkImageFilterTypes.cpp index f2f6667967c..ab967239e58 100644 --- a/chromium/third_party/skia/src/core/SkImageFilterTypes.cpp +++ b/chromium/third_party/skia/src/core/SkImageFilterTypes.cpp @@ -37,7 +37,7 @@ Mapping Mapping::Make(const SkMatrix& ctm, const SkImageFilter* filter) { // TODO (michaelludwig) - Should maybe strip out any fractional part of the translation in // 'ctm' so that can be incorporated during regular drawing, instead of by resampling the // filtered image. - layer = SkMatrix::MakeScale(scale.fWidth, scale.fHeight); + layer = SkMatrix::Scale(scale.fWidth, scale.fHeight); } else { // Perspective // TODO (michaelludwig) - Should investigate choosing a scale factor for the layer matrix diff --git a/chromium/third_party/skia/src/core/SkImageInfo.cpp b/chromium/third_party/skia/src/core/SkImageInfo.cpp index 11789d10be3..81994fb6ef4 100644 --- a/chromium/third_party/skia/src/core/SkImageInfo.cpp +++ b/chromium/third_party/skia/src/core/SkImageInfo.cpp @@ -90,7 +90,7 @@ bool SkColorTypeValidateAlphaType(SkColorType colorType, SkAlphaType alphaType, if (kUnpremul_SkAlphaType == alphaType) { alphaType = kPremul_SkAlphaType; } - // fall-through + [[fallthrough]]; case kARGB_4444_SkColorType: case kRGBA_8888_SkColorType: case kBGRA_8888_SkColorType: diff --git a/chromium/third_party/skia/src/core/SkLegacyGpuBlurUtils.cpp b/chromium/third_party/skia/src/core/SkLegacyGpuBlurUtils.cpp new file mode 100644 index 00000000000..461da44cf28 --- /dev/null +++ b/chromium/third_party/skia/src/core/SkLegacyGpuBlurUtils.cpp @@ -0,0 +1,485 @@ +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/core/SkGpuBlurUtils.h" + +#include "include/core/SkRect.h" + +#if SK_SUPPORT_GPU +#include "include/private/GrRecordingContext.h" +#include "src/gpu/GrCaps.h" +#include "src/gpu/GrRecordingContextPriv.h" +#include "src/gpu/GrRenderTargetContext.h" +#include "src/gpu/GrRenderTargetContextPriv.h" +#include "src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h" +#include "src/gpu/effects/GrMatrixConvolutionEffect.h" + +#include "src/gpu/SkGr.h" + +#define MAX_BLUR_SIGMA 4.0f + +using Direction = GrGaussianConvolutionFragmentProcessor::Direction; + +static void scale_irect_roundout(SkIRect* rect, float xScale, float yScale) { + rect->fLeft = SkScalarFloorToInt(rect->fLeft * xScale); + rect->fTop = SkScalarFloorToInt(rect->fTop * yScale); + rect->fRight = SkScalarCeilToInt(rect->fRight * xScale); + rect->fBottom = SkScalarCeilToInt(rect->fBottom * yScale); +} + +static void scale_irect(SkIRect* rect, int xScale, int yScale) { + rect->fLeft *= xScale; + rect->fTop *= yScale; + rect->fRight *= xScale; + rect->fBottom *= yScale; +} + +#ifdef SK_DEBUG +static inline int is_even(int x) { return !(x & 1); } +#endif + +static void shrink_irect_by_2(SkIRect* rect, bool xAxis, bool yAxis) { + if (xAxis) { + SkASSERT(is_even(rect->fLeft) && is_even(rect->fRight)); + rect->fLeft /= 2; + rect->fRight /= 2; + } + if (yAxis) { + SkASSERT(is_even(rect->fTop) && is_even(rect->fBottom)); + rect->fTop /= 2; + rect->fBottom /= 2; + } +} + +static float adjust_sigma(float sigma, int maxTextureSize, int *scaleFactor, int *radius) { + *scaleFactor = 1; + while (sigma > MAX_BLUR_SIGMA) { + *scaleFactor *= 2; + sigma *= 0.5f; + if (*scaleFactor > maxTextureSize) { + *scaleFactor = maxTextureSize; + sigma = MAX_BLUR_SIGMA; + } + } + *radius = static_cast<int>(ceilf(sigma * 3.0f)); + SkASSERT(*radius <= GrGaussianConvolutionFragmentProcessor::kMaxKernelRadius); + return sigma; +} + +/** + * Draws 'rtcRect' into 'renderTargetContext' evaluating a 1D Gaussian over 'srcView'. The src rect + * is 'rtcRect' offset by 'rtcToSrcOffset'. 'mode' and 'bounds' are applied to the src coords. + */ +static void convolve_gaussian_1d(GrRenderTargetContext* renderTargetContext, + GrSurfaceProxyView srcView, + SkIVector rtcToSrcOffset, + const SkIRect& rtcRect, + SkAlphaType srcAlphaType, + Direction direction, + int radius, + float sigma, + SkTileMode mode, + int bounds[2]) { + GrPaint paint; + auto wm = SkTileModeToWrapMode(mode); + auto subset = SkIRect::MakeSize(srcView.dimensions()); + if (bounds) { + switch (direction) { + case Direction::kX: subset.fLeft = bounds[0]; subset.fRight = bounds[1]; break; + case Direction::kY: subset.fTop = bounds[0]; subset.fBottom = bounds[1]; break; + } + } + std::unique_ptr<GrFragmentProcessor> conv(GrGaussianConvolutionFragmentProcessor::Make( + std::move(srcView), srcAlphaType, direction, radius, sigma, wm, subset, nullptr, + *renderTargetContext->caps())); + paint.addColorFragmentProcessor(std::move(conv)); + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + auto srcRect = SkRect::Make(rtcRect.makeOffset(rtcToSrcOffset)); + renderTargetContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(rtcRect), srcRect); +} + +static std::unique_ptr<GrRenderTargetContext> convolve_gaussian_2d(GrRecordingContext* context, + GrSurfaceProxyView srcView, + GrColorType srcColorType, + const SkIRect& srcBounds, + const SkIRect& dstBounds, + int radiusX, + int radiusY, + SkScalar sigmaX, + SkScalar sigmaY, + SkTileMode mode, + sk_sp<SkColorSpace> finalCS, + SkBackingFit dstFit) { + auto renderTargetContext = GrRenderTargetContext::Make( + context, srcColorType, std::move(finalCS), dstFit, dstBounds.size(), 1, + GrMipMapped::kNo, srcView.proxy()->isProtected(), srcView.origin()); + if (!renderTargetContext) { + return nullptr; + } + + SkISize size = SkISize::Make(2 * radiusX + 1, 2 * radiusY + 1); + SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY); + GrPaint paint; + auto wm = SkTileModeToWrapMode(mode); + auto conv = GrMatrixConvolutionEffect::MakeGaussian(context, std::move(srcView), srcBounds, + size, 1.0, 0.0, kernelOffset, wm, true, + sigmaX, sigmaY, + *renderTargetContext->caps()); + paint.addColorFragmentProcessor(std::move(conv)); + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + + // 'dstBounds' is actually in 'srcView' proxy space. It represents the blurred area from src + // space that we want to capture in the new RTC at {0, 0}. Hence, we use its size as the rect to + // draw and it directly as the local rect. + renderTargetContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(dstBounds.size()), SkRect::Make(dstBounds)); + + return renderTargetContext; +} + +static std::unique_ptr<GrRenderTargetContext> convolve_gaussian(GrRecordingContext* context, + GrSurfaceProxyView srcView, + GrColorType srcColorType, + SkAlphaType srcAlphaType, + SkIRect* contentRect, + SkIRect dstBounds, + Direction direction, + int radius, + float sigma, + SkTileMode mode, + sk_sp<SkColorSpace> finalCS, + SkBackingFit fit) { + // Logically we're creating an infinite blur of 'contentRect' of 'srcView' with 'mode' tiling + // and then capturing the 'dstBounds' portion in a new RTC where the top left of 'dstBounds' is + // at {0, 0} in the new RTC. + auto dstRenderTargetContext = GrRenderTargetContext::Make( + context, srcColorType, std::move(finalCS), fit, dstBounds.size(), 1, GrMipMapped::kNo, + srcView.proxy()->isProtected(), srcView.origin()); + if (!dstRenderTargetContext) { + return nullptr; + } + + // This represents the translation from 'dstRenderTargetContext' coords to 'srcView' coords. + auto rtcToSrcOffset = dstBounds.topLeft(); + + if (SkTileMode::kClamp == mode && + contentRect->contains(SkIRect::MakeSize(srcView.proxy()->backingStoreDimensions()))) { + auto dstRect = SkIRect::MakeSize(dstBounds.size()); + convolve_gaussian_1d(dstRenderTargetContext.get(), std::move(srcView), rtcToSrcOffset, + dstRect, srcAlphaType, direction, radius, sigma, SkTileMode::kClamp, + nullptr); + *contentRect = dstRect; + return dstRenderTargetContext; + } + + // 'left' and 'right' are the sub rects of 'contentTect' where 'mode' must be enforced. + // 'mid' is the area where we can ignore the mode because the kernel does not reach to the + // edge of 'contentRect'. The names are derived from the Direction::kX case. + // TODO: When mode is kMirror or kRepeat it makes more sense to think of 'contentRect' + // as a tile and figure out the collection of mid/left/right rects that cover 'dstBounds'. + // Also if 'mid' is small and 'left' or 'right' is non-empty we should probably issue one + // draw that implements the mode in the shader rather than break it up in this fashion. + SkIRect mid, left, right; + // 'top' and 'bottom' are areas of 'dstBounds' that are entirely above/below + // 'contentRect'. These are areas that we can simply clear in the dst. If 'contentRect' + // straddles the top edge of 'dstBounds' then 'top' will be inverted and we will skip + // the clear. Similar for 'bottom'. The positional/directional labels above refer to the + // Direction::kX case and one should think of these as 'left' and 'right' for Direction::kY. + SkIRect top, bottom; + int bounds[2]; + if (Direction::kX == direction) { + bounds[0] = contentRect->left(); + bounds[1] = contentRect->right(); + + top = {dstBounds.left(), dstBounds.top() , dstBounds.right(), contentRect->top()}; + bottom = {dstBounds.left(), contentRect->bottom(), dstBounds.right(), dstBounds.bottom()}; + + // Inset for sub-rect of 'contentRect' where the x-dir kernel doesn't reach the edges. + // TODO: Consider clipping mid/left/right to dstBounds to increase likelihood of doing + // fewer draws below. + mid = contentRect->makeInset(radius, 0); + + left = {dstBounds.left(), mid.top(), mid.left() , mid.bottom()}; + right = {mid.right(), mid.top(), dstBounds.right(), mid.bottom()}; + + // The new 'contentRect' when we're done will be the area between the clears in the dst. + *contentRect = {dstBounds.left(), + std::max(contentRect->top(), dstBounds.top()), + dstBounds.right(), + std::min(dstBounds.bottom(), contentRect->bottom())}; + } else { + // This is the same as the x direction code if you turn your head 90 degrees CCW. Swap x and + // y and swap top/bottom with left/right. + bounds[0] = contentRect->top(); + bounds[1] = contentRect->bottom(); + + top = {dstBounds.left(), dstBounds.top() , contentRect->left(), dstBounds.bottom()}; + bottom = {contentRect->right(), dstBounds.top() , dstBounds.right() , dstBounds.bottom()}; + + mid = contentRect->makeInset(0, radius); + + left = {mid.left(), dstBounds.top(), mid.right(), mid.top() }; + right = {mid.left(), mid.bottom() , mid.right(), dstBounds.bottom()}; + + *contentRect = {std::max(contentRect->left(), dstBounds.left()), + dstBounds.top(), + std::min(contentRect->right(), dstBounds.right()), + dstBounds.bottom()}; + } + // Move all the rects from 'srcView' coord system to 'dstRenderTargetContext' coord system. + mid .offset(-rtcToSrcOffset); + top .offset(-rtcToSrcOffset); + bottom.offset(-rtcToSrcOffset); + left .offset(-rtcToSrcOffset); + right .offset(-rtcToSrcOffset); + + contentRect->offset(-rtcToSrcOffset); + + if (!top.isEmpty()) { + dstRenderTargetContext->priv().clearAtLeast(top, SK_PMColor4fTRANSPARENT); + } + + if (!bottom.isEmpty()) { + dstRenderTargetContext->priv().clearAtLeast(bottom, SK_PMColor4fTRANSPARENT); + } + + if (mid.isEmpty()) { + convolve_gaussian_1d(dstRenderTargetContext.get(), std::move(srcView), rtcToSrcOffset, + *contentRect, srcAlphaType, direction, radius, sigma, mode, bounds); + } else { + // Draw right and left margins with bounds; middle without. + convolve_gaussian_1d(dstRenderTargetContext.get(), srcView, rtcToSrcOffset, left, + srcAlphaType, direction, radius, sigma, mode, bounds); + convolve_gaussian_1d(dstRenderTargetContext.get(), srcView, rtcToSrcOffset, right, + srcAlphaType, direction, radius, sigma, mode, bounds); + convolve_gaussian_1d(dstRenderTargetContext.get(), std::move(srcView), rtcToSrcOffset, mid, + srcAlphaType, direction, radius, sigma, SkTileMode::kClamp, nullptr); + } + + return dstRenderTargetContext; +} + +// Returns a high quality scaled-down version of src. This is used to create an intermediate, +// shrunken version of the source image in the event that the requested blur sigma exceeds +// MAX_BLUR_SIGMA. +static GrSurfaceProxyView decimate(GrRecordingContext* context, + GrSurfaceProxyView srcView, + GrColorType srcColorType, + SkAlphaType srcAlphaType, + SkIPoint srcOffset, + SkIRect* contentRect, + int scaleFactorX, + int scaleFactorY, + SkTileMode mode, + sk_sp<SkColorSpace> finalCS) { + SkASSERT(SkIsPow2(scaleFactorX) && SkIsPow2(scaleFactorY)); + SkASSERT(scaleFactorX > 1 || scaleFactorY > 1); + + SkIRect srcRect = contentRect->makeOffset(srcOffset); + + scale_irect_roundout(&srcRect, 1.0f / scaleFactorX, 1.0f / scaleFactorY); + scale_irect(&srcRect, scaleFactorX, scaleFactorY); + + SkIRect dstRect(srcRect); + + std::unique_ptr<GrRenderTargetContext> dstRenderTargetContext; + + for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) { + shrink_irect_by_2(&dstRect, i < scaleFactorX, i < scaleFactorY); + + dstRenderTargetContext = GrRenderTargetContext::Make( + context, srcColorType, finalCS, SkBackingFit::kApprox, + {dstRect.fRight, dstRect.fBottom}, 1, GrMipMapped::kNo, + srcView.proxy()->isProtected(), srcView.origin()); + if (!dstRenderTargetContext) { + return {}; + } + + GrPaint paint; + std::unique_ptr<GrFragmentProcessor> fp; + if (i == 1) { + GrSamplerState::WrapMode wrapMode = SkTileModeToWrapMode(mode); + const auto& caps = *context->priv().caps(); + GrSamplerState sampler(wrapMode, GrSamplerState::Filter::kBilerp); + fp = GrTextureEffect::MakeSubset(std::move(srcView), srcAlphaType, SkMatrix::I(), + sampler, SkRect::Make(*contentRect), caps); + srcRect.offset(-srcOffset); + } else { + fp = GrTextureEffect::Make(std::move(srcView), srcAlphaType, SkMatrix::I(), + GrSamplerState::Filter::kBilerp); + } + paint.addColorFragmentProcessor(std::move(fp)); + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + + dstRenderTargetContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, + SkMatrix::I(), SkRect::Make(dstRect), + SkRect::Make(srcRect)); + + srcView = dstRenderTargetContext->readSurfaceView(); + if (!srcView.asTextureProxy()) { + return {}; + } + srcRect = dstRect; + } + + *contentRect = dstRect; + + SkASSERT(dstRenderTargetContext); + SkASSERT(srcView == dstRenderTargetContext->readSurfaceView()); + + return srcView; +} + +// Expand the contents of 'srcRenderTargetContext' to fit in 'dstII'. At this point, we are +// expanding an intermediate image, so there's no need to account for a proxy offset from the +// original input. +static std::unique_ptr<GrRenderTargetContext> reexpand(GrRecordingContext* context, + std::unique_ptr<GrRenderTargetContext> src, + const SkIRect& srcBounds, + int scaleFactorX, + int scaleFactorY, + SkISize dstSize, + sk_sp<SkColorSpace> colorSpace, + SkBackingFit fit) { + const SkIRect srcRect = SkIRect::MakeWH(src->width(), src->height()); + + GrSurfaceProxyView srcView = src->readSurfaceView(); + if (!srcView.asTextureProxy()) { + return nullptr; + } + + GrColorType srcColorType = src->colorInfo().colorType(); + SkAlphaType srcAlphaType = src->colorInfo().alphaType(); + + src.reset(); // no longer needed + + auto dstRenderTargetContext = GrRenderTargetContext::Make( + context, srcColorType, std::move(colorSpace), fit, dstSize, 1, GrMipMapped::kNo, + srcView.proxy()->isProtected(), srcView.origin()); + if (!dstRenderTargetContext) { + return nullptr; + } + + GrPaint paint; + const auto& caps = *context->priv().caps(); + auto fp = GrTextureEffect::MakeSubset(std::move(srcView), srcAlphaType, SkMatrix::I(), + GrSamplerState::Filter::kBilerp, SkRect::Make(srcBounds), + caps); + paint.addColorFragmentProcessor(std::move(fp)); + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + + // TODO: using dstII as dstRect results in some image diffs - why? + SkIRect dstRect(srcRect); + scale_irect(&dstRect, scaleFactorX, scaleFactorY); + + dstRenderTargetContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(dstRect), SkRect::Make(srcRect)); + + return dstRenderTargetContext; +} + +static std::unique_ptr<GrRenderTargetContext> two_pass_gaussian(GrRecordingContext* context, + GrSurfaceProxyView srcView, + GrColorType srcColorType, + SkAlphaType srcAlphaType, + sk_sp<SkColorSpace> colorSpace, + SkIRect* srcBounds, + SkIRect dstBounds, + float sigmaX, + float sigmaY, + int radiusX, + int radiusY, + SkTileMode mode, + SkBackingFit fit) { + std::unique_ptr<GrRenderTargetContext> dstRenderTargetContext; + if (sigmaX > 0.0f) { + SkBackingFit xFit = sigmaY > 0 ? SkBackingFit::kApprox : fit; + dstRenderTargetContext = convolve_gaussian( + context, std::move(srcView), srcColorType, srcAlphaType, srcBounds, dstBounds, + Direction::kX, radiusX, sigmaX, mode, colorSpace, xFit); + if (!dstRenderTargetContext) { + return nullptr; + } + srcView = dstRenderTargetContext->readSurfaceView(); + dstBounds = SkIRect::MakeSize(dstBounds.size()); + } + + if (sigmaY == 0.0f) { + return dstRenderTargetContext; + } + + return convolve_gaussian(context, std::move(srcView), srcColorType, srcAlphaType, srcBounds, + dstBounds, Direction::kY, radiusY, sigmaY, mode, colorSpace, fit); +} + +namespace SkGpuBlurUtils { + +std::unique_ptr<GrRenderTargetContext> LegacyGaussianBlur(GrRecordingContext* context, + GrSurfaceProxyView srcView, + GrColorType srcColorType, + SkAlphaType srcAlphaType, + sk_sp<SkColorSpace> colorSpace, + const SkIRect& dstBounds, + const SkIRect& srcBounds, + float sigmaX, + float sigmaY, + SkTileMode mode, + SkBackingFit fit) { + SkASSERT(context); + TRACE_EVENT2("skia.gpu", "GaussianBlur", "sigmaX", sigmaX, "sigmaY", sigmaY); + + if (!srcView.asTextureProxy()) { + return nullptr; + } + + int scaleFactorX, radiusX; + int scaleFactorY, radiusY; + int maxTextureSize = context->priv().caps()->maxTextureSize(); + sigmaX = adjust_sigma(sigmaX, maxTextureSize, &scaleFactorX, &radiusX); + sigmaY = adjust_sigma(sigmaY, maxTextureSize, &scaleFactorY, &radiusY); + SkASSERT(sigmaX || sigmaY); + + auto localSrcBounds = srcBounds; + + if (scaleFactorX == 1 && scaleFactorY == 1) { + // For really small blurs (certainly no wider than 5x5 on desktop GPUs) it is faster to just + // launch a single non separable kernel vs two launches. + const int kernelSize = (2 * radiusX + 1) * (2 * radiusY + 1); + if (sigmaX > 0 && sigmaY > 0 && kernelSize <= GrMatrixConvolutionEffect::kMaxUniformSize) { + // Apply the proxy offset to src bounds and offset directly + return convolve_gaussian_2d(context, std::move(srcView), srcColorType, srcBounds, + dstBounds, radiusX, radiusY, sigmaX, sigmaY, mode, + colorSpace, fit); + } + return two_pass_gaussian(context, std::move(srcView), srcColorType, srcAlphaType, + std::move(colorSpace), &localSrcBounds, dstBounds, sigmaX, sigmaY, + radiusX, radiusY, mode, fit); + } + + auto srcOffset = -dstBounds.topLeft(); + srcView = decimate(context, std::move(srcView), srcColorType, srcAlphaType, srcOffset, + &localSrcBounds, scaleFactorX, scaleFactorY, mode, colorSpace); + if (!srcView.proxy()) { + return nullptr; + } + SkASSERT(srcView.asTextureProxy()); + auto scaledDstBounds = SkIRect::MakeWH(sk_float_ceil(dstBounds.width() / (float)scaleFactorX), + sk_float_ceil(dstBounds.height() / (float)scaleFactorY)); + auto rtc = two_pass_gaussian(context, std::move(srcView), srcColorType, srcAlphaType, + colorSpace, &localSrcBounds, scaledDstBounds, sigmaX, sigmaY, + radiusX, radiusY, mode, SkBackingFit::kApprox); + if (!rtc) { + return nullptr; + } + return reexpand(context, std::move(rtc), localSrcBounds, scaleFactorX, scaleFactorY, + dstBounds.size(), std::move(colorSpace), fit); +} + +} + +#endif diff --git a/chromium/third_party/skia/src/core/SkLocalMatrixImageFilter.cpp b/chromium/third_party/skia/src/core/SkLocalMatrixImageFilter.cpp index bb6dc3f13fa..19ea376deb3 100644 --- a/chromium/third_party/skia/src/core/SkLocalMatrixImageFilter.cpp +++ b/chromium/third_party/skia/src/core/SkLocalMatrixImageFilter.cpp @@ -53,3 +53,15 @@ SkIRect SkLocalMatrixImageFilter::onFilterBounds(const SkIRect& src, const SkMat MapDirection dir, const SkIRect* inputRect) const { return this->getInput(0)->filterBounds(src, SkMatrix::Concat(ctm, fLocalM), dir, inputRect); } + +SkRect SkLocalMatrixImageFilter::computeFastBounds(const SkRect& bounds) const { + // In order to match the behavior of onFilterBounds, we map 'bounds' by the inverse of our + // local matrix, pass that to our child, and then map the result by our local matrix. + SkMatrix localInv; + if (!fLocalM.invert(&localInv)) { + return this->getInput(0)->computeFastBounds(bounds); + } + + SkRect localBounds = localInv.mapRect(bounds); + return fLocalM.mapRect(this->getInput(0)->computeFastBounds(localBounds)); +} diff --git a/chromium/third_party/skia/src/core/SkLocalMatrixImageFilter.h b/chromium/third_party/skia/src/core/SkLocalMatrixImageFilter.h index f20773ca0a5..2a8db26155a 100644 --- a/chromium/third_party/skia/src/core/SkLocalMatrixImageFilter.h +++ b/chromium/third_party/skia/src/core/SkLocalMatrixImageFilter.h @@ -19,6 +19,8 @@ class SkLocalMatrixImageFilter : public SkImageFilter_Base { public: static sk_sp<SkImageFilter> Make(const SkMatrix& localM, sk_sp<SkImageFilter> input); + SkRect computeFastBounds(const SkRect&) const override; + protected: void flatten(SkWriteBuffer&) const override; sk_sp<SkSpecialImage> onFilterImage(const Context&, SkIPoint* offset) const override; diff --git a/chromium/third_party/skia/src/core/SkMaskFilter.cpp b/chromium/third_party/skia/src/core/SkMaskFilter.cpp index c840a68a032..222a5943e1c 100644 --- a/chromium/third_party/skia/src/core/SkMaskFilter.cpp +++ b/chromium/third_party/skia/src/core/SkMaskFilter.cpp @@ -255,7 +255,7 @@ bool SkMaskFilterBase::filterPath(const SkPath& devPath, const SkMatrix& matrix, case kUnimplemented_FilterReturn: SkASSERT(nullptr == patch.fMask.fImage); - // fall through + // fall out break; } } @@ -335,7 +335,7 @@ bool SkMaskFilterBase::canFilterMaskGPU(const GrStyledShape& shape, bool SkMaskFilterBase::directFilterMaskGPU(GrRecordingContext*, GrRenderTargetContext*, GrPaint&&, - const GrClip&, + const GrClip*, const SkMatrix& viewMatrix, const GrStyledShape&) const { return false; diff --git a/chromium/third_party/skia/src/core/SkMaskFilterBase.h b/chromium/third_party/skia/src/core/SkMaskFilterBase.h index 1d8ecb157c2..5ac10de24a6 100644 --- a/chromium/third_party/skia/src/core/SkMaskFilterBase.h +++ b/chromium/third_party/skia/src/core/SkMaskFilterBase.h @@ -116,7 +116,7 @@ public: virtual bool directFilterMaskGPU(GrRecordingContext*, GrRenderTargetContext*, GrPaint&& paint, - const GrClip&, + const GrClip*, const SkMatrix& viewMatrix, const GrStyledShape& shape) const; diff --git a/chromium/third_party/skia/src/core/SkMatrixProvider.h b/chromium/third_party/skia/src/core/SkMatrixProvider.h index e4e902b26c3..2033ec2aa82 100644 --- a/chromium/third_party/skia/src/core/SkMatrixProvider.h +++ b/chromium/third_party/skia/src/core/SkMatrixProvider.h @@ -51,35 +51,25 @@ private: const SkMatrixProvider& fParent; }; -class SkPostConcatMatrixProvider : public SkMatrixProvider { +class SkPostTranslateMatrixProvider : public SkMatrixProvider { public: - SkPostConcatMatrixProvider(const SkMatrixProvider& parent, const SkMatrix& postMatrix) -#if defined(SK_SUPPORT_LEGACY_MATRIX44) - : SkMatrixProvider(SkMatrix::Concat(postMatrix, parent.localToDevice())) -#else - : SkMatrixProvider(SkM44(postMatrix) * parent.localToDevice44()) -#endif - , fParent(parent) - , fPostMatrix(postMatrix) {} + SkPostTranslateMatrixProvider(const SkMatrixProvider& parent, SkScalar dx, SkScalar dy) + : SkMatrixProvider(SkM44::Translate(dx, dy) * parent.localToDevice44()) + , fParent(parent) {} - // Assume that the post-matrix doesn't apply to any marked matrices + // Assume that the post-translation doesn't apply to any marked matrices bool getLocalToMarker(uint32_t id, SkM44* localToMarker) const override { return fParent.getLocalToMarker(id, localToMarker); } private: const SkMatrixProvider& fParent; - const SkMatrix fPostMatrix; }; class SkPreConcatMatrixProvider : public SkMatrixProvider { public: SkPreConcatMatrixProvider(const SkMatrixProvider& parent, const SkMatrix& preMatrix) -#if defined(SK_SUPPORT_LEGACY_MATRIX44) - : SkMatrixProvider(SkMatrix::Concat(parent.localToDevice(), preMatrix)) -#else : SkMatrixProvider(parent.localToDevice44() * SkM44(preMatrix)) -#endif , fParent(parent) , fPreMatrix(preMatrix) {} diff --git a/chromium/third_party/skia/src/core/SkMipMap.h b/chromium/third_party/skia/src/core/SkMipMap.h index 9aa43d265e3..89312b9dec5 100644 --- a/chromium/third_party/skia/src/core/SkMipMap.h +++ b/chromium/third_party/skia/src/core/SkMipMap.h @@ -36,6 +36,7 @@ public: // This does not include the base mipmap level that the user provided when // creating the SkMipMap. static int ComputeLevelCount(int baseWidth, int baseHeight); + static int ComputeLevelCount(SkISize s) { return ComputeLevelCount(s.width(), s.height()); } // Determines the size of a given mipmap level. // |level| is an index into the generated mipmap levels. It does not include diff --git a/chromium/third_party/skia/src/core/SkModeColorFilter.cpp b/chromium/third_party/skia/src/core/SkModeColorFilter.cpp index 1927c0f9dca..721cc468073 100644 --- a/chromium/third_party/skia/src/core/SkModeColorFilter.cpp +++ b/chromium/third_party/skia/src/core/SkModeColorFilter.cpp @@ -38,12 +38,13 @@ bool SkModeColorFilter::onAsAColorMode(SkColor* color, SkBlendMode* mode) const return true; } -uint32_t SkModeColorFilter::getFlags() const { +uint32_t SkModeColorFilter::onGetFlags() const { uint32_t flags = 0; switch (fMode) { case SkBlendMode::kDst: //!< [Da, Dc] case SkBlendMode::kSrcATop: //!< [Da, Sc * Da + (1 - Sa) * Dc] flags |= kAlphaUnchanged_Flag; + break; default: break; } @@ -93,7 +94,8 @@ std::unique_ptr<GrFragmentProcessor> SkModeColorFilter::asFragmentProcessor( return nullptr; } - auto constFP = GrConstColorProcessor::Make(SkColorToPMColor4f(fColor, dstColorInfo), + auto constFP = GrConstColorProcessor::Make(/*inputFP=*/nullptr, + SkColorToPMColor4f(fColor, dstColorInfo), GrConstColorProcessor::InputMode::kIgnore); auto fp = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(constFP), fMode); if (!fp) { diff --git a/chromium/third_party/skia/src/core/SkModeColorFilter.h b/chromium/third_party/skia/src/core/SkModeColorFilter.h index b1a48f6d2ca..e2aa599971d 100644 --- a/chromium/third_party/skia/src/core/SkModeColorFilter.h +++ b/chromium/third_party/skia/src/core/SkModeColorFilter.h @@ -8,22 +8,23 @@ #ifndef SkModeColorFilter_DEFINED #define SkModeColorFilter_DEFINED -#include "include/core/SkColorFilter.h" -#include "include/core/SkFlattenable.h" +#include "src/core/SkColorFilterBase.h" -class SkModeColorFilter : public SkColorFilter { +class SkModeColorFilter : public SkColorFilterBase { public: static sk_sp<SkColorFilter> Make(SkColor color, SkBlendMode mode) { return sk_sp<SkColorFilter>(new SkModeColorFilter(color, mode)); } - uint32_t getFlags() const override; + uint32_t onGetFlags() const override; #if SK_SUPPORT_GPU std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(GrRecordingContext*, const GrColorInfo&) const override; #endif + SK_FLATTENABLE_HOOKS(SkModeColorFilter) + protected: SkModeColorFilter(SkColor color, SkBlendMode mode); @@ -35,14 +36,12 @@ protected: SkColorSpace*, skvm::Uniforms*, SkArenaAlloc*) const override; private: - SK_FLATTENABLE_HOOKS(SkModeColorFilter) - SkColor fColor; SkBlendMode fMode; friend class SkColorFilter; - typedef SkColorFilter INHERITED; + typedef SkColorFilterBase INHERITED; }; #endif diff --git a/chromium/third_party/skia/src/core/SkOSFile.h b/chromium/third_party/skia/src/core/SkOSFile.h index 082f7b8f108..d96f11fc581 100644 --- a/chromium/third_party/skia/src/core/SkOSFile.h +++ b/chromium/third_party/skia/src/core/SkOSFile.h @@ -80,16 +80,17 @@ class SkOSFile { public: class Iter { public: - Iter(); - Iter(const char path[], const char suffix[] = nullptr); - ~Iter(); + // SPI for module use. + SK_SPI Iter(); + SK_SPI Iter(const char path[], const char suffix[] = nullptr); + SK_SPI ~Iter(); - void reset(const char path[], const char suffix[] = nullptr); + SK_SPI void reset(const char path[], const char suffix[] = nullptr); /** If getDir is true, only returns directories. Results are undefined if true and false calls are interleaved on a single iterator. */ - bool next(SkString* name, bool getDir = false); + SK_SPI bool next(SkString* name, bool getDir = false); static const size_t kStorageSize = 40; private: diff --git a/chromium/third_party/skia/src/core/SkOpts.cpp b/chromium/third_party/skia/src/core/SkOpts.cpp index 08f758e552b..b847c3022a5 100644 --- a/chromium/third_party/skia/src/core/SkOpts.cpp +++ b/chromium/third_party/skia/src/core/SkOpts.cpp @@ -107,7 +107,6 @@ namespace SkOpts { // Each Init_foo() is defined in src/opts/SkOpts_foo.cpp. void Init_ssse3(); - void Init_sse41(); void Init_sse42(); void Init_avx(); void Init_hsw(); @@ -121,10 +120,6 @@ namespace SkOpts { if (SkCpu::Supports(SkCpu::SSSE3)) { Init_ssse3(); } #endif - #if SK_CPU_SSE_LEVEL < SK_CPU_SSE_LEVEL_SSE41 - if (SkCpu::Supports(SkCpu::SSE41)) { Init_sse41(); } - #endif - #if SK_CPU_SSE_LEVEL < SK_CPU_SSE_LEVEL_SSE42 if (SkCpu::Supports(SkCpu::SSE42)) { Init_sse42(); } #endif diff --git a/chromium/third_party/skia/src/core/SkOpts.h b/chromium/third_party/skia/src/core/SkOpts.h index 5b8e7739d90..04aee49b4ae 100644 --- a/chromium/third_party/skia/src/core/SkOpts.h +++ b/chromium/third_party/skia/src/core/SkOpts.h @@ -9,6 +9,7 @@ #define SkOpts_DEFINED #include "include/core/SkTypes.h" +#include "include/private/SkOpts_spi.h" #include "src/core/SkRasterPipeline.h" #include "src/core/SkXfermodePriv.h" @@ -55,8 +56,6 @@ namespace SkOpts { extern float (*cubic_solver)(float, float, float, float); - // The fastest high quality 32-bit hash we can provide on this platform. - extern uint32_t (*hash_fn)(const void*, size_t, uint32_t seed); static inline uint32_t hash(const void* data, size_t bytes, uint32_t seed=0) { return hash_fn(data, bytes, seed); } diff --git a/chromium/third_party/skia/src/core/SkOpts_skx.cpp b/chromium/third_party/skia/src/core/SkOpts_skx.cpp deleted file mode 100644 index 9341406bc2c..00000000000 --- a/chromium/third_party/skia/src/core/SkOpts_skx.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2020 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "src/core/SkOpts.h" - -#if defined(SK_CPU_X86) - - // Turn on SKX feature set. - #if defined(__clang__) - #pragma clang attribute push(__attribute__((target("avx512f,avx512dq,avx512cd,avx512bw,avx512vl"))), apply_to=function) - #elif defined(__GNUC__) - #pragma GCC push_options - #pragma GCC target("avx512f,avx512dq,avx512cd,avx512bw,avx512vl") - #endif - - // Let our code in *_opts.h know we want SKX features. - #undef SK_CPU_SSE_LEVEL - #define SK_CPU_SSE_LEVEL SK_CPU_SSE_LEVEL_SKX - - #if defined(__clang__) && defined(_MSC_VER) - // clang-cl's immintrin.h is bizarrely annoying, not including the - // various foointrin.h unless the __FOO__ flag is also defined (i.e. - // you used command-line flags to set the features instead of attributes). - // MSVC itself doesn't work this way, nor does non-_MSC_VER clang. :/ - #define __SSE__ 1 - #define __SSE2__ 1 - #define __SSE3__ 1 - #define __SSSE3__ 1 - #define __SSE4_1__ 1 - #define __SSE4_2__ 1 - #define __AVX__ 1 - #define __F16C__ 1 - #define __AVX2__ 1 - #define __FMA__ 1 - #define __AVX512F__ 1 - #define __AVX512DQ__ 1 - #define __AVX512CD__ 1 - #define __AVX512BW__ 1 - #define __AVX512VL__ 1 - #endif - - #define SK_OPTS_NS skx - #include "src/opts/SkBlitRow_opts.h" - #include "src/opts/SkVM_opts.h" - - namespace SkOpts { - void Init_skx() { - blit_row_s32a_opaque = SK_OPTS_NS::blit_row_s32a_opaque; - interpret_skvm = SK_OPTS_NS::interpret_skvm; - } - } - - #if defined(__clang__) - #pragma clang attribute pop - #elif defined(__GNUC__) - #pragma GCC pop_options - #endif - -#endif//defined(SK_CPU_X86) diff --git a/chromium/third_party/skia/src/core/SkOverdrawCanvas.cpp b/chromium/third_party/skia/src/core/SkOverdrawCanvas.cpp index 0297a973404..f606ac7dcb8 100644 --- a/chromium/third_party/skia/src/core/SkOverdrawCanvas.cpp +++ b/chromium/third_party/skia/src/core/SkOverdrawCanvas.cpp @@ -50,7 +50,7 @@ public: fOverdrawCanvas{overdrawCanvas}, fPainter{props, kN32_SkColorType, nullptr, SkStrikeCache::GlobalStrikeCache()} {} - void paintPaths(SkDrawableGlyphBuffer*, SkScalar scale, const SkPaint& paint) const override {} + void paintPaths(SkDrawableGlyphBuffer*, SkScalar, SkPoint, const SkPaint&) const override {} void paintMasks(SkDrawableGlyphBuffer* drawables, const SkPaint& paint) const override { for (auto t : drawables->drawable()) { diff --git a/chromium/third_party/skia/src/core/SkPaint.cpp b/chromium/third_party/skia/src/core/SkPaint.cpp index f294dbe4a09..2451fcefe6b 100644 --- a/chromium/third_party/skia/src/core/SkPaint.cpp +++ b/chromium/third_party/skia/src/core/SkPaint.cpp @@ -7,7 +7,6 @@ #include "include/core/SkPaint.h" -#include "include/core/SkColorFilter.h" #include "include/core/SkData.h" #include "include/core/SkGraphics.h" #include "include/core/SkImageFilter.h" @@ -19,6 +18,7 @@ #include "include/core/SkTypeface.h" #include "include/private/SkMutex.h" #include "include/private/SkTo.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkColorSpacePriv.h" #include "src/core/SkColorSpaceXformSteps.h" #include "src/core/SkDraw.h" @@ -109,6 +109,10 @@ void SkPaint::setStyle(Style style) { } } +void SkPaint::setStroke(bool isStroke) { + fBitfields.fStyle = isStroke ? kStroke_Style : kFill_Style; +} + void SkPaint::setColor(SkColor color) { fColor4f = SkColor4f::FromColor(color); } @@ -513,7 +517,7 @@ const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc, // return true if the filter exists, and may affect alpha static bool affects_alpha(const SkColorFilter* cf) { - return cf && !(cf->getFlags() & SkColorFilter::kAlphaUnchanged_Flag); + return cf && !as_CFB(cf)->isAlphaUnchanged(); } // return true if the filter exists, and may affect alpha diff --git a/chromium/third_party/skia/src/core/SkPaintPriv.cpp b/chromium/third_party/skia/src/core/SkPaintPriv.cpp index 4bf00023586..7ad907ba5b8 100644 --- a/chromium/third_party/skia/src/core/SkPaintPriv.cpp +++ b/chromium/third_party/skia/src/core/SkPaintPriv.cpp @@ -5,8 +5,8 @@ * found in the LICENSE file. */ -#include "include/core/SkColorFilter.h" #include "include/core/SkPaint.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkColorSpacePriv.h" #include "src/core/SkPaintPriv.h" #include "src/core/SkXfermodePriv.h" @@ -15,7 +15,7 @@ static bool changes_alpha(const SkPaint& paint) { SkColorFilter* cf = paint.getColorFilter(); - return cf && !(cf->getFlags() & SkColorFilter::kAlphaUnchanged_Flag); + return cf && !(as_CFB(cf)->getFlags() & SkColorFilterBase::kAlphaUnchanged_Flag); } bool SkPaintPriv::Overwrites(const SkPaint* paint, ShaderOverrideOpacity overrideOpacity) { diff --git a/chromium/third_party/skia/src/core/SkPath.cpp b/chromium/third_party/skia/src/core/SkPath.cpp index 09c061de51a..95bb11b57c4 100644 --- a/chromium/third_party/skia/src/core/SkPath.cpp +++ b/chromium/third_party/skia/src/core/SkPath.cpp @@ -148,6 +148,15 @@ SkPath::SkPath() fIsVolatile = false; } +SkPath::SkPath(sk_sp<SkPathRef> pr, SkPathFillType ft, bool isVolatile) + : fPathRef(std::move(pr)) + , fLastMoveToIndex(INITIAL_LASTMOVETOINDEX_VALUE) + , fConvexity((uint8_t)SkPathConvexityType::kUnknown) + , fFirstDirection(SkPathPriv::kUnknown_FirstDirection) + , fFillType((unsigned)ft) + , fIsVolatile(isVolatile) +{} + void SkPath::resetFields() { //fPathRef is assumed to have been emptied by the caller. fLastMoveToIndex = INITIAL_LASTMOVETOINDEX_VALUE; @@ -1815,7 +1824,7 @@ SkPath::Verb SkPath::Iter::next(SkPoint ptsParam[4]) { break; case kConic_Verb: fConicWeights += 1; - // fall-through + [[fallthrough]]; case kQuad_Verb: pts[0] = this->cons_moveTo(); memcpy(&pts[1], srcPts, 2 * sizeof(SkPoint)); @@ -2351,7 +2360,7 @@ void ContourIter::next() { break; case SkPath::kConic_Verb: fCurrConicWeight += 1; - // fall-through + [[fallthrough]]; case SkPath::kQuad_Verb: ptCount += 2; break; @@ -3348,6 +3357,7 @@ bool SkPathPriv::IsRectContour(const SkPath& path, bool allowPartial, int* currV savePts = pts; autoClose = true; insertClose = false; + [[fallthrough]]; case SkPath::kLine_Verb: { if (SkPath::kClose_Verb != verb) { lastPt = pts; diff --git a/chromium/third_party/skia/src/core/SkPathBuilder.cpp b/chromium/third_party/skia/src/core/SkPathBuilder.cpp new file mode 100644 index 00000000000..d5b21472681 --- /dev/null +++ b/chromium/third_party/skia/src/core/SkPathBuilder.cpp @@ -0,0 +1,358 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkPathBuilder.h" +#include "include/core/SkRRect.h" +#include "include/private/SkPathRef.h" +#include "include/private/SkSafe32.h" + +SkPathBuilder::SkPathBuilder() { + this->reset(); +} + +SkPathBuilder::~SkPathBuilder() { +} + +SkPathBuilder& SkPathBuilder::reset() { + fPts.reset(); + fVerbs.reset(); + fConicWeights.reset(); + fFillType = SkPathFillType::kWinding; + fIsVolatile = false; + + // these are internal state + + fSegmentMask = 0; + fLastMovePoint = {0, 0}; + fNeedsMoveVerb = true; + + return *this; +} + +void SkPathBuilder::incReserve(int extraPtCount, int extraVbCount) { + fPts.setReserve( Sk32_sat_add(fPts.count(), extraPtCount)); + fVerbs.setReserve(Sk32_sat_add(fVerbs.count(), extraVbCount)); +} + +/* + * Some old behavior in SkPath -- should we keep it? + * + * After each edit (i.e. adding a verb) + this->setConvexityType(SkPathConvexityType::kUnknown); + this->setFirstDirection(SkPathPriv::kUnknown_FirstDirection); + */ + +SkPathBuilder& SkPathBuilder::moveTo(SkPoint pt) { + fPts.push_back(pt); + fVerbs.push_back((uint8_t)SkPathVerb::kMove); + + fLastMovePoint = pt; + fNeedsMoveVerb = false; + return *this; +} + +SkPathBuilder& SkPathBuilder::lineTo(SkPoint pt) { + this->ensureMove(); + + fPts.push_back(pt); + fVerbs.push_back((uint8_t)SkPathVerb::kLine); + + fSegmentMask |= kLine_SkPathSegmentMask; + return *this; +} + +SkPathBuilder& SkPathBuilder::quadTo(SkPoint pt1, SkPoint pt2) { + this->ensureMove(); + + SkPoint* p = fPts.append(2); + p[0] = pt1; + p[1] = pt2; + fVerbs.push_back((uint8_t)SkPathVerb::kQuad); + + fSegmentMask |= kQuad_SkPathSegmentMask; + return *this; +} + +SkPathBuilder& SkPathBuilder::conicTo(SkPoint pt1, SkPoint pt2, SkScalar w) { + this->ensureMove(); + + SkPoint* p = fPts.append(2); + p[0] = pt1; + p[1] = pt2; + fVerbs.push_back((uint8_t)SkPathVerb::kConic); + fConicWeights.push_back(w); + + fSegmentMask |= kConic_SkPathSegmentMask; + return *this; +} + +SkPathBuilder& SkPathBuilder::cubicTo(SkPoint pt1, SkPoint pt2, SkPoint pt3) { + this->ensureMove(); + + SkPoint* p = fPts.append(3); + p[0] = pt1; + p[1] = pt2; + p[2] = pt3; + fVerbs.push_back((uint8_t)SkPathVerb::kCubic); + + fSegmentMask |= kCubic_SkPathSegmentMask; + return *this; +} + +SkPathBuilder& SkPathBuilder::close() { + this->ensureMove(); + + fVerbs.push_back((uint8_t)SkPathVerb::kClose); + + // fLastMovePoint stays where it is -- the previous moveTo + fNeedsMoveVerb = true; + return *this; +} + +SkPath SkPathBuilder::snapshot() { + return SkPath(sk_sp<SkPathRef>(new SkPathRef(fPts, fVerbs, fConicWeights, fSegmentMask)), + fFillType, fIsVolatile); +} + +SkPath SkPathBuilder::detach() { + auto path = SkPath(sk_sp<SkPathRef>(new SkPathRef(std::move(fPts), + std::move(fVerbs), + std::move(fConicWeights), + fSegmentMask)), + fFillType, fIsVolatile); + this->reset(); + return path; +} + +/////////////////////////////////////////////////////////////////////////////////////////// + +namespace { + template <unsigned N> class PointIterator { + public: + PointIterator(SkPathDirection dir, unsigned startIndex) + : fCurrent(startIndex % N) + , fAdvance(dir == SkPathDirection::kCW ? 1 : N - 1) + {} + + const SkPoint& current() const { + SkASSERT(fCurrent < N); + return fPts[fCurrent]; + } + + const SkPoint& next() { + fCurrent = (fCurrent + fAdvance) % N; + return this->current(); + } + + protected: + SkPoint fPts[N]; + + private: + unsigned fCurrent; + unsigned fAdvance; + }; + + class RectPointIterator : public PointIterator<4> { + public: + RectPointIterator(const SkRect& rect, SkPathDirection dir, unsigned startIndex) + : PointIterator(dir, startIndex) { + + fPts[0] = SkPoint::Make(rect.fLeft, rect.fTop); + fPts[1] = SkPoint::Make(rect.fRight, rect.fTop); + fPts[2] = SkPoint::Make(rect.fRight, rect.fBottom); + fPts[3] = SkPoint::Make(rect.fLeft, rect.fBottom); + } + }; + + class OvalPointIterator : public PointIterator<4> { + public: + OvalPointIterator(const SkRect& oval, SkPathDirection dir, unsigned startIndex) + : PointIterator(dir, startIndex) { + + const SkScalar cx = oval.centerX(); + const SkScalar cy = oval.centerY(); + + fPts[0] = SkPoint::Make(cx, oval.fTop); + fPts[1] = SkPoint::Make(oval.fRight, cy); + fPts[2] = SkPoint::Make(cx, oval.fBottom); + fPts[3] = SkPoint::Make(oval.fLeft, cy); + } + }; + + class RRectPointIterator : public PointIterator<8> { + public: + RRectPointIterator(const SkRRect& rrect, SkPathDirection dir, unsigned startIndex) + : PointIterator(dir, startIndex) + { + const SkRect& bounds = rrect.getBounds(); + const SkScalar L = bounds.fLeft; + const SkScalar T = bounds.fTop; + const SkScalar R = bounds.fRight; + const SkScalar B = bounds.fBottom; + + fPts[0] = SkPoint::Make(L + rrect.radii(SkRRect::kUpperLeft_Corner).fX, T); + fPts[1] = SkPoint::Make(R - rrect.radii(SkRRect::kUpperRight_Corner).fX, T); + fPts[2] = SkPoint::Make(R, T + rrect.radii(SkRRect::kUpperRight_Corner).fY); + fPts[3] = SkPoint::Make(R, B - rrect.radii(SkRRect::kLowerRight_Corner).fY); + fPts[4] = SkPoint::Make(R - rrect.radii(SkRRect::kLowerRight_Corner).fX, B); + fPts[5] = SkPoint::Make(L + rrect.radii(SkRRect::kLowerLeft_Corner).fX, B); + fPts[6] = SkPoint::Make(L, B - rrect.radii(SkRRect::kLowerLeft_Corner).fY); + fPts[7] = SkPoint::Make(L, T + rrect.radii(SkRRect::kUpperLeft_Corner).fY); + } + }; +} // anonymous namespace + + +SkPathBuilder& SkPathBuilder::addRect(const SkRect& rect, SkPathDirection dir, unsigned index) { + const int kPts = 4; // moveTo + 3 lines + const int kVerbs = 5; // moveTo + 3 lines + close + this->incReserve(kPts, kVerbs); + + RectPointIterator iter(rect, dir, index); + + this->moveTo(iter.current()); + this->lineTo(iter.next()); + this->lineTo(iter.next()); + this->lineTo(iter.next()); + return this->close(); +} + +SkPathBuilder& SkPathBuilder::addOval(const SkRect& oval, SkPathDirection dir, unsigned index) { + const int kPts = 9; // moveTo + 4 conics(2 pts each) + const int kVerbs = 6; // moveTo + 4 conics + close + this->incReserve(kPts, kVerbs); + + OvalPointIterator ovalIter(oval, dir, index); + RectPointIterator rectIter(oval, dir, index + (dir == SkPathDirection::kCW ? 0 : 1)); + + // The corner iterator pts are tracking "behind" the oval/radii pts. + + this->moveTo(ovalIter.current()); + for (unsigned i = 0; i < 4; ++i) { + this->conicTo(rectIter.next(), ovalIter.next(), SK_ScalarRoot2Over2); + } + return this->close(); +} + +SkPathBuilder& SkPathBuilder::addRRect(const SkRRect& rrect, SkPathDirection dir, unsigned index) { + const SkRect& bounds = rrect.getBounds(); + + if (rrect.isRect() || rrect.isEmpty()) { + // degenerate(rect) => radii points are collapsing + this->addRect(bounds, dir, (index + 1) / 2); + } else if (rrect.isOval()) { + // degenerate(oval) => line points are collapsing + this->addOval(bounds, dir, index / 2); + } else { + // we start with a conic on odd indices when moving CW vs. even indices when moving CCW + const bool startsWithConic = ((index & 1) == (dir == SkPathDirection::kCW)); + const SkScalar weight = SK_ScalarRoot2Over2; + + const int kVerbs = startsWithConic + ? 9 // moveTo + 4x conicTo + 3x lineTo + close + : 10; // moveTo + 4x lineTo + 4x conicTo + close + this->incReserve(kVerbs); + + RRectPointIterator rrectIter(rrect, dir, index); + // Corner iterator indices follow the collapsed radii model, + // adjusted such that the start pt is "behind" the radii start pt. + const unsigned rectStartIndex = index / 2 + (dir == SkPathDirection::kCW ? 0 : 1); + RectPointIterator rectIter(bounds, dir, rectStartIndex); + + this->moveTo(rrectIter.current()); + if (startsWithConic) { + for (unsigned i = 0; i < 3; ++i) { + this->conicTo(rectIter.next(), rrectIter.next(), weight); + this->lineTo(rrectIter.next()); + } + this->conicTo(rectIter.next(), rrectIter.next(), weight); + // final lineTo handled by close(). + } else { + for (unsigned i = 0; i < 4; ++i) { + this->lineTo(rrectIter.next()); + this->conicTo(rectIter.next(), rrectIter.next(), weight); + } + } + this->close(); + } + return *this; +} + +////////////////////////////////////////////////////////////////////////////////////////////////// + +struct PathInfo { + bool valid; + int points, weights; + unsigned segmentMask; +}; + +static PathInfo validate_verbs(const uint8_t vbs[], int verbCount) { + PathInfo info = {false, 0, 0, 0}; + + bool needMove = true; + bool invalid = false; + for (int i = 0; i < verbCount; ++i) { + switch ((SkPathVerb)vbs[i]) { + case SkPathVerb::kMove: + needMove = false; + info.points += 1; + break; + case SkPathVerb::kLine: + invalid |= needMove; + info.segmentMask |= kLine_SkPathSegmentMask; + info.points += 1; + break; + case SkPathVerb::kQuad: + invalid |= needMove; + info.segmentMask |= kQuad_SkPathSegmentMask; + info.points += 2; + break; + case SkPathVerb::kConic: + invalid |= needMove; + info.segmentMask |= kConic_SkPathSegmentMask; + info.points += 2; + info.weights += 1; + break; + case SkPathVerb::kCubic: + invalid |= needMove; + info.segmentMask |= kCubic_SkPathSegmentMask; + info.points += 3; + break; + case SkPathVerb::kClose: + invalid |= needMove; + needMove = true; + break; + default: + invalid = true; + break; + } + } + info.valid = !invalid; + return info; +} + +SkPath SkPathBuilder::Make(const SkPoint pts[], int pointCount, + const uint8_t vbs[], int verbCount, + const SkScalar ws[], int wCount, + SkPathFillType ft, bool isVolatile) { + if (verbCount <= 0) { + return SkPath(); + } + + const auto info = validate_verbs(vbs, verbCount); + if (!info.valid || info.points > pointCount || info.weights > wCount) { + SkDEBUGFAIL("invalid verbs and number of points/weights"); + return SkPath(); + } + + return SkPath(sk_sp<SkPathRef>(new SkPathRef(SkTDArray<SkPoint>(pts, info.points), + SkTDArray<uint8_t>(vbs, verbCount), + SkTDArray<SkScalar>(ws, info.weights), + info.segmentMask)), + ft, isVolatile); +} + diff --git a/chromium/third_party/skia/src/core/SkPathRef.cpp b/chromium/third_party/skia/src/core/SkPathRef.cpp index 68c8970b07a..dca2b329d89 100644 --- a/chromium/third_party/skia/src/core/SkPathRef.cpp +++ b/chromium/third_party/skia/src/core/SkPathRef.cpp @@ -394,10 +394,12 @@ SkPoint* SkPathRef::growForRepeatedVerb(int /*SkPath::Verb*/ verb, break; case SkPath::kDone_Verb: SkDEBUGFAIL("growForRepeatedVerb called for kDone"); - // fall through + pCnt = 0; + break; default: SkDEBUGFAIL("default should not be reached"); pCnt = 0; + break; } fBoundsIsDirty = true; // this also invalidates fIsFinite @@ -444,10 +446,12 @@ SkPoint* SkPathRef::growForVerb(int /* SkPath::Verb*/ verb, SkScalar weight) { break; case SkPath::kDone_Verb: SkDEBUGFAIL("growForVerb called for kDone"); - // fall through + pCnt = 0; + break; default: SkDEBUGFAIL("default is not reached"); pCnt = 0; + break; } fSegmentMask |= mask; @@ -596,7 +600,7 @@ uint8_t SkPathRef::Iter::next(SkPoint pts[4]) { break; case SkPath::kConic_Verb: fConicWeights += 1; - // fall-through + [[fallthrough]]; case SkPath::kQuad_Verb: pts[0] = srcPts[-1]; pts[1] = srcPts[0]; diff --git a/chromium/third_party/skia/src/core/SkPath_serial.cpp b/chromium/third_party/skia/src/core/SkPath_serial.cpp index b1d85f451cd..694ce77315c 100644 --- a/chromium/third_party/skia/src/core/SkPath_serial.cpp +++ b/chromium/third_party/skia/src/core/SkPath_serial.cpp @@ -211,7 +211,7 @@ size_t SkPath::readFromMemory_EQ4Or5(const void* storage, size_t length) { case SerializationType::kRRect: return this->readAsRRect(storage, length); case SerializationType::kGeneral: - break; // fall through + break; // fall out default: return 0; } diff --git a/chromium/third_party/skia/src/core/SkPicture.cpp b/chromium/third_party/skia/src/core/SkPicture.cpp index e041ba64f0c..dbfb7aa69cb 100644 --- a/chromium/third_party/skia/src/core/SkPicture.cpp +++ b/chromium/third_party/skia/src/core/SkPicture.cpp @@ -185,7 +185,7 @@ sk_sp<SkPicture> SkPicture::MakeFromStream(SkStream* stream, const SkDeserialPro } return procs.fPictureProc(data->data(), size, procs.fPictureCtx); } - default: // fall through to error return + default: // fall out to error return break; } return nullptr; diff --git a/chromium/third_party/skia/src/core/SkPictureData.cpp b/chromium/third_party/skia/src/core/SkPictureData.cpp index c4ae9a002ee..611c5f2b9f0 100644 --- a/chromium/third_party/skia/src/core/SkPictureData.cpp +++ b/chromium/third_party/skia/src/core/SkPictureData.cpp @@ -315,7 +315,12 @@ bool SkPictureData::parseStreamTag(SkStream* stream, case SK_PICT_TYPEFACE_TAG: { fTFPlayback.setCount(size); for (uint32_t i = 0; i < size; ++i) { - sk_sp<SkTypeface> tf(SkTypeface::MakeDeserialize(stream)); + sk_sp<SkTypeface> tf; + if (procs.fTypefaceProc) { + tf = procs.fTypefaceProc(&stream, sizeof(stream), procs.fTypefaceCtx); + } else { + tf = SkTypeface::MakeDeserialize(stream); + } if (!tf.get()) { // failed to deserialize // fTFPlayback asserts it never has a null, so we plop in // the default here. diff --git a/chromium/third_party/skia/src/core/SkPictureData.h b/chromium/third_party/skia/src/core/SkPictureData.h index 25c9a7acc4b..f820ca7a158 100644 --- a/chromium/third_party/skia/src/core/SkPictureData.h +++ b/chromium/third_party/skia/src/core/SkPictureData.h @@ -18,7 +18,6 @@ class SkData; class SkPictureRecord; -class SkReader32; struct SkSerialProcs; class SkStream; class SkWStream; diff --git a/chromium/third_party/skia/src/core/SkPictureFlat.h b/chromium/third_party/skia/src/core/SkPictureFlat.h index 2f551f20665..4bb87e7f0bf 100644 --- a/chromium/third_party/skia/src/core/SkPictureFlat.h +++ b/chromium/third_party/skia/src/core/SkPictureFlat.h @@ -132,8 +132,8 @@ enum SaveLayerRecFlatFlags { SAVELAYERREC_HAS_PAINT = 1 << 1, SAVELAYERREC_HAS_BACKDROP = 1 << 2, SAVELAYERREC_HAS_FLAGS = 1 << 3, - SAVELAYERREC_HAS_CLIPMASK = 1 << 4, - SAVELAYERREC_HAS_CLIPMATRIX = 1 << 5, + SAVELAYERREC_HAS_CLIPMASK_OBSOLETE = 1 << 4, // 6/13/2020 + SAVELAYERREC_HAS_CLIPMATRIX_OBSOLETE = 1 << 5, // 6/13/2020 }; enum SaveBehindFlatFlags { diff --git a/chromium/third_party/skia/src/core/SkPicturePlayback.cpp b/chromium/third_party/skia/src/core/SkPicturePlayback.cpp index 07ea8cd3bfe..9d7209297ae 100644 --- a/chromium/third_party/skia/src/core/SkPicturePlayback.cpp +++ b/chromium/third_party/skia/src/core/SkPicturePlayback.cpp @@ -601,8 +601,7 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, canvas->saveLayer(SkCanvas::SaveLayerRec(boundsPtr, paint, flags)); } break; case SAVE_LAYER_SAVELAYERREC: { - SkCanvas::SaveLayerRec rec(nullptr, nullptr, nullptr, nullptr, nullptr, 0); - SkMatrix clipMatrix; + SkCanvas::SaveLayerRec rec(nullptr, nullptr, nullptr, 0); const uint32_t flatFlags = reader->readInt(); SkRect bounds; if (flatFlags & SAVELAYERREC_HAS_BOUNDS) { @@ -620,12 +619,12 @@ void SkPicturePlayback::handleOp(SkReadBuffer* reader, if (flatFlags & SAVELAYERREC_HAS_FLAGS) { rec.fSaveLayerFlags = reader->readInt(); } - if (flatFlags & SAVELAYERREC_HAS_CLIPMASK) { - rec.fClipMask = fPictureData->getImage(reader); + if (flatFlags & SAVELAYERREC_HAS_CLIPMASK_OBSOLETE) { + (void)fPictureData->getImage(reader); } - if (flatFlags & SAVELAYERREC_HAS_CLIPMATRIX) { - reader->readMatrix(&clipMatrix); - rec.fClipMatrix = &clipMatrix; + if (flatFlags & SAVELAYERREC_HAS_CLIPMATRIX_OBSOLETE) { + SkMatrix clipMatrix_ignored; + reader->readMatrix(&clipMatrix_ignored); } BREAK_ON_READ_ERROR(reader); diff --git a/chromium/third_party/skia/src/core/SkPicturePriv.h b/chromium/third_party/skia/src/core/SkPicturePriv.h index 16f0e42e1c2..67cb931ba3e 100644 --- a/chromium/third_party/skia/src/core/SkPicturePriv.h +++ b/chromium/third_party/skia/src/core/SkPicturePriv.h @@ -76,6 +76,7 @@ public: // V73: Use SkColor4f in per-edge AA quad API // V74: MorphologyImageFilter internal radius is SkScaler // V75: SkVertices switched from unsafe use of SkReader32 to SkReadBuffer (like everything else) + // V76: Add filtering enum to ImageShader enum Version { kTileModeInBlurImageFilter_Version = 56, @@ -98,10 +99,11 @@ public: kEdgeAAQuadColor4f_Version = 73, kMorphologyTakesScalar_Version = 74, kVerticesUseReadBuffer_Version = 75, + kFilteringInImageShader_Version = 76, // Only SKPs within the min/current picture version range (inclusive) can be read. kMin_Version = kTileModeInBlurImageFilter_Version, - kCurrent_Version = kVerticesUseReadBuffer_Version + kCurrent_Version = kFilteringInImageShader_Version }; static_assert(kMin_Version <= 62, "Remove kFontAxes_bad from SkFontDescriptor.cpp"); diff --git a/chromium/third_party/skia/src/core/SkPictureRecord.cpp b/chromium/third_party/skia/src/core/SkPictureRecord.cpp index a9e053eb4a2..50ffb99079b 100644 --- a/chromium/third_party/skia/src/core/SkPictureRecord.cpp +++ b/chromium/third_party/skia/src/core/SkPictureRecord.cpp @@ -129,14 +129,6 @@ void SkPictureRecord::recordSaveLayer(const SaveLayerRec& rec) { flatFlags |= SAVELAYERREC_HAS_FLAGS; size += sizeof(uint32_t); } - if (rec.fClipMask) { - flatFlags |= SAVELAYERREC_HAS_CLIPMASK; - size += sizeof(uint32_t); // clip image index - } - if (rec.fClipMatrix) { - flatFlags |= SAVELAYERREC_HAS_CLIPMATRIX; - size += SkMatrixPriv::WriteToMemory(*rec.fClipMatrix, nullptr); - } const size_t initialOffset = this->addDraw(SAVE_LAYER_SAVELAYERREC, &size); this->addInt(flatFlags); @@ -155,12 +147,6 @@ void SkPictureRecord::recordSaveLayer(const SaveLayerRec& rec) { if (flatFlags & SAVELAYERREC_HAS_FLAGS) { this->addInt(rec.fSaveLayerFlags); } - if (flatFlags & SAVELAYERREC_HAS_CLIPMASK) { - this->addImage(rec.fClipMask); - } - if (flatFlags & SAVELAYERREC_HAS_CLIPMATRIX) { - this->addMatrix(*rec.fClipMatrix); - } this->validate(initialOffset, size); } @@ -241,11 +227,11 @@ void SkPictureRecord::didConcat44(const SkM44& m) { } void SkPictureRecord::didScale(SkScalar x, SkScalar y) { - this->didConcat(SkMatrix::MakeScale(x, y)); + this->didConcat(SkMatrix::Scale(x, y)); } void SkPictureRecord::didTranslate(SkScalar x, SkScalar y) { - this->didConcat(SkMatrix::MakeTrans(x, y)); + this->didConcat(SkMatrix::Translate(x, y)); } void SkPictureRecord::didConcat(const SkMatrix& matrix) { diff --git a/chromium/third_party/skia/src/core/SkPixmap.cpp b/chromium/third_party/skia/src/core/SkPixmap.cpp index 49ba4228718..0364a32fb86 100644 --- a/chromium/third_party/skia/src/core/SkPixmap.cpp +++ b/chromium/third_party/skia/src/core/SkPixmap.cpp @@ -243,6 +243,7 @@ bool SkPixmap::scalePixels(const SkPixmap& actualDst, SkFilterQuality quality) c SkTileMode::kClamp, SkTileMode::kClamp, &scale, + (SkImageShader::FilterEnum)quality, clampAsIfUnpremul); sk_sp<SkSurface> surface = SkSurface::MakeRasterDirect(dst.info(), diff --git a/chromium/third_party/skia/src/core/SkRasterPipeline.cpp b/chromium/third_party/skia/src/core/SkRasterPipeline.cpp index 2a4fbd0439f..f1bce40b41c 100644 --- a/chromium/third_party/skia/src/core/SkRasterPipeline.cpp +++ b/chromium/third_party/skia/src/core/SkRasterPipeline.cpp @@ -6,6 +6,7 @@ */ #include "include/private/SkImageInfoPriv.h" +#include "include/private/SkNx.h" #include "src/core/SkColorSpacePriv.h" #include "src/core/SkOpts.h" #include "src/core/SkRasterPipeline.h" diff --git a/chromium/third_party/skia/src/core/SkRasterPipeline.h b/chromium/third_party/skia/src/core/SkRasterPipeline.h index 316e8846293..4ec07de8709 100644 --- a/chromium/third_party/skia/src/core/SkRasterPipeline.h +++ b/chromium/third_party/skia/src/core/SkRasterPipeline.h @@ -14,7 +14,6 @@ #include "include/core/SkRefCnt.h" #include "include/core/SkTileMode.h" #include "include/core/SkTypes.h" -#include "include/private/SkNx.h" #include "include/private/SkTArray.h" #include "src/core/SkArenaAlloc.h" #include <functional> @@ -44,7 +43,6 @@ class SkData; M(unpremul) M(premul) M(premul_dst) \ M(force_opaque) M(force_opaque_dst) \ M(set_rgb) M(unbounded_set_rgb) M(swap_rb) M(swap_rb_dst) \ - M(from_srgb) M(to_srgb) \ M(black_color) M(white_color) \ M(uniform_color) M(unbounded_uniform_color) M(uniform_color_dst) \ M(seed_shader) M(dither) \ diff --git a/chromium/third_party/skia/src/core/SkRasterPipelineBlitter.cpp b/chromium/third_party/skia/src/core/SkRasterPipelineBlitter.cpp index 6db71082b5e..4fdcffd3b94 100644 --- a/chromium/third_party/skia/src/core/SkRasterPipelineBlitter.cpp +++ b/chromium/third_party/skia/src/core/SkRasterPipelineBlitter.cpp @@ -6,13 +6,13 @@ */ #include "include/core/SkColor.h" -#include "include/core/SkColorFilter.h" #include "include/core/SkPaint.h" #include "include/core/SkShader.h" #include "include/private/SkTo.h" #include "src/core/SkArenaAlloc.h" #include "src/core/SkBlendModePriv.h" #include "src/core/SkBlitter.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkColorSpacePriv.h" #include "src/core/SkColorSpaceXformSteps.h" #include "src/core/SkMatrixProvider.h" @@ -90,13 +90,7 @@ SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst, const SkMatrixProvider& matrixProvider, SkArenaAlloc* alloc, sk_sp<SkShader> clipShader) { - // For legacy to keep working, we need to sometimes still distinguish null dstCS from sRGB. -#if 0 - SkColorSpace* dstCS = dst.colorSpace() ? dst.colorSpace() - : sk_srgb_singleton(); -#else SkColorSpace* dstCS = dst.colorSpace(); -#endif SkColorType dstCT = dst.colorType(); SkColor4f paintColor = paint.getColor4f(); SkColorSpaceXformSteps(sk_srgb_singleton(), kUnpremul_SkAlphaType, @@ -129,8 +123,8 @@ SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst, std::move(clipShader)); } - // The shader has opted out of drawing anything. - return alloc->make<SkNullBlitter>(); + // The shader can't draw with SkRasterPipeline. + return nullptr; } SkBlitter* SkCreateRasterPipelineBlitter(const SkPixmap& dst, @@ -190,10 +184,12 @@ SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, SkStageRec rec = { colorPipeline, alloc, dst.colorType(), dst.colorSpace(), paint, nullptr, matrixProvider }; - colorFilter->appendStages(rec, is_opaque); - is_opaque = is_opaque && (colorFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag); + as_CFB(colorFilter)->appendStages(rec, is_opaque); + is_opaque = is_opaque + && (as_CFB(colorFilter)->getFlags() & SkColorFilterBase::kAlphaUnchanged_Flag); } +#if defined(SK_LATE_DITHER) // Not all formats make sense to dither (think, F16). We set their dither rate // to zero. We need to decide if we're going to dither now to keep is_constant accurate. if (paint.isDither()) { @@ -226,6 +222,39 @@ SkBlitter* SkRasterPipelineBlitter::Create(const SkPixmap& dst, // could disable it (for speed, by not adding the stage). } is_constant = is_constant && (blitter->fDitherRate == 0.0f); +#else + // Not all formats make sense to dither (think, F16). We set their dither rate + // to zero. We only dither non-constant shaders, so is_constant won't change here. + if (paint.isDither() && !is_constant) { + switch (dst.info().colorType()) { + case kARGB_4444_SkColorType: blitter->fDitherRate = 1/15.0f; break; + case kRGB_565_SkColorType: blitter->fDitherRate = 1/63.0f; break; + case kGray_8_SkColorType: + case kRGB_888x_SkColorType: + case kRGBA_8888_SkColorType: + case kBGRA_8888_SkColorType: blitter->fDitherRate = 1/255.0f; break; + case kRGB_101010x_SkColorType: + case kRGBA_1010102_SkColorType: + case kBGR_101010x_SkColorType: + case kBGRA_1010102_SkColorType: blitter->fDitherRate = 1/1023.0f; break; + + case kUnknown_SkColorType: + case kAlpha_8_SkColorType: + case kRGBA_F16_SkColorType: + case kRGBA_F16Norm_SkColorType: + case kRGBA_F32_SkColorType: + case kR8G8_unorm_SkColorType: + case kA16_float_SkColorType: + case kA16_unorm_SkColorType: + case kR16G16_float_SkColorType: + case kR16G16_unorm_SkColorType: + case kR16G16B16A16_unorm_SkColorType: blitter->fDitherRate = 0.0f; break; + } + if (blitter->fDitherRate > 0.0f) { + colorPipeline->append(SkRasterPipeline::dither, &blitter->fDitherRate); + } + } +#endif // We're logically done here. The code between here and return blitter is all optimization. @@ -303,9 +332,11 @@ void SkRasterPipelineBlitter::append_store(SkRasterPipeline* p) const { if (fDst.info().alphaType() == kUnpremul_SkAlphaType) { p->append(SkRasterPipeline::unpremul); } +#if defined(SK_LATE_DITHER) if (fDitherRate > 0.0f) { p->append(SkRasterPipeline::dither, &fDitherRate); } +#endif p->append_store(fDst.info().colorType(), &fDstPtr); } diff --git a/chromium/third_party/skia/src/core/SkReadBuffer.cpp b/chromium/third_party/skia/src/core/SkReadBuffer.cpp index c7e26df8d4d..61867776ca5 100644 --- a/chromium/third_party/skia/src/core/SkReadBuffer.cpp +++ b/chromium/third_party/skia/src/core/SkReadBuffer.cpp @@ -17,8 +17,6 @@ #include "src/core/SkReadBuffer.h" #include "src/core/SkSafeMath.h" -#ifndef SK_DISABLE_READBUFFER - namespace { // This generator intentionally should always fail on all attempts to get its pixels, // simulating a bad or empty codec stream. @@ -37,38 +35,18 @@ namespace { } // anonymous namespace - -SkReadBuffer::SkReadBuffer() { - fVersion = 0; - - fTFArray = nullptr; - fTFCount = 0; - - fFactoryArray = nullptr; - fFactoryCount = 0; -} - -SkReadBuffer::SkReadBuffer(const void* data, size_t size) { - fVersion = 0; - this->setMemory(data, size); - - fTFArray = nullptr; - fTFCount = 0; - - fFactoryArray = nullptr; - fFactoryCount = 0; -} - void SkReadBuffer::setMemory(const void* data, size_t size) { this->validate(IsPtrAlign4(data) && (SkAlign4(size) == size)); if (!fError) { - fReader.setMemory(data, size); + fBase = fCurr = (const char*)data; + fStop = fBase + size; } } + void SkReadBuffer::setInvalid() { if (!fError) { // When an error is found, send the read cursor to the end of the stream - fReader.skip(fReader.available()); + fCurr = fStop; fError = true; } } @@ -76,13 +54,13 @@ void SkReadBuffer::setInvalid() { const void* SkReadBuffer::skip(size_t size) { size_t inc = SkAlign4(size); this->validate(inc >= size); - const void* addr = fReader.peek(); - this->validate(IsPtrAlign4(addr) && fReader.isAvailable(inc)); + const void* addr = fCurr; + this->validate(IsPtrAlign4(addr) && this->isAvailable(inc)); if (fError) { return nullptr; } - fReader.skip(size); + fCurr += inc; return addr; } @@ -107,14 +85,22 @@ SkColor SkReadBuffer::readColor() { int32_t SkReadBuffer::readInt() { const size_t inc = sizeof(int32_t); - this->validate(IsPtrAlign4(fReader.peek()) && fReader.isAvailable(inc)); - return fError ? 0 : fReader.readInt(); + if (!this->validate(IsPtrAlign4(fCurr) && this->isAvailable(inc))) { + return 0; + } + int32_t value = *((const int32_t*)fCurr); + fCurr += inc; + return value; } SkScalar SkReadBuffer::readScalar() { const size_t inc = sizeof(SkScalar); - this->validate(IsPtrAlign4(fReader.peek()) && fReader.isAvailable(inc)); - return fError ? 0 : fReader.readScalar(); + if (!this->validate(IsPtrAlign4(fCurr) && this->isAvailable(inc))) { + return 0; + } + SkScalar value = *((const SkScalar*)fCurr); + fCurr += inc; + return value; } uint32_t SkReadBuffer::readUInt() { @@ -126,11 +112,11 @@ int32_t SkReadBuffer::read32() { } uint8_t SkReadBuffer::peekByte() { - if (fReader.available() <= 0) { + if (this->available() <= 0) { fError = true; return 0; } - return *((uint8_t*) fReader.peek()); + return *((uint8_t*)fCurr); } bool SkReadBuffer::readPad32(void* buffer, size_t bytes) { @@ -182,7 +168,7 @@ void SkReadBuffer::readPoint3(SkPoint3* point) { void SkReadBuffer::readMatrix(SkMatrix* matrix) { size_t size = 0; if (this->isValid()) { - size = SkMatrixPriv::ReadFromMemory(matrix, fReader.peek(), fReader.available()); + size = SkMatrixPriv::ReadFromMemory(matrix, fCurr, this->available()); (void)this->validate((SkAlign4(size) == size) && (0 != size)); } if (!this->isValid()) { @@ -204,15 +190,20 @@ void SkReadBuffer::readRect(SkRect* rect) { } void SkReadBuffer::readRRect(SkRRect* rrect) { - if (!this->validate(fReader.readRRect(rrect))) { - rrect->setEmpty(); + size_t size = 0; + if (!fError) { + size = rrect->readFromMemory(fCurr, this->available()); + if (!this->validate((SkAlign4(size) == size) && (0 != size))) { + rrect->setEmpty(); + } } + (void)this->skip(size); } void SkReadBuffer::readRegion(SkRegion* region) { size_t size = 0; if (!fError) { - size = region->readFromMemory(fReader.peek(), fReader.available()); + size = region->readFromMemory(fCurr, this->available()); if (!this->validate((SkAlign4(size) == size) && (0 != size))) { region->setEmpty(); } @@ -223,7 +214,7 @@ void SkReadBuffer::readRegion(SkRegion* region) { void SkReadBuffer::readPath(SkPath* path) { size_t size = 0; if (!fError) { - size = path->readFromMemory(fReader.peek(), fReader.available()); + size = path->readFromMemory(fCurr, this->available()); if (!this->validate((SkAlign4(size) == size) && (0 != size))) { path->reset(); } @@ -261,9 +252,18 @@ bool SkReadBuffer::readScalarArray(SkScalar* values, size_t size) { return this->readArray(values, size, sizeof(SkScalar)); } +const void* SkReadBuffer::skipByteArray(size_t* size) { + const uint32_t count = this->readUInt(); + const void* buf = this->skip(count); + if (size) { + *size = this->isValid() ? count : 0; + } + return buf; +} + sk_sp<SkData> SkReadBuffer::readByteArrayAsData() { size_t numBytes = this->getArrayCount(); - if (!this->validate(fReader.isAvailable(numBytes))) { + if (!this->validate(this->isAvailable(numBytes))) { return nullptr; } @@ -276,8 +276,10 @@ sk_sp<SkData> SkReadBuffer::readByteArrayAsData() { uint32_t SkReadBuffer::getArrayCount() { const size_t inc = sizeof(uint32_t); - fError = fError || !IsPtrAlign4(fReader.peek()) || !fReader.isAvailable(inc); - return fError ? 0 : *(uint32_t*)fReader.peek(); + if (!this->validate(IsPtrAlign4(fCurr) && this->isAvailable(inc))) { + return 0; + } + return *((uint32_t*)fCurr); } /* Format: @@ -424,10 +426,10 @@ SkFlattenable* SkReadBuffer::readFlattenable(SkFlattenable::Type ft) { sk_sp<SkFlattenable> obj; uint32_t sizeRecorded = this->read32(); if (factory) { - size_t offset = fReader.offset(); + size_t offset = this->offset(); obj = (*factory)(*this); // check that we read the amount we expected - size_t sizeRead = fReader.offset() - offset; + size_t sizeRead = this->offset() - offset; if (sizeRecorded != sizeRead) { this->validate(false); return nullptr; @@ -438,7 +440,7 @@ SkFlattenable* SkReadBuffer::readFlattenable(SkFlattenable::Type ft) { } } else { // we must skip the remaining data - fReader.skip(sizeRecorded); + this->skip(sizeRecorded); } if (!this->isValid()) { return nullptr; @@ -461,5 +463,3 @@ int32_t SkReadBuffer::checkInt(int32_t min, int32_t max) { SkFilterQuality SkReadBuffer::checkFilterQuality() { return this->checkRange<SkFilterQuality>(kNone_SkFilterQuality, kLast_SkFilterQuality); } - -#endif // #ifndef SK_DISABLE_READBUFFER diff --git a/chromium/third_party/skia/src/core/SkReadBuffer.h b/chromium/third_party/skia/src/core/SkReadBuffer.h index 0bc91a09e0a..59be7fc70dc 100644 --- a/chromium/third_party/skia/src/core/SkReadBuffer.h +++ b/chromium/third_party/skia/src/core/SkReadBuffer.h @@ -8,7 +8,6 @@ #ifndef SkReadBuffer_DEFINED #define SkReadBuffer_DEFINED -#include "include/core/SkColorFilter.h" #include "include/core/SkDrawLooper.h" #include "include/core/SkFont.h" #include "include/core/SkImageFilter.h" @@ -16,23 +15,26 @@ #include "include/core/SkPathEffect.h" #include "include/core/SkPicture.h" #include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" #include "include/core/SkSerialProcs.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkMaskFilterBase.h" #include "src/core/SkPaintPriv.h" #include "src/core/SkPicturePriv.h" -#include "src/core/SkReader32.h" #include "src/core/SkWriteBuffer.h" #include "src/shaders/SkShaderBase.h" class SkData; class SkImage; -#ifndef SK_DISABLE_READBUFFER - class SkReadBuffer { public: - SkReadBuffer(); - SkReadBuffer(const void* data, size_t size); + SkReadBuffer() = default; + SkReadBuffer(const void* data, size_t size) { + this->setMemory(data, size); + } + + void setMemory(const void*, size_t); /** * Returns true IFF the version is older than the specified version. @@ -50,12 +52,12 @@ public: fVersion = version; } - size_t size() const { return fReader.size(); } - size_t offset() const { return fReader.offset(); } - bool eof() { return fReader.eof(); } + size_t size() const { return fStop - fBase; } + size_t offset() const { return fCurr - fBase; } + bool eof() { return fCurr >= fStop; } const void* skip(size_t size); const void* skip(size_t count, size_t size); // does safe multiply - size_t available() const { return fReader.available(); } + size_t available() const { return fStop - fCurr; } template <typename T> const T* skipT() { return static_cast<const T*>(this->skip(sizeof(T))); @@ -106,7 +108,7 @@ public: template <typename T> sk_sp<T> readFlattenable() { return sk_sp<T>((T*)this->readFlattenable(T::GetFlattenableType())); } - sk_sp<SkColorFilter> readColorFilter() { return this->readFlattenable<SkColorFilter>(); } + sk_sp<SkColorFilter> readColorFilter() { return this->readFlattenable<SkColorFilterBase>(); } sk_sp<SkDrawLooper> readDrawLooper() { return this->readFlattenable<SkDrawLooper>(); } sk_sp<SkImageFilter> readImageFilter() { return this->readFlattenable<SkImageFilter>(); } sk_sp<SkMaskFilter> readMaskFilter() { return this->readFlattenable<SkMaskFilterBase>(); } @@ -124,6 +126,8 @@ public: bool readPointArray(SkPoint* points, size_t size); bool readScalarArray(SkScalar* values, size_t size); + const void* skipByteArray(size_t* size); + sk_sp<SkData> readByteArrayAsData(); // helpers to get info about arrays and binary data @@ -170,7 +174,7 @@ public: */ template <typename T> bool validateCanReadN(size_t n) { - return this->validate(n <= (fReader.available() / sizeof(T))); + return this->validate(n <= (this->available() / sizeof(T))); } bool isValid() const { return !fError; } @@ -196,20 +200,23 @@ private: void setInvalid(); bool readArray(void* value, size_t size, size_t elementSize); - void setMemory(const void*, size_t); + bool isAvailable(size_t size) const { return size <= this->available(); } - SkReader32 fReader; + // These are always 4-byte aligned + const char* fCurr = nullptr; // current position within buffer + const char* fStop = nullptr; // end of buffer + const char* fBase = nullptr; // beginning of buffer // Only used if we do not have an fFactoryArray. SkTHashMap<uint32_t, SkFlattenable::Factory> fFlattenableDict; - int fVersion; + int fVersion = 0; - sk_sp<SkTypeface>* fTFArray; - int fTFCount; + sk_sp<SkTypeface>* fTFArray = nullptr; + int fTFCount = 0; - SkFlattenable::Factory* fFactoryArray; - int fFactoryCount; + SkFlattenable::Factory* fFactoryArray = nullptr; + int fFactoryCount = 0; SkDeserialProcs fProcs; @@ -220,102 +227,4 @@ private: bool fError = false; }; -#else // #ifndef SK_DISABLE_READBUFFER - -class SkReadBuffer { -public: - SkReadBuffer() {} - SkReadBuffer(const void*, size_t) {} - - bool isVersionLT(SkPicturePriv::Version) const { return false; } - uint32_t getVersion() const { return 0xffffffff; } - void setVersion(int) {} - - size_t size() const { return 0; } - size_t offset() const { return 0; } - bool eof() { return true; } - size_t available() const { return 0; } - - const void* skip(size_t) { return nullptr; } - const void* skip(size_t, size_t) { return nullptr; } - template <typename T> const T* skipT() { return nullptr; } - template <typename T> const T* skipT(size_t) { return nullptr; } - - bool readBool() { return 0; } - SkColor readColor() { return 0; } - int32_t readInt() { return 0; } - SkScalar readScalar() { return 0; } - uint32_t readUInt() { return 0; } - int32_t read32() { return 0; } - - template <typename T> T read32LE(T max) { return max; } - - uint8_t peekByte() { return 0; } - - void readColor4f(SkColor4f* out) { *out = SkColor4f{0,0,0,0}; } - void readPoint (SkPoint* out) { *out = SkPoint{0,0}; } - void readPoint3 (SkPoint3* out) { *out = SkPoint3{0,0,0}; } - void readMatrix (SkMatrix* out) { *out = SkMatrix::I(); } - void readIRect (SkIRect* out) { *out = SkIRect{0,0,0,0}; } - void readRect (SkRect* out) { *out = SkRect{0,0,0,0}; } - void readRRect (SkRRect* out) { *out = SkRRect(); } - void readRegion (SkRegion* out) { *out = SkRegion(); } - void readString (SkString* out) { *out = SkString(); } - void readPath (SkPath* out) { *out = SkPath(); } - SkReadPaintResult readPaint (SkPaint* out, SkFont* font) { - *out = SkPaint(); - if (font) { - *font = SkFont(); - } - return kFailed_ReadPaint; - } - - SkPoint readPoint() { return {0,0}; } - - SkFlattenable* readFlattenable(SkFlattenable::Type) { return nullptr; } - - template <typename T> sk_sp<T> readFlattenable() { return nullptr; } - sk_sp<SkColorFilter> readColorFilter() { return nullptr; } - sk_sp<SkDrawLooper> readDrawLooper() { return nullptr; } - sk_sp<SkImageFilter> readImageFilter() { return nullptr; } - sk_sp<SkMaskFilter> readMaskFilter() { return nullptr; } - sk_sp<SkPathEffect> readPathEffect() { return nullptr; } - sk_sp<SkShader> readShader() { return nullptr; } - - bool readPad32 (void*, size_t) { return false; } - bool readByteArray (void*, size_t) { return false; } - bool readColorArray (SkColor*, size_t) { return false; } - bool readColor4fArray(SkColor4f*, size_t) { return false; } - bool readIntArray (int32_t*, size_t) { return false; } - bool readPointArray (SkPoint*, size_t) { return false; } - bool readScalarArray (SkScalar*, size_t) { return false; } - - sk_sp<SkData> readByteArrayAsData() { return nullptr; } - uint32_t getArrayCount() { return 0; } - - sk_sp<SkImage> readImage() { return nullptr; } - sk_sp<SkTypeface> readTypeface() { return nullptr; } - - bool validate(bool) { return false; } - template <typename T> bool validateCanReadN(size_t) { return false; } - bool isValid() const { return false; } - bool validateIndex(int, int) { return false; } - - int32_t checkInt(int min, int) { return min; } - template <typename T> T checkRange(T min, T) { return min; } - - SkFilterQuality checkFilterQuality() { return SkFilterQuality::kNone_SkFilterQuality; } - - void setTypefaceArray(sk_sp<SkTypeface>[], int) {} - void setFactoryPlayback(SkFlattenable::Factory[], int) {} - void setDeserialProcs(const SkDeserialProcs&) {} - - const SkDeserialProcs& getDeserialProcs() const { - static const SkDeserialProcs procs; - return procs; - } -}; - -#endif // #ifndef SK_DISABLE_READBUFFER - #endif // SkReadBuffer_DEFINED diff --git a/chromium/third_party/skia/src/core/SkReader32.h b/chromium/third_party/skia/src/core/SkReader32.h deleted file mode 100644 index ff2b820de6d..00000000000 --- a/chromium/third_party/skia/src/core/SkReader32.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2008 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - - -#ifndef SkReader32_DEFINED -#define SkReader32_DEFINED - -#include "include/core/SkData.h" -#include "include/core/SkMatrix.h" -#include "include/core/SkPath.h" -#include "include/core/SkRRect.h" -#include "include/core/SkRegion.h" -#include "include/core/SkScalar.h" -#include "include/private/SkNoncopyable.h" - -class SkString; - -class SkReader32 : SkNoncopyable { -public: - SkReader32() : fCurr(nullptr), fStop(nullptr), fBase(nullptr) {} - SkReader32(const void* data, size_t size) { - this->setMemory(data, size); - } - - void setMemory(const void* data, size_t size) { - SkASSERT(ptr_align_4(data)); - SkASSERT(SkAlign4(size) == size); - - fBase = fCurr = (const char*)data; - fStop = (const char*)data + size; - } - - size_t size() const { return fStop - fBase; } - size_t offset() const { return fCurr - fBase; } - bool eof() const { return fCurr >= fStop; } - const void* base() const { return fBase; } - const void* peek() const { return fCurr; } - - size_t available() const { return fStop - fCurr; } - bool isAvailable(size_t size) const { return size <= this->available(); } - - void rewind() { fCurr = fBase; } - - void setOffset(size_t offset) { - SkASSERT(SkAlign4(offset) == offset); - SkASSERT(offset <= this->size()); - fCurr = fBase + offset; - } - - bool readBool() { return this->readInt() != 0; } - - int32_t readInt() { - SkASSERT(ptr_align_4(fCurr)); - int32_t value = *(const int32_t*)fCurr; - fCurr += sizeof(value); - SkASSERT(fCurr <= fStop); - return value; - } - - void* readPtr() { - void* ptr; - // we presume this "if" is resolved at compile-time - if (4 == sizeof(void*)) { - ptr = *(void**)fCurr; - } else { - memcpy(&ptr, fCurr, sizeof(void*)); - } - fCurr += sizeof(void*); - return ptr; - } - - SkScalar readScalar() { - SkASSERT(ptr_align_4(fCurr)); - SkScalar value = *(const SkScalar*)fCurr; - fCurr += sizeof(value); - SkASSERT(fCurr <= fStop); - return value; - } - - const void* skip(size_t size) { - SkASSERT(ptr_align_4(fCurr)); - const void* addr = fCurr; - fCurr += SkAlign4(size); - SkASSERT(fCurr <= fStop); - return addr; - } - - template <typename T> const T& skipT() { - SkASSERT(SkAlign4(sizeof(T)) == sizeof(T)); - return *(const T*)this->skip(sizeof(T)); - } - - void read(void* dst, size_t size) { - SkASSERT(0 == size || dst != nullptr); - SkASSERT(ptr_align_4(fCurr)); - sk_careful_memcpy(dst, fCurr, size); - fCurr += SkAlign4(size); - SkASSERT(fCurr <= fStop); - } - - uint8_t readU8() { return (uint8_t)this->readInt(); } - uint16_t readU16() { return (uint16_t)this->readInt(); } - int32_t readS32() { return this->readInt(); } - uint32_t readU32() { return this->readInt(); } - - bool readPath(SkPath* path) { - return this->readObjectFromMemory(path); - } - - bool readMatrix(SkMatrix* matrix) { - return this->readObjectFromMemory(matrix); - } - - bool readRRect(SkRRect* rrect) { - return this->readObjectFromMemory(rrect); - } - - bool readRegion(SkRegion* rgn) { - return this->readObjectFromMemory(rgn); - } - - /** - * Read the length of a string (written by SkWriter32::writeString) into - * len (if len is not nullptr) and return the null-ternimated address of the - * string within the reader's buffer. - */ - const char* readString(size_t* len = nullptr); - - /** - * Read the string (written by SkWriter32::writeString) and return it in - * copy (if copy is not null). Return the length of the string. - */ - size_t readIntoString(SkString* copy); - - sk_sp<SkData> readData() { - uint32_t byteLength = this->readU32(); - if (0 == byteLength) { - return SkData::MakeEmpty(); - } - return SkData::MakeWithCopy(this->skip(byteLength), byteLength); - } - -private: - template <typename T> bool readObjectFromMemory(T* obj) { - size_t size = obj->readFromMemory(this->peek(), this->available()); - // If readFromMemory() fails (which means that available() was too small), it returns 0 - bool success = (size > 0) && (size <= this->available()) && (SkAlign4(size) == size); - // In case of failure, we want to skip to the end - (void)this->skip(success ? size : this->available()); - return success; - } - - // these are always 4-byte aligned - const char* fCurr; // current position within buffer - const char* fStop; // end of buffer - const char* fBase; // beginning of buffer - -#ifdef SK_DEBUG - static bool ptr_align_4(const void* ptr) { - return (((const char*)ptr - (const char*)nullptr) & 3) == 0; - } -#endif -}; - -#endif diff --git a/chromium/third_party/skia/src/core/SkRecord.h b/chromium/third_party/skia/src/core/SkRecord.h index 37cc0583b31..10a385fdf1e 100644 --- a/chromium/third_party/skia/src/core/SkRecord.h +++ b/chromium/third_party/skia/src/core/SkRecord.h @@ -85,19 +85,6 @@ public: return fRecords[i].set(this->allocCommand<T>()); } - // Replace the i-th command with a new command of type T. - // You are expected to placement new an object of type T onto this pointer. - // You must show proof that you've already adopted the existing command. - template <typename T, typename Existing> - T* replace(int i, const SkRecords::Adopted<Existing>& proofOfAdoption) { - SkASSERT(i < this->count()); - - SkASSERT(Existing::kType == fRecords[i].type()); - SkASSERT(proofOfAdoption == fRecords[i].ptr()); - - return fRecords[i].set(this->allocCommand<T>()); - } - // Does not return the bytes in any pointers embedded in the Records; callers // need to iterate with a visitor to measure those they care for. size_t bytesUsed() const; diff --git a/chromium/third_party/skia/src/core/SkRecordDraw.cpp b/chromium/third_party/skia/src/core/SkRecordDraw.cpp index a8d88dbc985..9a638471c8c 100644 --- a/chromium/third_party/skia/src/core/SkRecordDraw.cpp +++ b/chromium/third_party/skia/src/core/SkRecordDraw.cpp @@ -81,8 +81,6 @@ DRAW(Save, save()); DRAW(SaveLayer, saveLayer(SkCanvas::SaveLayerRec(r.bounds, r.paint, r.backdrop.get(), - r.clipMask.get(), - r.clipMatrix, r.saveLayerFlags))); template <> void Draw::draw(const SaveBehind& r) { diff --git a/chromium/third_party/skia/src/core/SkRecordOpts.cpp b/chromium/third_party/skia/src/core/SkRecordOpts.cpp index 127a9a861ee..45d5de3b58f 100644 --- a/chromium/third_party/skia/src/core/SkRecordOpts.cpp +++ b/chromium/third_party/skia/src/core/SkRecordOpts.cpp @@ -185,8 +185,8 @@ struct SaveLayerDrawRestoreNooper { typedef Pattern<Is<SaveLayer>, IsDraw, Is<Restore>> Match; bool onMatch(SkRecord* record, Match* match, int begin, int end) { - if (match->first<SaveLayer>()->backdrop || match->first<SaveLayer>()->clipMask) { - // can't throw away the layer if we have a backdrop or clip mask + if (match->first<SaveLayer>()->backdrop) { + // can't throw away the layer if we have a backdrop return false; } diff --git a/chromium/third_party/skia/src/core/SkRecorder.cpp b/chromium/third_party/skia/src/core/SkRecorder.cpp index b11bd1ae4b1..4ff6c1a3201 100644 --- a/chromium/third_party/skia/src/core/SkRecorder.cpp +++ b/chromium/third_party/skia/src/core/SkRecorder.cpp @@ -316,8 +316,6 @@ SkCanvas::SaveLayerStrategy SkRecorder::getSaveLayerStrategy(const SaveLayerRec& this->append<SkRecords::SaveLayer>(this->copy(rec.fBounds) , this->copy(rec.fPaint) , sk_ref_sp(rec.fBackdrop) - , sk_ref_sp(rec.fClipMask) - , this->copy(rec.fClipMatrix) , rec.fSaveLayerFlags); return SkCanvas::kNoLayer_SaveLayerStrategy; } diff --git a/chromium/third_party/skia/src/core/SkRecords.h b/chromium/third_party/skia/src/core/SkRecords.h index 8d89252e4b8..f44de620a7d 100644 --- a/chromium/third_party/skia/src/core/SkRecords.h +++ b/chromium/third_party/skia/src/core/SkRecords.h @@ -109,25 +109,6 @@ private: Optional& operator=(const Optional&) = delete; }; -// Like Optional, but ptr must not be NULL. -template <typename T> -class Adopted { -public: - Adopted(T* ptr) : fPtr(ptr) { SkASSERT(fPtr); } - Adopted(Adopted* source) { - // Transfer ownership from source to this. - fPtr = source->fPtr; - source->fPtr = NULL; - } - ~Adopted() { if (fPtr) fPtr->~T(); } - - ACT_AS_PTR(fPtr) -private: - T* fPtr; - Adopted(const Adopted&) = delete; - Adopted& operator=(const Adopted&) = delete; -}; - // PODArray doesn't own the pointer's memory, and we assume the data is POD. template <typename T> class PODArray { @@ -185,8 +166,6 @@ RECORD(SaveLayer, kHasPaint_Tag, Optional<SkRect> bounds; Optional<SkPaint> paint; sk_sp<const SkImageFilter> backdrop; - sk_sp<const SkImage> clipMask; - Optional<SkMatrix> clipMatrix; SkCanvas::SaveLayerFlags saveLayerFlags); RECORD(SaveBehind, 0, @@ -299,7 +278,7 @@ RECORD(DrawPoints, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkCanvas::PointMode mode; unsigned count; - SkPoint* pts); + PODArray<SkPoint> pts); RECORD(DrawRRect, kDraw_Tag|kHasPaint_Tag, SkPaint paint; SkRRect rrect); diff --git a/chromium/third_party/skia/src/core/SkRemoteGlyphCache.cpp b/chromium/third_party/skia/src/core/SkRemoteGlyphCache.cpp index d25a6c3daa7..ae4a83a3ccf 100644 --- a/chromium/third_party/skia/src/core/SkRemoteGlyphCache.cpp +++ b/chromium/third_party/skia/src/core/SkRemoteGlyphCache.cpp @@ -28,8 +28,9 @@ #include "src/core/SkZip.h" #if SK_SUPPORT_GPU +#include "include/gpu/GrContextOptions.h" #include "src/gpu/GrDrawOpAtlas.h" -#include "src/gpu/text/GrTextContext.h" +#include "src/gpu/text/GrSDFTOptions.h" #endif static SkDescriptor* auto_descriptor_from_desc(const SkDescriptor* source_desc, @@ -392,8 +393,9 @@ public: protected: void drawGlyphRunList(const SkGlyphRunList& glyphRunList) override { #if SK_SUPPORT_GPU - GrTextContext::Options options; - GrTextContext::SanitizeOptions(&options); + GrContextOptions ctxOptions; + GrSDFTOptions options = + {ctxOptions.fMinDistanceFieldFontSize, ctxOptions.fGlyphsAsPathsFontSize}; #ifdef SK_CAPTURE_DRAW_TEXT_BLOB if (SkTextBlobTrace::Capture* capture = fStrikeServer->fCapture.get()) { diff --git a/chromium/third_party/skia/src/core/SkRuntimeEffect.cpp b/chromium/third_party/skia/src/core/SkRuntimeEffect.cpp index ac5652bec4f..fb8d40e5c8f 100644 --- a/chromium/third_party/skia/src/core/SkRuntimeEffect.cpp +++ b/chromium/third_party/skia/src/core/SkRuntimeEffect.cpp @@ -11,6 +11,7 @@ #include "include/private/SkChecksum.h" #include "include/private/SkMutex.h" #include "src/core/SkCanvasPriv.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkColorSpacePriv.h" #include "src/core/SkColorSpaceXformSteps.h" #include "src/core/SkMatrixProvider.h" @@ -28,8 +29,8 @@ #include "include/private/GrRecordingContext.h" #include "src/gpu/GrColorInfo.h" #include "src/gpu/GrFPArgs.h" +#include "src/gpu/effects/GrMatrixEffect.h" #include "src/gpu/effects/GrSkSLFP.h" -#include "src/gpu/effects/generated/GrMatrixEffect.h" #endif #include <algorithm> @@ -411,7 +412,13 @@ SkRuntimeEffect::ByteCodeResult SkRuntimeEffect::toByteCode(const void* inputs) static std::vector<skvm::F32> program_fn(skvm::Builder* p, const SkSL::ByteCodeFunction& fn, const std::vector<skvm::F32>& uniform, - std::vector<skvm::F32> stack) { + const SkMatrixProvider& matrices, + std::vector<skvm::F32> stack, + /*these parameters are used to call program() on children*/ + const std::vector<sk_sp<SkShader>>& children, + skvm::Coord device, skvm::Color paint, + SkFilterQuality quality, const SkColorInfo& dst, + skvm::Uniforms* uniforms, SkArenaAlloc* alloc) { auto push = [&](skvm::F32 x) { stack.push_back(x); }; auto pop = [&]{ skvm::F32 x = stack.back(); stack.pop_back(); return x; }; @@ -466,6 +473,30 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p, #endif return {}; + // TODO: Inst::kSampleMatrix, should look much like kSampleExplicit. + + case Inst::kSampleExplicit: { + // Child shader to run. + int ix = u8(); + + // Stack contains x,y to sample at. + skvm::F32 y = pop(), + x = pop(); + + SkOverrideDeviceMatrixProvider mats{matrices, SkMatrix::I()}; + skvm::Color c = as_SB(children[ix])->program(p, device, {x,y},paint, + mats, nullptr, + quality, dst, + uniforms, alloc); + if (!c) { + return {}; + } + push(c.r); + push(c.g); + push(c.b); + push(c.a); + } break; + case Inst::kLoad: { int ix = u8(); push(stack[ix + 0]); @@ -518,6 +549,14 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p, push(uniform[ix + 3]); } break; + case Inst::kLoadFragCoord: { + // TODO: Actually supply Z and 1/W from the rasterizer? + push(device.x); + push(device.y); + push(p->splat(0.0f)); // Z + push(p->splat(1.0f)); // 1/W + } break; + case Inst::kStore: { int ix = u8(); stack[ix + 0] = pop(); @@ -571,6 +610,16 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p, push(stack[stack.size() - 4]); } break; + case Inst::kSwizzle: { + skvm::F32 tmp[4]; + for (int i = u8(); i --> 0;) { + tmp[i] = pop(); + } + for (int i = u8(); i --> 0;) { + push(tmp[u8()]); + } + } break; + case Inst::kAddF: case Inst::kAddF2: case Inst::kAddF3: @@ -591,11 +640,65 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p, case Inst::kDivideF3: case Inst::kDivideF4: binary(Inst::kDivideF, std::divides<>{}); break; + case Inst::kMinF: + case Inst::kMinF2: + case Inst::kMinF3: + case Inst::kMinF4: + binary(Inst::kMinF, [](skvm::F32 x, skvm::F32 y) { return skvm::min(x,y); }); + break; + + case Inst::kMaxF: + case Inst::kMaxF2: + case Inst::kMaxF3: + case Inst::kMaxF4: + binary(Inst::kMaxF, [](skvm::F32 x, skvm::F32 y) { return skvm::max(x,y); }); + break; + + case Inst::kNegateF: + case Inst::kNegateF2: + case Inst::kNegateF3: + case Inst::kNegateF4: unary(Inst::kNegateF, std::negate<>{}); break; + + case Inst::kPow: + case Inst::kPow2: + case Inst::kPow3: + case Inst::kPow4: + binary(Inst::kPow, [](skvm::F32 x, skvm::F32 y) { return skvm::approx_powf(x,y); }); + break; + + case Inst::kLerp: + case Inst::kLerp2: + case Inst::kLerp3: + case Inst::kLerp4: { + int N = (int)Inst::kLerp - (int)inst + 1; + + skvm::F32 t[4], + b[4], + a[4]; + for (int i = N; i --> 0; ) { t[i] = pop(); } + for (int i = N; i --> 0; ) { b[i] = pop(); } + for (int i = N; i --> 0; ) { a[i] = pop(); } + + for (int i = 0; i < N; i++) { + push(skvm::lerp(a[i], b[i], t[i])); + } + } break; + case Inst::kATan: case Inst::kATan2: case Inst::kATan3: case Inst::kATan4: unary(Inst::kATan, skvm::approx_atan); break; + case Inst::kCeil: + case Inst::kCeil2: + case Inst::kCeil3: + case Inst::kCeil4: unary(Inst::kCeil, skvm::ceil); break; + + case Inst::kFloor: + case Inst::kFloor2: + case Inst::kFloor3: + case Inst::kFloor4: unary(Inst::kFloor, skvm::floor); break; + case Inst::kFract: case Inst::kFract2: case Inst::kFract3: @@ -611,6 +714,27 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p, case Inst::kSin3: case Inst::kSin4: unary(Inst::kSin, skvm::approx_sin); break; + case Inst::kMatrixMultiply: { + // Computes M = A*B (all stored column major) + int aCols = u8(), + aRows = u8(), + bCols = u8(), + bRows = aCols; + std::vector<skvm::F32> A(aCols*aRows), + B(bCols*bRows); + for (auto i = B.size(); i --> 0;) { B[i] = pop(); } + for (auto i = A.size(); i --> 0;) { A[i] = pop(); } + + for (int c = 0; c < bCols; ++c) + for (int r = 0; r < aRows; ++r) { + skvm::F32 sum = p->splat(0.0f); + for (int j = 0; j < aCols; ++j) { + sum += A[j*aRows + r] * B[c*bRows + j]; + } + push(sum); + } + } break; + // Baby steps... just leaving test conditions on the stack for now. case Inst::kMaskPush: break; case Inst::kMaskNegate: break; @@ -647,27 +771,16 @@ static std::vector<skvm::F32> program_fn(skvm::Builder* p, } -class SkRuntimeColorFilter : public SkColorFilter { +class SkRuntimeColorFilter : public SkColorFilterBase { public: - SkRuntimeColorFilter(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> inputs, - sk_sp<SkColorFilter> children[], size_t childCount) + SkRuntimeColorFilter(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> inputs) : fEffect(std::move(effect)) - , fInputs(std::move(inputs)) - , fChildren(children, children + childCount) {} + , fInputs(std::move(inputs)) {} #if SK_SUPPORT_GPU std::unique_ptr<GrFragmentProcessor> asFragmentProcessor( GrRecordingContext* context, const GrColorInfo& colorInfo) const override { - auto fp = GrSkSLFP::Make(context, fEffect, "Runtime_Color_Filter", fInputs); - for (const auto& child : fChildren) { - auto childFP = child ? child->asFragmentProcessor(context, colorInfo) : nullptr; - if (!childFP) { - // TODO: This is the case that should eventually mean "the original input color" - return nullptr; - } - fp->addChild(std::move(childFP)); - } - return std::move(fp); + return GrSkSLFP::Make(context, fEffect, "Runtime_Color_Filter", fInputs); } #endif @@ -692,7 +805,7 @@ public: ctx->shaderConvention = false; ctx->byteCode = this->byteCode(); - if (!ctx->byteCode) { + if (!ctx->byteCode || !ctx->byteCode->canRun()) { return false; } @@ -722,7 +835,9 @@ public: } std::vector<skvm::F32> stack = - program_fn(p, *fn, uniform, {c.r, c.g, c.b, c.a}); + program_fn(p, *fn, uniform, SkSimpleMatrixProvider{SkMatrix::I()}, {c.r, c.g, c.b, c.a}, + /* the remaining parameters are for shaders only and won't be used here */ + {},{},{},{},{},{},{}); if (stack.size() == 4) { return {stack[0], stack[1], stack[2], stack[3]}; @@ -737,10 +852,6 @@ public: } else { buffer.writeByteArray(nullptr, 0); } - buffer.write32(fChildren.size()); - for (const auto& child : fChildren) { - buffer.writeFlattenable(child.get()); - } } SK_FLATTENABLE_HOOKS(SkRuntimeColorFilter) @@ -748,7 +859,6 @@ public: private: sk_sp<SkRuntimeEffect> fEffect; sk_sp<SkData> fInputs; - std::vector<sk_sp<SkColorFilter>> fChildren; mutable SkMutex fByteCodeMutex; mutable std::unique_ptr<SkSL::ByteCode> fByteCode; @@ -765,19 +875,7 @@ sk_sp<SkFlattenable> SkRuntimeColorFilter::CreateProc(SkReadBuffer& buffer) { return nullptr; } - size_t childCount = buffer.read32(); - if (childCount != effect->children().count()) { - buffer.validate(false); - return nullptr; - } - - std::vector<sk_sp<SkColorFilter>> children; - children.resize(childCount); - for (size_t i = 0; i < children.size(); ++i) { - children[i] = buffer.readColorFilter(); - } - - return effect->makeColorFilter(std::move(inputs), children.data(), children.size()); + return effect->makeColorFilter(std::move(inputs)); } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -879,9 +977,7 @@ public: fp->addChild(std::move(childFP)); } std::unique_ptr<GrFragmentProcessor> result = std::move(fp); - if (!matrix.isIdentity()) { - result = GrMatrixEffect::Make(matrix, std::move(result)); - } + result = GrMatrixEffect::Make(matrix, std::move(result)); if (GrColorTypeClampType(args.fDstColorInfo->colorType()) != GrClampType::kNone) { return GrFragmentProcessor::ClampPremulOutput(std::move(result)); } else { @@ -920,7 +1016,7 @@ public: ctx->shaderConvention = true; ctx->byteCode = this->byteCode(); - if (!ctx->byteCode) { + if (!ctx->byteCode || !ctx->byteCode->canRun()) { return false; } ctx->fn = ctx->byteCode->getFunction("main"); @@ -930,10 +1026,11 @@ public: return true; } - skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, - SkFilterQuality, const SkColorInfo& dst, - skvm::Uniforms* uniforms, SkArenaAlloc*) const override { + skvm::Color onProgram(skvm::Builder* p, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider& matrices, const SkMatrix* localM, + SkFilterQuality quality, const SkColorInfo& dst, + skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override { const SkSL::ByteCode* bc = this->byteCode(); if (!bc) { return {}; @@ -944,11 +1041,7 @@ public: return {}; } - // TODO: Eventually, plumb SkMatrixProvider here (instead of just ctm). For now, we will - // simply fail if our effect requires any marked matrices (SkSimpleMatrixProvider always - // returns false in getLocalToMarker). - SkSimpleMatrixProvider matrixProvider(SkMatrix::I()); - sk_sp<SkData> inputs = this->getUniforms(matrixProvider, dst.colorSpace()); + sk_sp<SkData> inputs = this->getUniforms(matrices, dst.colorSpace()); if (!inputs) { return {}; } @@ -961,13 +1054,16 @@ public: } SkMatrix inv; - if (!this->computeTotalInverse(ctm, localM, &inv)) { + if (!this->computeTotalInverse(matrices.localToDevice(), localM, &inv)) { return {}; } - SkShaderBase::ApplyMatrix(p,inv, &x,&y,uniforms); + local = SkShaderBase::ApplyMatrix(p,inv,local,uniforms); std::vector<skvm::F32> stack = - program_fn(p, *fn, uniform, {x,y, paint.r, paint.g, paint.b, paint.a}); + program_fn(p, *fn, uniform, matrices, + {local.x,local.y, paint.r, paint.g, paint.b, paint.a}, + /*parameters for calling program() on children*/ + fChildren, device,paint, quality,dst, uniforms,alloc); if (stack.size() == 6) { return {stack[2], stack[3], stack[4], stack[5]}; @@ -1069,22 +1165,18 @@ sk_sp<SkShader> SkRuntimeEffect::makeShader(sk_sp<SkData> inputs, : nullptr; } -sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> inputs, - sk_sp<SkColorFilter> children[], - size_t childCount) { +sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> inputs) { + if (!fChildren.empty()) { + return nullptr; + } if (!inputs) { inputs = SkData::MakeEmpty(); } - return inputs && inputs->size() == this->inputSize() && childCount == fChildren.size() - ? sk_sp<SkColorFilter>(new SkRuntimeColorFilter(sk_ref_sp(this), std::move(inputs), - children, childCount)) + return inputs->size() == this->inputSize() + ? sk_sp<SkColorFilter>(new SkRuntimeColorFilter(sk_ref_sp(this), std::move(inputs))) : nullptr; } -sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> inputs) { - return this->makeColorFilter(std::move(inputs), nullptr, 0); -} - /////////////////////////////////////////////////////////////////////////////////////////////////// void SkRuntimeEffect::RegisterFlattenables() { diff --git a/chromium/third_party/skia/src/core/SkSpecialImage.cpp b/chromium/third_party/skia/src/core/SkSpecialImage.cpp index 065d4fe542f..f434bd587b7 100644 --- a/chromium/third_party/skia/src/core/SkSpecialImage.cpp +++ b/chromium/third_party/skia/src/core/SkSpecialImage.cpp @@ -10,11 +10,9 @@ #include "include/core/SkBitmap.h" #include "include/core/SkCanvas.h" #include "include/core/SkImage.h" -#include "src/core/SkBitmapCache.h" #include "src/core/SkSpecialSurface.h" #include "src/core/SkSurfacePriv.h" #include "src/image/SkImage_Base.h" -#include <atomic> #if SK_SUPPORT_GPU #include "include/gpu/GrContext.h" @@ -23,7 +21,6 @@ #include "src/gpu/GrImageInfo.h" #include "src/gpu/GrProxyProvider.h" #include "src/gpu/GrRecordingContextPriv.h" -#include "src/gpu/GrSurfaceContext.h" #include "src/gpu/GrTextureProxy.h" #include "src/image/SkImage_Gpu.h" #endif @@ -88,52 +85,6 @@ SkSpecialImage::SkSpecialImage(const SkIRect& subset, , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID) { } -sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(GrRecordingContext* context) const { -#if SK_SUPPORT_GPU - if (!context) { - return nullptr; - } - if (GrRecordingContext* curContext = as_SIB(this)->onGetContext()) { - return curContext->priv().matches(context) ? sk_ref_sp(this) : nullptr; - } - - SkBitmap bmp; - // At this point, we are definitely not texture-backed, so we must be raster or generator - // backed. If we remove the special-wrapping-an-image subclass, we may be able to assert that - // we are strictly raster-backed (i.e. generator images become raster when they are specialized) - // in which case getROPixels could turn into peekPixels... - if (!this->getROPixels(&bmp)) { - return nullptr; - } - - if (bmp.empty()) { - return SkSpecialImage::MakeFromRaster(SkIRect::MakeEmpty(), bmp, &this->props()); - } - - // TODO: this is a tight copy of 'bmp' but it doesn't have to be (given SkSpecialImage's - // semantics). Since this is cached though we would have to bake the fit into the cache key. - auto view = GrMakeCachedBitmapProxyView(context, bmp); - if (!view.proxy()) { - return nullptr; - } - - const SkIRect rect = SkIRect::MakeSize(view.proxy()->dimensions()); - - // GrMakeCachedBitmapProxyView has uploaded only the specified subset of 'bmp' so we need not - // bother with SkBitmap::getSubset - return SkSpecialImage::MakeDeferredFromGpu(context, - rect, - this->uniqueID(), - std::move(view), - SkColorTypeToGrColorType(bmp.colorType()), - sk_ref_sp(this->getColorSpace()), - &this->props(), - this->alphaType()); -#else - return nullptr; -#endif -} - void SkSpecialImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) const { return as_SIB(this)->onDraw(canvas, x, y, paint); } @@ -207,21 +158,17 @@ sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(GrRecordingContext* context, SkASSERT(rect_fits(subset, image->width(), image->height())); #if SK_SUPPORT_GPU - if (const GrSurfaceProxyView* view = as_IB(image)->view(context)) { - if (!as_IB(image)->context()->priv().matches(context)) { - return nullptr; - } - - return MakeDeferredFromGpu(context, subset, image->uniqueID(), *view, + if (context) { + GrSurfaceProxyView view = as_IB(image)->refView(context, GrMipMapped::kNo); + return MakeDeferredFromGpu(context, subset, image->uniqueID(), view, SkColorTypeToGrColorType(image->colorType()), image->refColorSpace(), props); - } else + } #endif - { - SkBitmap bm; - if (as_IB(image)->getROPixels(&bm)) { - return MakeFromRaster(subset, bm, props); - } + + SkBitmap bm; + if (as_IB(image)->getROPixels(&bm)) { + return MakeFromRaster(subset, bm, props); } return nullptr; } @@ -385,14 +332,7 @@ public: , fView(std::move(view)) , fColorType(ct) , fAlphaType(at) - , fColorSpace(std::move(colorSpace)) - , fAddedRasterVersionToCache(false) { - } - - ~SkSpecialImage_Gpu() override { - if (fAddedRasterVersionToCache.load()) { - SkNotifyBitmapGenIDIsStale(this->uniqueID()); - } + , fColorSpace(std::move(colorSpace)) { } SkAlphaType alphaType() const override { return fAlphaType; } @@ -426,35 +366,10 @@ public: GrSurfaceProxyView onView(GrRecordingContext* context) const override { return fView; } bool onGetROPixels(SkBitmap* dst) const override { - const auto desc = SkBitmapCacheDesc::Make(this->uniqueID(), this->subset()); - if (SkBitmapCache::Find(desc, dst)) { - SkASSERT(dst->getGenerationID() == this->uniqueID()); - SkASSERT(dst->isImmutable()); - SkASSERT(dst->getPixels()); - return true; - } - - SkPixmap pmap; - SkImageInfo info = SkImageInfo::MakeN32(this->width(), this->height(), - this->alphaType(), fColorSpace); - auto rec = SkBitmapCache::Alloc(desc, info, &pmap); - if (!rec) { - return false; - } - auto sContext = GrSurfaceContext::Make(fContext, fView, fColorType, this->alphaType(), - fColorSpace); - if (!sContext) { - return false; - } - - if (!sContext->readPixels(info, pmap.writable_addr(), pmap.rowBytes(), - {this->subset().left(), this->subset().top()})) { - return false; - } - - SkBitmapCache::Add(std::move(rec), dst); - fAddedRasterVersionToCache.store(true); - return true; + // This should never be called: All GPU image filters are implemented entirely on the GPU, + // so we never perform read-back. + SkASSERT(false); + return false; } SkColorSpace* onGetColorSpace() const override { @@ -531,7 +446,6 @@ private: const GrColorType fColorType; const SkAlphaType fAlphaType; sk_sp<SkColorSpace> fColorSpace; - mutable std::atomic<bool> fAddedRasterVersionToCache; typedef SkSpecialImage_Base INHERITED; }; diff --git a/chromium/third_party/skia/src/core/SkSpecialImage.h b/chromium/third_party/skia/src/core/SkSpecialImage.h index 9df11ab04c5..0dfed777123 100644 --- a/chromium/third_party/skia/src/core/SkSpecialImage.h +++ b/chromium/third_party/skia/src/core/SkSpecialImage.h @@ -62,13 +62,6 @@ public: virtual size_t getSize() const = 0; /** - * Ensures that a special image is backed by a texture (when GrRecordingContext is non-null). - * If no transformation is required, the returned image may be the same as this special image. - * If this special image is from a different GrRecordingContext, this will fail. - */ - sk_sp<SkSpecialImage> makeTextureImage(GrRecordingContext*) const; - - /** * Draw this SpecialImage into the canvas, automatically taking into account the image's subset */ void draw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const; diff --git a/chromium/third_party/skia/src/core/SkStrikeSpec.cpp b/chromium/third_party/skia/src/core/SkStrikeSpec.cpp index c5c46bf46c8..51b92e087b6 100644 --- a/chromium/third_party/skia/src/core/SkStrikeSpec.cpp +++ b/chromium/third_party/skia/src/core/SkStrikeSpec.cpp @@ -14,8 +14,9 @@ #include "src/core/SkTLazy.h" #if SK_SUPPORT_GPU +#include "src/gpu/text/GrSDFMaskFilter.h" +#include "src/gpu/text/GrSDFTOptions.h" #include "src/gpu/text/GrStrikeCache.h" -#include "src/gpu/text/GrTextContext.h" #endif SkStrikeSpec SkStrikeSpec::MakeMask(const SkFont& font, const SkPaint& paint, @@ -186,20 +187,19 @@ SkStrikeSpec SkStrikeSpec::MakePDFVector(const SkTypeface& typeface, int* size) std::tuple<SkStrikeSpec, SkScalar, SkScalar> SkStrikeSpec::MakeSDFT(const SkFont& font, const SkPaint& paint, const SkSurfaceProps& surfaceProps, const SkMatrix& deviceMatrix, - const GrTextContext::Options& options) { + const GrSDFTOptions& options) { SkStrikeSpec storage; - SkPaint dfPaint = GrTextContext::InitDistanceFieldPaint(paint); - SkFont dfFont = GrTextContext::InitDistanceFieldFont( - font, deviceMatrix, options, &storage.fStrikeToSourceRatio); + SkPaint dfPaint{paint}; + dfPaint.setMaskFilter(GrSDFMaskFilter::Make()); + SkFont dfFont = options.getSDFFont(font, deviceMatrix, &storage.fStrikeToSourceRatio); // Fake-gamma and subpixel antialiasing are applied in the shader, so we ignore the // passed-in scaler context flags. (It's only used when we fall-back to bitmap text). SkScalerContextFlags flags = SkScalerContextFlags::kNone; SkScalar minScale, maxScale; - std::tie(minScale, maxScale) = GrTextContext::InitDistanceFieldMinMaxScale( - font.getSize(), deviceMatrix, options); + std::tie(minScale, maxScale) = options.computeSDFMinMaxScale(font.getSize(), deviceMatrix); storage.commonSetup(dfFont, dfPaint, surfaceProps, flags, SkMatrix::I()); diff --git a/chromium/third_party/skia/src/core/SkStrikeSpec.h b/chromium/third_party/skia/src/core/SkStrikeSpec.h index de8731750b9..5b854118ea6 100644 --- a/chromium/third_party/skia/src/core/SkStrikeSpec.h +++ b/chromium/third_party/skia/src/core/SkStrikeSpec.h @@ -13,7 +13,7 @@ #include "src/core/SkStrikeForGPU.h" #if SK_SUPPORT_GPU -#include "src/gpu/text/GrTextContext.h" +#include "src/gpu/text/GrSDFTOptions.h" class GrStrikeCache; class GrTextStrike; #endif @@ -67,7 +67,7 @@ public: const SkPaint& paint, const SkSurfaceProps& surfaceProps, const SkMatrix& deviceMatrix, - const GrTextContext::Options& options); + const GrSDFTOptions& options); sk_sp<GrTextStrike> findOrCreateGrStrike(GrStrikeCache* cache) const; #endif diff --git a/chromium/third_party/skia/src/core/SkString.cpp b/chromium/third_party/skia/src/core/SkString.cpp index d42ee6f07e9..13743b2212b 100644 --- a/chromium/third_party/skia/src/core/SkString.cpp +++ b/chromium/third_party/skia/src/core/SkString.cpp @@ -19,50 +19,38 @@ // number of bytes (on the stack) to receive the printf result static const size_t kBufferSize = 1024; -static const char* apply_format_string(const char* format, va_list args, char* stackBuffer, - size_t stackBufferSize, int* length, SkString* heapBuffer) { +struct StringBuffer { + char* fText; + int fLength; +}; + +template <int SIZE> +static StringBuffer apply_format_string(const char* format, va_list args, char (&stackBuffer)[SIZE], + SkString* heapBuffer) { + // First, attempt to print directly to the stack buffer. va_list argsCopy; va_copy(argsCopy, args); - *length = std::vsnprintf(stackBuffer, stackBufferSize, format, args); - if (*length < 0) { + int outLength = std::vsnprintf(stackBuffer, SIZE, format, args); + if (outLength < 0) { SkDebugf("SkString: vsnprintf reported error."); va_end(argsCopy); - *length = 0; - return stackBuffer; + return {stackBuffer, 0}; } - if (*length < SkToInt(stackBufferSize)) { + if (outLength < SIZE) { va_end(argsCopy); - return stackBuffer; + return {stackBuffer, outLength}; } - heapBuffer->resize(*length); - SkDEBUGCODE(int check =) - std::vsnprintf(heapBuffer->writable_str(), *length + 1, format, argsCopy); - SkASSERT(check == *length); + + // Our text was too long to fit on the stack! However, we now know how much space we need to + // format it. Format the string into our heap buffer. `set` automatically reserves an extra + // byte at the end of the buffer for a null terminator, so we don't need to add one here. + heapBuffer->set(nullptr, outLength); + char* heapBufferDest = heapBuffer->writable_str(); + SkDEBUGCODE(int checkLength =) std::vsnprintf(heapBufferDest, outLength + 1, format, argsCopy); + SkASSERT(checkLength == outLength); va_end(argsCopy); - return heapBuffer->c_str(); -} - -#define ARGS_TO_BUFFER(format, buffer, size, written, result) \ - SkString overflow; \ - do { \ - va_list args; \ - va_start(args, format); \ - result = apply_format_string(format, args, buffer, size, &written, &overflow); \ - va_end(args); \ - } while (0) - -#define V_SKSTRING_PRINTF(output, format) \ - do { \ - char buffer[kBufferSize]; \ - va_list args; \ - va_start(args, format); \ - int length; \ - auto result = apply_format_string(format, args, buffer, kBufferSize, &length, &output); \ - SkASSERT(result == output.c_str() || result == buffer); \ - if (result == buffer) { \ - output.set(buffer, length); \ - } \ - } while (0) + return {heapBufferDest, outLength}; +} /////////////////////////////////////////////////////////////////////////////// @@ -339,31 +327,40 @@ char* SkString::writable_str() { return fRec->data(); } +void SkString::resize(size_t len) { + len = trim_size_t_to_u32(len); + if (0 == len) { + this->reset(); + } else if (fRec->unique() && ((len >> 2) <= (fRec->fLength >> 2))) { + // Use less of the buffer we have without allocating a smaller one. + char* p = this->writable_str(); + p[len] = '\0'; + fRec->fLength = SkToU32(len); + } else { + SkString newString(len); + char* dest = newString.writable_str(); + int copyLen = std::min<uint32_t>(len, this->size()); + memcpy(dest, this->c_str(), copyLen); + dest[copyLen] = '\0'; + this->swap(newString); + } +} + void SkString::set(const char text[]) { this->set(text, text ? strlen(text) : 0); } void SkString::set(const char text[], size_t len) { len = trim_size_t_to_u32(len); - bool unique = fRec->unique(); if (0 == len) { this->reset(); - } else if (unique && len <= fRec->fLength) { - // should we resize if len <<<< fLength, to save RAM? (e.g. len < (fLength>>1))? - // just use less of the buffer without allocating a smaller one - char* p = this->writable_str(); - if (text) { - memcpy(p, text, len); - } - p[len] = 0; - fRec->fLength = SkToU32(len); - } else if (unique && (fRec->fLength >> 2) == (len >> 2)) { - // we have spare room in the current allocation, so don't alloc a larger one + } else if (fRec->unique() && ((len >> 2) <= (fRec->fLength >> 2))) { + // Use less of the buffer we have without allocating a smaller one. char* p = this->writable_str(); if (text) { memcpy(p, text, len); } - p[len] = 0; + p[len] = '\0'; fRec->fLength = SkToU32(len); } else { SkString tmp(text, len); @@ -488,44 +485,63 @@ void SkString::insertScalar(size_t offset, SkScalar value) { this->insert(offset, buffer, stop - buffer); } +/////////////////////////////////////////////////////////////////////////////// + void SkString::printf(const char format[], ...) { - V_SKSTRING_PRINTF((*this), format); + va_list args; + va_start(args, format); + this->printVAList(format, args); + va_end(args); } -void SkString::appendf(const char format[], ...) { - char buffer[kBufferSize]; - int length; - const char* result; - ARGS_TO_BUFFER(format, buffer, kBufferSize, length, result); +void SkString::printVAList(const char format[], va_list args) { + char stackBuffer[kBufferSize]; + StringBuffer result = apply_format_string(format, args, stackBuffer, this); + + if (result.fText == stackBuffer) { + this->set(result.fText, result.fLength); + } +} - this->append(result, length); +void SkString::appendf(const char format[], ...) { + va_list args; + va_start(args, format); + this->appendVAList(format, args); + va_end(args); } void SkString::appendVAList(const char format[], va_list args) { - char buffer[kBufferSize]; - int length = vsnprintf(buffer, kBufferSize, format, args); - SkASSERT(length >= 0 && length < SkToInt(kBufferSize)); + if (this->isEmpty()) { + this->printVAList(format, args); + return; + } + + SkString overflow; + char stackBuffer[kBufferSize]; + StringBuffer result = apply_format_string(format, args, stackBuffer, &overflow); - this->append(buffer, length); + this->append(result.fText, result.fLength); } void SkString::prependf(const char format[], ...) { - char buffer[kBufferSize]; - int length; - const char* result; - ARGS_TO_BUFFER(format, buffer, kBufferSize, length, result); - - this->prepend(result, length); + va_list args; + va_start(args, format); + this->prependVAList(format, args); + va_end(args); } void SkString::prependVAList(const char format[], va_list args) { - char buffer[kBufferSize]; - int length = vsnprintf(buffer, kBufferSize, format, args); - SkASSERT(length >= 0 && length < SkToInt(kBufferSize)); + if (this->isEmpty()) { + this->printVAList(format, args); + return; + } - this->prepend(buffer, length); -} + SkString overflow; + char stackBuffer[kBufferSize]; + StringBuffer result = apply_format_string(format, args, stackBuffer, &overflow); + this->prepend(result.fText, result.fLength); +} /////////////////////////////////////////////////////////////////////////////// @@ -568,7 +584,10 @@ void SkString::swap(SkString& other) { SkString SkStringPrintf(const char* format, ...) { SkString formattedOutput; - V_SKSTRING_PRINTF(formattedOutput, format); + va_list args; + va_start(args, format); + formattedOutput.printVAList(format, args); + va_end(args); return formattedOutput; } diff --git a/chromium/third_party/skia/src/core/SkVM.cpp b/chromium/third_party/skia/src/core/SkVM.cpp index 2a7db341702..654ab8f97c3 100644 --- a/chromium/third_party/skia/src/core/SkVM.cpp +++ b/chromium/third_party/skia/src/core/SkVM.cpp @@ -250,6 +250,7 @@ namespace skvm { case Op::select: write(o, V{id}, "=", op, V{x}, V{y}, V{z}, fs(id)...); break; case Op::pack: write(o, V{id}, "=", op, V{x}, V{y}, Shift{immz}, fs(id)...); break; + case Op::ceil: write(o, V{id}, "=", op, V{x}, fs(id)...); break; case Op::floor: write(o, V{id}, "=", op, V{x}, fs(id)...); break; case Op::to_f32: write(o, V{id}, "=", op, V{x}, fs(id)...); break; case Op::trunc: write(o, V{id}, "=", op, V{x}, fs(id)...); break; @@ -369,6 +370,7 @@ namespace skvm { case Op::select: write(o, R{d}, "=", op, R{x}, R{y}, R{z}); break; case Op::pack: write(o, R{d}, "=", op, R{x}, R{y}, Shift{immz}); break; + case Op::ceil: write(o, R{d}, "=", op, R{x}); break; case Op::floor: write(o, R{d}, "=", op, R{x}); break; case Op::to_f32: write(o, R{d}, "=", op, R{x}); break; case Op::trunc: write(o, R{d}, "=", op, R{x}); break; @@ -738,6 +740,9 @@ namespace skvm { } F32 Builder::approx_powf(F32 x, F32 y) { + // TODO: assert this instead? Sometimes x is very slightly negative. See skia:10210. + x = max(0.0f, x); + auto is_x = bit_or(eq(x, 0.0f), eq(x, 1.0f)); return select(is_x, x, approx_pow2(mul(approx_log2(x), y))); @@ -1010,6 +1015,10 @@ namespace skvm { return {this, this->push(Op::pack, x.id,y.id,NA, 0,bits)}; } + F32 Builder::ceil(F32 x) { + if (float X; this->allImm(x.id,&X)) { return splat(ceilf(X)); } + return {this, this->push(Op::ceil, x.id)}; + } F32 Builder::floor(F32 x) { if (float X; this->allImm(x.id,&X)) { return splat(floorf(X)); } return {this, this->push(Op::floor, x.id)}; @@ -1231,32 +1240,35 @@ namespace skvm { }; switch (mode) { - default: SkASSERT(false); /*but also, for safety, fallthrough*/ + default: + SkASSERT(false); + [[fallthrough]]; /*but also, for safety, fallthrough*/ case SkBlendMode::kClear: return { splat(0.0f), splat(0.0f), splat(0.0f), splat(0.0f) }; case SkBlendMode::kSrc: return src; case SkBlendMode::kDst: return dst; - case SkBlendMode::kDstOver: std::swap(src, dst); // fall-through + case SkBlendMode::kDstOver: std::swap(src, dst); [[fallthrough]]; case SkBlendMode::kSrcOver: return apply_rgba([&](auto s, auto d) { return mad(d,1-src.a, s); }); - case SkBlendMode::kDstIn: std::swap(src, dst); // fall-through + case SkBlendMode::kDstIn: std::swap(src, dst); [[fallthrough]]; case SkBlendMode::kSrcIn: return apply_rgba([&](auto s, auto d) { return s * dst.a; }); - case SkBlendMode::kDstOut: std::swap(src, dst); // fall-through + case SkBlendMode::kDstOut: std::swap(src, dst); [[fallthrough]]; + case SkBlendMode::kSrcOut: return apply_rgba([&](auto s, auto d) { return s * (1-dst.a); }); - case SkBlendMode::kDstATop: std::swap(src, dst); // fall-through + case SkBlendMode::kDstATop: std::swap(src, dst); [[fallthrough]]; case SkBlendMode::kSrcATop: return apply_rgba([&](auto s, auto d) { return mma(s, dst.a, d, 1-src.a); @@ -2346,6 +2358,9 @@ namespace skvm { F(vals[z])})); break; + case Op::ceil: + vals[i] = I(b->CreateUnaryIntrinsic(llvm::Intrinsic::ceil, F(vals[x]))); + break; case Op::floor: vals[i] = I(b->CreateUnaryIntrinsic(llvm::Intrinsic::floor, F(vals[x]))); break; @@ -3217,6 +3232,11 @@ namespace skvm { a->vpor (dst(), dst(), any(x)); break; + case Op::ceil: + if (in_reg(x)) { a->vroundps(dst(x), r(x), Assembler::CEIL); } + else { a->vroundps(dst(), any(x), Assembler::CEIL); } + break; + case Op::floor: if (in_reg(x)) { a->vroundps(dst(x), r(x), Assembler::FLOOR); } else { a->vroundps(dst(), any(x), Assembler::FLOOR); } diff --git a/chromium/third_party/skia/src/core/SkVM.h b/chromium/third_party/skia/src/core/SkVM.h index 697337e1d4b..db5b273c45c 100644 --- a/chromium/third_party/skia/src/core/SkVM.h +++ b/chromium/third_party/skia/src/core/SkVM.h @@ -387,7 +387,8 @@ namespace skvm { M(fma_f32) M(fms_f32) M(fnma_f32) \ M(sqrt_f32) \ M(shl_i32) M(shr_i32) M(sra_i32) \ - M(floor) M(trunc) M(round) M(to_f32) \ + M(ceil) M(floor) M(trunc) M(round) \ + M(to_f32) \ M( eq_f32) M( eq_i32) \ M(neq_f32) \ M( gt_f32) M( gt_i32) \ @@ -475,6 +476,12 @@ namespace skvm { Builder* operator->() const { return a.operator->(); } }; + struct Coord { + F32 x,y; + explicit operator bool() const { return x && y; } + Builder* operator->() const { return x.operator->(); } + }; + struct Uniform { Arg ptr; int offset; @@ -642,6 +649,7 @@ namespace skvm { F32 abs(F32 x) { return bit_cast(bit_and(bit_cast(x), 0x7fff'ffff)); } F32 fract(F32 x) { return sub(x, floor(x)); } + F32 ceil(F32); F32 floor(F32); I32 is_NaN(F32 x) { return neq(x,x); } @@ -871,11 +879,13 @@ namespace skvm { static inline I32 max(I32 x, I32a y) { return x->max(x,y); } static inline I32 max(int x, I32 y) { return y->max(x,y); } - static inline I32 operator==(I32 x, I32a y) { return x->eq(x,y); } - static inline I32 operator==(int x, I32 y) { return y->eq(x,y); } + static inline I32 operator==(I32 x, I32 y) { return x->eq(x,y); } + static inline I32 operator==(I32 x, int y) { return x->eq(x,y); } + static inline I32 operator==(int x, I32 y) { return y->eq(x,y); } - static inline I32 operator!=(I32 x, I32a y) { return x->neq(x,y); } - static inline I32 operator!=(int x, I32 y) { return y->neq(x,y); } + static inline I32 operator!=(I32 x, I32 y) { return x->neq(x,y); } + static inline I32 operator!=(I32 x, int y) { return x->neq(x,y); } + static inline I32 operator!=(int x, I32 y) { return y->neq(x,y); } static inline I32 operator< (I32 x, I32a y) { return x->lt(x,y); } static inline I32 operator< (int x, I32 y) { return y->lt(x,y); } @@ -908,11 +918,13 @@ namespace skvm { static inline F32 max(F32 x, F32a y) { return x->max(x,y); } static inline F32 max(float x, F32 y) { return y->max(x,y); } - static inline I32 operator==(F32 x, F32a y) { return x->eq(x,y); } - static inline I32 operator==(float x, F32 y) { return y->eq(x,y); } + static inline I32 operator==(F32 x, F32 y) { return x->eq(x,y); } + static inline I32 operator==(F32 x, float y) { return x->eq(x,y); } + static inline I32 operator==(float x, F32 y) { return y->eq(x,y); } - static inline I32 operator!=(F32 x, F32a y) { return x->neq(x,y); } - static inline I32 operator!=(float x, F32 y) { return y->neq(x,y); } + static inline I32 operator!=(F32 x, F32 y) { return x->neq(x,y); } + static inline I32 operator!=(F32 x, float y) { return x->neq(x,y); } + static inline I32 operator!=(float x, F32 y) { return y->neq(x,y); } static inline I32 operator< (F32 x, F32a y) { return x->lt(x,y); } static inline I32 operator< (float x, F32 y) { return y->lt(x,y); } @@ -974,6 +986,7 @@ namespace skvm { static inline F32 clamp01(F32 x) { return x->clamp01(x); } static inline F32 abs(F32 x) { return x-> abs(x); } + static inline F32 ceil(F32 x) { return x-> ceil(x); } static inline F32 fract(F32 x) { return x-> fract(x); } static inline F32 floor(F32 x) { return x-> floor(x); } static inline I32 is_NaN(F32 x) { return x-> is_NaN(x); } diff --git a/chromium/third_party/skia/src/core/SkVMBlitter.cpp b/chromium/third_party/skia/src/core/SkVMBlitter.cpp index 37172c8b7f9..196fae8a5cc 100644 --- a/chromium/third_party/skia/src/core/SkVMBlitter.cpp +++ b/chromium/third_party/skia/src/core/SkVMBlitter.cpp @@ -9,6 +9,7 @@ #include "include/private/SkMacros.h" #include "src/core/SkArenaAlloc.h" #include "src/core/SkBlendModePriv.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkColorSpacePriv.h" #include "src/core/SkColorSpaceXformSteps.h" #include "src/core/SkCoreBlitters.h" @@ -34,13 +35,13 @@ namespace { enum class Coverage { Full, UniformA8, MaskA8, MaskLCD16, Mask3D }; struct Params { - sk_sp<SkShader> shader; - sk_sp<SkShader> clip; - SkColorInfo dst; - SkBlendMode blendMode; - Coverage coverage; - SkFilterQuality quality; - SkMatrix ctm; + sk_sp<SkShader> shader; + sk_sp<SkShader> clip; + SkColorInfo dst; + SkBlendMode blendMode; + Coverage coverage; + SkFilterQuality quality; + const SkMatrixProvider& matrices; Params withCoverage(Coverage c) const { Params p = *this; @@ -59,7 +60,7 @@ namespace { blendMode, coverage; uint32_t padding{0}; - // Params::quality and Params::ctm are only passed to {shader,clip}->program(), + // Params::quality and Params::matrices are only passed to {shader,clip}->program(), // not used here by the blitter itself. No need to include them in the key; // they'll be folded into the shader key if used. @@ -117,8 +118,9 @@ namespace { skvm::I32 dx = p.uniform32(uniforms->base, offsetof(BlitterUniforms, right)) - p.index(), dy = p.uniform32(uniforms->base, offsetof(BlitterUniforms, y)); - skvm::F32 x = to_f32(dx) + 0.5f, - y = to_f32(dy) + 0.5f; + skvm::Coord device = {to_f32(dx) + 0.5f, + to_f32(dy) + 0.5f}, + local = device; skvm::Color paint = { p.uniformF(uniforms->base, offsetof(BlitterUniforms, paint.fR)), @@ -129,8 +131,8 @@ namespace { uint64_t hash = 0; if (auto c = sb->program(&p, - x,y, paint, - params.ctm, /*localM=*/nullptr, + device,local, paint, + params.matrices, /*localM=*/nullptr, params.quality, params.dst, uniforms,alloc)) { hash = p.hash(); @@ -197,8 +199,9 @@ namespace { skvm::I32 dx = p->uniform32(uniforms->base, offsetof(BlitterUniforms, right)) - p->index(), dy = p->uniform32(uniforms->base, offsetof(BlitterUniforms, y)); - skvm::F32 x = to_f32(dx) + 0.5f, - y = to_f32(dy) + 0.5f; + skvm::Coord device = {to_f32(dx) + 0.5f, + to_f32(dy) + 0.5f}, + local = device; skvm::Color paint = { p->uniformF(uniforms->base, offsetof(BlitterUniforms, paint.fR)), @@ -207,8 +210,8 @@ namespace { p->uniformF(uniforms->base, offsetof(BlitterUniforms, paint.fA)), }; - skvm::Color src = as_SB(params.shader)->program(p, x,y, paint, - params.ctm, /*localM=*/nullptr, + skvm::Color src = as_SB(params.shader)->program(p, device,local, paint, + params.matrices, /*localM=*/nullptr, params.quality, params.dst, uniforms, alloc); SkASSERT(src); @@ -274,8 +277,8 @@ namespace { } if (params.clip) { - skvm::Color clip = as_SB(params.clip)->program(p, x,y, paint, - params.ctm, /*localM=*/nullptr, + skvm::Color clip = as_SB(params.clip)->program(p, device,local, paint, + params.matrices, /*localM=*/nullptr, params.quality, params.dst, uniforms, alloc); SkAssertResult(clip); @@ -404,7 +407,7 @@ namespace { } - struct NoopColorFilter : public SkColorFilter { + struct NoopColorFilter : public SkColorFilterBase { skvm::Color onProgram(skvm::Builder*, skvm::Color c, SkColorSpace*, skvm::Uniforms*, SkArenaAlloc*) const override { return c; @@ -428,13 +431,14 @@ namespace { bool isOpaque() const override { return fShader->isOpaque(); } - skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color onProgram(skvm::Builder* p, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider& matrices, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override { // Run our wrapped shader. - skvm::Color c = as_SB(fShader)->program(p, x,y, paint, - ctm,localM, quality,dst, uniforms,alloc); + skvm::Color c = as_SB(fShader)->program(p, device,local, paint, + matrices,localM, quality,dst, uniforms,alloc); if (!c) { return {}; } @@ -467,8 +471,10 @@ namespace { // See SkRasterPipeline dither stage. // This is 8x8 ordered dithering. From here we'll only need dx and dx^dy. - skvm::I32 X = trunc(x - 0.5f), - Y = X ^ trunc(y - 0.5f); + SkASSERT(local.x.id == device.x.id); + SkASSERT(local.y.id == device.y.id); + skvm::I32 X = trunc(device.x - 0.5f), + Y = X ^ trunc(device.y - 0.5f); // If X's low bits are abc and Y's def, M is fcebda, // 6 bits producing all values [0,63] shuffled over an 8x8 grid. @@ -501,7 +507,7 @@ namespace { static Params effective_params(const SkPixmap& device, const SkPaint& paint, - const SkMatrix& ctm, + const SkMatrixProvider& matrices, sk_sp<SkShader> clip) { // Color filters have been handled for us by SkBlitter::Choose(). SkASSERT(!paint.getColorFilter()); @@ -547,7 +553,7 @@ namespace { blendMode, Coverage::Full, // Placeholder... withCoverage() will change as needed. paint.getFilterQuality(), - ctm, + matrices, }; } @@ -555,12 +561,12 @@ namespace { public: Blitter(const SkPixmap& device, const SkPaint& paint, - const SkMatrix& ctm, + const SkMatrixProvider& matrices, sk_sp<SkShader> clip, bool* ok) : fDevice(device) , fUniforms(kBlitterUniformsCount) - , fParams(effective_params(device, paint, ctm, std::move(clip))) + , fParams(effective_params(device, paint, matrices, std::move(clip))) , fKey(cache_key(fParams, &fUniforms, &fAlloc, ok)) , fPaint([&]{ SkColor4f color = paint.getColor4f(); @@ -737,10 +743,10 @@ namespace { SkBlitter* SkCreateSkVMBlitter(const SkPixmap& device, const SkPaint& paint, - const SkMatrix& ctm, + const SkMatrixProvider& matrices, SkArenaAlloc* alloc, sk_sp<SkShader> clip) { bool ok = true; - auto blitter = alloc->make<Blitter>(device, paint, ctm, std::move(clip), &ok); + auto blitter = alloc->make<Blitter>(device, paint, matrices, std::move(clip), &ok); return ok ? blitter : nullptr; } diff --git a/chromium/third_party/skia/src/core/SkVM_fwd.h b/chromium/third_party/skia/src/core/SkVM_fwd.h index 1442a9fa9d9..e8dc43f6e3f 100644 --- a/chromium/third_party/skia/src/core/SkVM_fwd.h +++ b/chromium/third_party/skia/src/core/SkVM_fwd.h @@ -16,6 +16,7 @@ namespace skvm { struct I32; struct F32; struct Color; + struct Coord; struct Uniforms; } diff --git a/chromium/third_party/skia/src/core/SkValidatingReadBuffer.h b/chromium/third_party/skia/src/core/SkValidatingReadBuffer.h deleted file mode 100644 index 887c621f84d..00000000000 --- a/chromium/third_party/skia/src/core/SkValidatingReadBuffer.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2013 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef SkValidatingReadBuffer_DEFINED -#define SkValidatingReadBuffer_DEFINED - -#include "include/core/SkPath.h" -#include "include/core/SkPicture.h" -#include "include/core/SkRefCnt.h" -#include "src/core/SkReadBuffer.h" -#include "src/core/SkReader32.h" -#include "src/core/SkWriteBuffer.h" - -class SkBitmap; - -// DEPRECATED -- just use SkReadBuffer (so we can delete this header) -typedef SkReadBuffer SkValidatingReadBuffer; - -#endif diff --git a/chromium/third_party/skia/src/core/SkWriteBuffer.cpp b/chromium/third_party/skia/src/core/SkWriteBuffer.cpp index f12099ab164..4e0424fac53 100644 --- a/chromium/third_party/skia/src/core/SkWriteBuffer.cpp +++ b/chromium/third_party/skia/src/core/SkWriteBuffer.cpp @@ -219,32 +219,29 @@ void SkBinaryWriteBuffer::writeFlattenable(const SkFlattenable* flattenable) { * already written the string, we write its index instead. */ - SkFlattenable::Factory factory = flattenable->getFactory(); - SkASSERT(factory); if (fFactorySet) { + SkFlattenable::Factory factory = flattenable->getFactory(); + SkASSERT(factory); + this->write32(fFactorySet->add(factory)); } else { + const char* name = flattenable->getTypeName(); + SkASSERT(name); + SkASSERT(0 != strcmp("", name)); - if (uint32_t* indexPtr = fFlattenableDict.find(factory)) { + if (uint32_t* indexPtr = fFlattenableDict.find(name)) { // We will write the index as a 32-bit int. We want the first byte // that we send to be zero - this will act as a sentinel that we // have an index (not a string). This means that we will send the // the index shifted left by 8. The remaining 24-bits should be // plenty to store the index. Note that this strategy depends on - // being little endian. + // being little endian, and type names being non-empty. SkASSERT(0 == *indexPtr >> 24); this->write32(*indexPtr << 8); } else { - const char* name = flattenable->getTypeName(); - SkASSERT(name); - // Otherwise write the string. Clients should not use the empty - // string as a name, or we will have a problem. - SkASSERT(0 != strcmp("", name)); this->writeString(name); - - // Add key to dictionary. - fFlattenableDict.set(factory, fFlattenableDict.count() + 1); + fFlattenableDict.set(name, fFlattenableDict.count() + 1); } } diff --git a/chromium/third_party/skia/src/core/SkWriteBuffer.h b/chromium/third_party/skia/src/core/SkWriteBuffer.h index 5bd58e9156d..f962786d2a2 100644 --- a/chromium/third_party/skia/src/core/SkWriteBuffer.h +++ b/chromium/third_party/skia/src/core/SkWriteBuffer.h @@ -122,6 +122,7 @@ public: bool writeToStream(SkWStream*) const; void writeToMemory(void* dst) const { fWriter.flatten(dst); } + sk_sp<SkData> snapshotAsData() const { return fWriter.snapshotAsData(); } void setFactoryRecorder(sk_sp<SkFactorySet>); void setTypefaceRecorder(sk_sp<SkRefCntSet>); @@ -133,7 +134,7 @@ private: SkWriter32 fWriter; // Only used if we do not have an fFactorySet - SkTHashMap<SkFlattenable::Factory, uint32_t> fFlattenableDict; + SkTHashMap<const char*, uint32_t> fFlattenableDict; }; #endif // SkWriteBuffer_DEFINED diff --git a/chromium/third_party/skia/src/core/SkWriter32.cpp b/chromium/third_party/skia/src/core/SkWriter32.cpp index 589382b381c..aa96531dfcd 100644 --- a/chromium/third_party/skia/src/core/SkWriter32.cpp +++ b/chromium/third_party/skia/src/core/SkWriter32.cpp @@ -5,11 +5,8 @@ * found in the LICENSE file. */ -#include "include/core/SkString.h" #include "include/private/SkTo.h" #include "src/core/SkMatrixPriv.h" -#include "src/core/SkReader32.h" - #include "src/core/SkWriter32.h" void SkWriter32::writeMatrix(const SkMatrix& matrix) { @@ -18,33 +15,6 @@ void SkWriter32::writeMatrix(const SkMatrix& matrix) { SkMatrixPriv::WriteToMemory(matrix, this->reserve(size)); } -/* - * Strings are stored as: length[4-bytes] + string_data + '\0' + pad_to_mul_4 - */ - -const char* SkReader32::readString(size_t* outLen) { - size_t len = this->readU32(); - const void* ptr = this->peek(); - - // skip over the string + '\0' and then pad to a multiple of 4 - size_t alignedSize = SkAlign4(len + 1); - this->skip(alignedSize); - - if (outLen) { - *outLen = len; - } - return (const char*)ptr; -} - -size_t SkReader32::readIntoString(SkString* copy) { - size_t len; - const char* ptr = this->readString(&len); - if (copy) { - copy->set(ptr, len); - } - return len; -} - void SkWriter32::writeString(const char str[], size_t len) { if (nullptr == str) { str = ""; diff --git a/chromium/third_party/skia/src/core/SkWriter32.h b/chromium/third_party/skia/src/core/SkWriter32.h index ca0664e4012..8e2595873bf 100644 --- a/chromium/third_party/skia/src/core/SkWriter32.h +++ b/chromium/third_party/skia/src/core/SkWriter32.h @@ -110,12 +110,6 @@ public: *(int32_t*)this->reserve(sizeof(value)) = value; } - void writePtr(void* value) { - // this->reserve() only returns 4-byte aligned pointers, - // so this may be an under-aligned write if we were to do this like the others. - memcpy(this->reserve(sizeof(value)), &value, sizeof(value)); - } - void writeScalar(SkScalar value) { *(SkScalar*)this->reserve(sizeof(value)) = value; } @@ -190,10 +184,9 @@ public: } /** - * Writes a string to the writer, which can be retrieved with - * SkReader32::readString(). - * The length can be specified, or if -1 is passed, it will be computed by - * calling strlen(). The length must be < max size_t. + * Writes a string to the writer, which can be retrieved with SkReadBuffer::readString(). + * The length can be specified, or if -1 is passed, it will be computed by calling strlen(). + * The length must be < max size_t. * * If you write NULL, it will be read as "". */ diff --git a/chromium/third_party/skia/src/effects/Sk1DPathEffect.cpp b/chromium/third_party/skia/src/effects/Sk1DPathEffect.cpp index 360179d6631..16dee4a90b6 100644 --- a/chromium/third_party/skia/src/effects/Sk1DPathEffect.cpp +++ b/chromium/third_party/skia/src/effects/Sk1DPathEffect.cpp @@ -127,7 +127,7 @@ static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas, srcP[2] = srcP[1]; srcP[1].set(SkScalarAve(srcP[0].fX, srcP[2].fX), SkScalarAve(srcP[0].fY, srcP[2].fY)); - // fall through to quad + [[fallthrough]]; case SkPath::kQuad_Verb: if (morphpoints(dstP, &srcP[1], 2, meas, dist)) { dst->quadTo(dstP[0], dstP[1]); diff --git a/chromium/third_party/skia/src/effects/SkHighContrastFilter.cpp b/chromium/third_party/skia/src/effects/SkHighContrastFilter.cpp index b97eabe0cf6..b670462166e 100644 --- a/chromium/third_party/skia/src/effects/SkHighContrastFilter.cpp +++ b/chromium/third_party/skia/src/effects/SkHighContrastFilter.cpp @@ -9,6 +9,7 @@ #include "include/effects/SkHighContrastFilter.h" #include "include/private/SkColorData.h" #include "src/core/SkArenaAlloc.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkColorSpacePriv.h" #include "src/core/SkEffectPriv.h" #include "src/core/SkRasterPipeline.h" @@ -25,7 +26,7 @@ using InvertStyle = SkHighContrastConfig::InvertStyle; -class SkHighContrast_Filter : public SkColorFilter { +class SkHighContrast_Filter : public SkColorFilterBase { public: SkHighContrast_Filter(const SkHighContrastConfig& config) { fConfig = config; @@ -305,9 +306,8 @@ void GLHighContrastFilterEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppendf("half4 color = %s;", args.fInputColor); - // Unpremultiply. The max() is to guard against 0 / 0. - fragBuilder->codeAppendf("half nonZeroAlpha = max(color.a, 0.0001);"); - fragBuilder->codeAppendf("color = half4(color.rgb / nonZeroAlpha, nonZeroAlpha);"); + // Unpremultiply. + fragBuilder->codeAppendf("color = unpremul(color);"); if (hcfe.linearize()) { fragBuilder->codeAppend("color.rgb = color.rgb * color.rgb;"); diff --git a/chromium/third_party/skia/src/effects/SkLumaColorFilter.cpp b/chromium/third_party/skia/src/effects/SkLumaColorFilter.cpp index 13efc7514b3..e246dae5e4a 100644 --- a/chromium/third_party/skia/src/effects/SkLumaColorFilter.cpp +++ b/chromium/third_party/skia/src/effects/SkLumaColorFilter.cpp @@ -8,6 +8,7 @@ #include "include/core/SkString.h" #include "include/effects/SkLumaColorFilter.h" #include "include/private/SkColorData.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkEffectPriv.h" #include "src/core/SkRasterPipeline.h" #include "src/core/SkVM.h" @@ -19,39 +20,50 @@ #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" #endif -bool SkLumaColorFilter::onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const { - rec.fPipeline->append(SkRasterPipeline::bt709_luminance_or_luma_to_alpha); - rec.fPipeline->append(SkRasterPipeline::clamp_0); - rec.fPipeline->append(SkRasterPipeline::clamp_1); - return true; -} +class SkLumaColorFilterImpl : public SkColorFilterBase { +public: +#if SK_SUPPORT_GPU + std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(GrRecordingContext*, + const GrColorInfo&) const override { + return GrLumaColorFilterEffect::Make(/*inputFP=*/nullptr); + } +#endif -skvm::Color SkLumaColorFilter::onProgram(skvm::Builder* p, skvm::Color c, - SkColorSpace* dstCS, - skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { - return { - p->splat(0.0f), - p->splat(0.0f), - p->splat(0.0f), - clamp01(c.r * 0.2126f + c.g * 0.7152f + c.b * 0.0722f), - }; -} + static sk_sp<SkFlattenable> CreateProc(SkReadBuffer&) { + return SkLumaColorFilter::Make(); + } -sk_sp<SkColorFilter> SkLumaColorFilter::Make() { - return sk_sp<SkColorFilter>(new SkLumaColorFilter); -} +protected: + void flatten(SkWriteBuffer&) const override {} -SkLumaColorFilter::SkLumaColorFilter() : INHERITED() {} +private: + Factory getFactory() const override { return CreateProc; } + const char* getTypeName() const override { return "SkLumaColorFilter"; } -sk_sp<SkFlattenable> SkLumaColorFilter::CreateProc(SkReadBuffer&) { - return Make(); -} + bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override { + rec.fPipeline->append(SkRasterPipeline::bt709_luminance_or_luma_to_alpha); + rec.fPipeline->append(SkRasterPipeline::clamp_0); + rec.fPipeline->append(SkRasterPipeline::clamp_1); + return true; + } -void SkLumaColorFilter::flatten(SkWriteBuffer&) const {} + skvm::Color onProgram(skvm::Builder* p, skvm::Color c, SkColorSpace*, skvm::Uniforms*, + SkArenaAlloc*) const override { + return { + p->splat(0.0f), + p->splat(0.0f), + p->splat(0.0f), + clamp01(c.r * 0.2126f + c.g * 0.7152f + c.b * 0.0722f), + }; + } -#if SK_SUPPORT_GPU -std::unique_ptr<GrFragmentProcessor> SkLumaColorFilter::asFragmentProcessor( - GrRecordingContext*, const GrColorInfo&) const { - return GrLumaColorFilterEffect::Make(); + typedef SkColorFilterBase INHERITED; +}; + +sk_sp<SkColorFilter> SkLumaColorFilter::Make() { + return sk_sp<SkColorFilter>(new SkLumaColorFilterImpl); +} + +void SkLumaColorFilter::RegisterFlattenable() { + SkFlattenable::Register("SkLumaColorFilter", SkLumaColorFilterImpl::CreateProc); } -#endif diff --git a/chromium/third_party/skia/src/effects/SkOpPE.h b/chromium/third_party/skia/src/effects/SkOpPE.h index 1f51579ebff..db87a052fe4 100644 --- a/chromium/third_party/skia/src/effects/SkOpPE.h +++ b/chromium/third_party/skia/src/effects/SkOpPE.h @@ -65,5 +65,20 @@ private: typedef SkPathEffect INHERITED; }; +class SkStrokeAndFillPE : public SkPathEffect { +public: + SkStrokeAndFillPE() {} + +protected: + void flatten(SkWriteBuffer&) const override; + bool onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override; + // TODO: override onComputeFastBounds (I think) + +private: + SK_FLATTENABLE_HOOKS(SkStrokeAndFillPE) + + typedef SkPathEffect INHERITED; +}; + #endif diff --git a/chromium/third_party/skia/src/effects/SkOpPathEffect.cpp b/chromium/third_party/skia/src/effects/SkOpPathEffect.cpp index e7b8a604bd1..91d89532b0b 100644 --- a/chromium/third_party/skia/src/effects/SkOpPathEffect.cpp +++ b/chromium/third_party/skia/src/effects/SkOpPathEffect.cpp @@ -57,7 +57,7 @@ sk_sp<SkPathEffect> SkMatrixPathEffect::MakeTranslate(SkScalar dx, SkScalar dy) if (!SkScalarsAreFinite(dx, dy)) { return nullptr; } - return sk_sp<SkPathEffect>(new SkMatrixPE(SkMatrix::MakeTrans(dx, dy))); + return sk_sp<SkPathEffect>(new SkMatrixPE(SkMatrix::Translate(dx, dy))); } sk_sp<SkPathEffect> SkMatrixPathEffect::Make(const SkMatrix& matrix) { @@ -121,4 +121,57 @@ sk_sp<SkFlattenable> SkStrokePE::CreateProc(SkReadBuffer& buffer) { return buffer.isValid() ? SkStrokePathEffect::Make(width, join, cap, miter) : nullptr; } +////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "include/effects/SkStrokeAndFillPathEffect.h" +#include "src/core/SkPathPriv.h" + +sk_sp<SkPathEffect> SkStrokeAndFillPathEffect::Make() { + static SkPathEffect* strokeAndFill = new SkStrokeAndFillPE; + return sk_ref_sp(strokeAndFill); +} + +void SkStrokeAndFillPE::flatten(SkWriteBuffer&) const {} + +static bool known_to_be_opposite_directions(const SkPath& a, const SkPath& b) { + auto a_dir = SkPathPriv::kUnknown_FirstDirection, + b_dir = SkPathPriv::kUnknown_FirstDirection; + (void)SkPathPriv::CheapComputeFirstDirection(a, &a_dir); + (void)SkPathPriv::CheapComputeFirstDirection(b, &b_dir); + + return (a_dir == SkPathPriv::kCCW_FirstDirection && + b_dir == SkPathPriv::kCW_FirstDirection) + || + (a_dir == SkPathPriv::kCW_FirstDirection && + b_dir == SkPathPriv::kCCW_FirstDirection); +} + +bool SkStrokeAndFillPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec, + const SkRect*) const { + // This one is weird, since we exist to allow this paint-style to go away. If we see it, + // just let the normal machine run its course. + if (rec->getStyle() == SkStrokeRec::kStrokeAndFill_Style) { + *dst = src; + return true; + } + if (rec->getStyle() == SkStrokeRec::kStroke_Style) { + if (!rec->applyToPath(dst, src)) { + return false; + } + + if (known_to_be_opposite_directions(src, *dst)) { + dst->reverseAddPath(src); + } else { + dst->addPath(src); + } + } else { + *dst = src; + } + rec->setFillStyle(); + return true; +} + +sk_sp<SkFlattenable> SkStrokeAndFillPE::CreateProc(SkReadBuffer& buffer) { + return SkStrokeAndFillPathEffect::Make(); +} diff --git a/chromium/third_party/skia/src/effects/SkTableColorFilter.cpp b/chromium/third_party/skia/src/effects/SkTableColorFilter.cpp index 87e0bd2bbfc..39b706274cb 100644 --- a/chromium/third_party/skia/src/effects/SkTableColorFilter.cpp +++ b/chromium/third_party/skia/src/effects/SkTableColorFilter.cpp @@ -13,6 +13,7 @@ #include "include/private/SkColorData.h" #include "include/private/SkTo.h" #include "src/core/SkArenaAlloc.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkEffectPriv.h" #include "src/core/SkRasterPipeline.h" #include "src/core/SkReadBuffer.h" @@ -54,7 +55,7 @@ static const uint8_t gIdentityTable[] = { 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; -class SkTable_ColorFilter : public SkColorFilter { +class SkTable_ColorFilter : public SkColorFilterBase { public: SkTable_ColorFilter(const uint8_t tableA[], const uint8_t tableR[], const uint8_t tableG[], const uint8_t tableB[]) { @@ -270,10 +271,9 @@ void SkTable_ColorFilter::getTableAsBitmap(SkBitmap* table) const { #include "src/gpu/GrFragmentProcessor.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/SkGr.h" +#include "src/gpu/effects/GrTextureEffect.h" #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" -#include "src/gpu/glsl/GrGLSLProgramDataManager.h" -#include "src/gpu/glsl/GrGLSLUniformHandler.h" class ColorTableEffect : public GrFragmentProcessor { public: @@ -285,89 +285,56 @@ public: const char* name() const override { return "ColorTableEffect"; } std::unique_ptr<GrFragmentProcessor> clone() const override { - return std::unique_ptr<GrFragmentProcessor>(new ColorTableEffect(fTextureSampler.view())); + return std::unique_ptr<GrFragmentProcessor>(new ColorTableEffect(*this)); } private: GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; + void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {} bool onIsEqual(const GrFragmentProcessor&) const override { return true; } - ColorTableEffect(GrSurfaceProxyView view) - : INHERITED( - kColorTableEffect_ClassID, - kNone_OptimizationFlags) // Not bothering with table-specific optimizations. - , fTextureSampler(std::move(view)) { - this->setTextureSamplerCnt(1); - } + ColorTableEffect(GrSurfaceProxyView view); - const TextureSampler& onTextureSampler(int) const override { return fTextureSampler; } + explicit ColorTableEffect(const ColorTableEffect& that); GR_DECLARE_FRAGMENT_PROCESSOR_TEST - TextureSampler fTextureSampler; - typedef GrFragmentProcessor INHERITED; }; -class GLColorTableEffect : public GrGLSLFragmentProcessor { -public: - void emitCode(EmitArgs&) override; - - static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*) {} - -private: - typedef GrGLSLFragmentProcessor INHERITED; -}; - -void GLColorTableEffect::emitCode(EmitArgs& args) { - static const float kColorScaleFactor = 255.0f / 256.0f; - static const float kColorOffsetFactor = 1.0f / 512.0f; - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - if (nullptr == args.fInputColor) { - // the input color is solid white (all ones). - static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor; - fragBuilder->codeAppendf("\t\thalf4 coord = half4(%f, %f, %f, %f);\n", - kMaxValue, kMaxValue, kMaxValue, kMaxValue); - - } else { - fragBuilder->codeAppendf("\t\thalf nonZeroAlpha = max(%s.a, .0001);\n", args.fInputColor); - fragBuilder->codeAppendf("\t\thalf4 coord = half4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", - args.fInputColor); - fragBuilder->codeAppendf("\t\tcoord = coord * %f + half4(%f, %f, %f, %f);\n", - kColorScaleFactor, - kColorOffsetFactor, kColorOffsetFactor, - kColorOffsetFactor, kColorOffsetFactor); - } - - SkString coord; - - fragBuilder->codeAppendf("\t\t%s.a = ", args.fOutputColor); - coord.printf("half2(coord.a, 0.125)"); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], coord.c_str()); - fragBuilder->codeAppend(".a;\n"); - - fragBuilder->codeAppendf("\t\t%s.r = ", args.fOutputColor); - coord.printf("half2(coord.r, 0.375)"); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], coord.c_str()); - fragBuilder->codeAppend(".a;\n"); - - fragBuilder->codeAppendf("\t\t%s.g = ", args.fOutputColor); - coord.printf("half2(coord.g, 0.625)"); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], coord.c_str()); - fragBuilder->codeAppend(".a;\n"); +ColorTableEffect::ColorTableEffect(GrSurfaceProxyView view) + // Not bothering with table-specific optimizations. + : INHERITED(kColorTableEffect_ClassID, kNone_OptimizationFlags) { + auto te = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType); + this->registerExplicitlySampledChild(std::move(te)); +} - fragBuilder->codeAppendf("\t\t%s.b = ", args.fOutputColor); - coord.printf("half2(coord.b, 0.875)"); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], coord.c_str()); - fragBuilder->codeAppend(".a;\n"); +ColorTableEffect::ColorTableEffect(const ColorTableEffect& that) + : INHERITED(kColorTableEffect_ClassID, that.optimizationFlags()) { + this->cloneAndRegisterAllChildProcessors(that); +} - fragBuilder->codeAppendf("\t\t%s.rgb *= %s.a;\n", args.fOutputColor, args.fOutputColor); +GrGLSLFragmentProcessor* ColorTableEffect::onCreateGLSLInstance() const { + class Impl : public GrGLSLFragmentProcessor { + public: + void emitCode(EmitArgs& args) override { + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + fragBuilder->codeAppendf("\t\thalf4 coord = 255*unpremul(%s) + 0.5;\n", + args.fInputColor); + SkString a = this->invokeChild(0, args, "half2(coord.a, 0.5)"); + SkString r = this->invokeChild(0, args, "half2(coord.r, 1.5)"); + SkString g = this->invokeChild(0, args, "half2(coord.g, 2.5)"); + SkString b = this->invokeChild(0, args, "half2(coord.b, 3.5)"); + fragBuilder->codeAppendf("%s = half4(half3(%s.a, %s.a, %s.a) * %s.a, %s.a);", + args.fOutputColor, r.c_str(), g.c_str(), b.c_str(), a.c_str(), + a.c_str()); + } + }; + return new Impl; } -/////////////////////////////////////////////////////////////////////////////// std::unique_ptr<GrFragmentProcessor> ColorTableEffect::Make(GrRecordingContext* context, const SkBitmap& bitmap) { SkASSERT(kPremul_SkAlphaType == bitmap.alphaType()); @@ -381,15 +348,6 @@ std::unique_ptr<GrFragmentProcessor> ColorTableEffect::Make(GrRecordingContext* return std::unique_ptr<GrFragmentProcessor>(new ColorTableEffect(std::move(view))); } -void ColorTableEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const { - GLColorTableEffect::GenKey(*this, caps, b); -} - -GrGLSLFragmentProcessor* ColorTableEffect::onCreateGLSLInstance() const { - return new GLColorTableEffect; -} - /////////////////////////////////////////////////////////////////////////////// GR_DEFINE_FRAGMENT_PROCESSOR_TEST(ColorTableEffect); @@ -420,7 +378,7 @@ std::unique_ptr<GrFragmentProcessor> ColorTableEffect::TestCreate(GrProcessorTes (flags & (1 << 3)) ? luts[3] : nullptr )); sk_sp<SkColorSpace> colorSpace = GrTest::TestColorSpace(d->fRandom); - auto fp = filter->asFragmentProcessor( + auto fp = as_CFB(filter)->asFragmentProcessor( d->context(), GrColorInfo(GrColorType::kRGBA_8888, kUnknown_SkAlphaType, std::move(colorSpace))); SkASSERT(fp); diff --git a/chromium/third_party/skia/src/effects/imagefilters/SkAlphaThresholdFilter.cpp b/chromium/third_party/skia/src/effects/imagefilters/SkAlphaThresholdFilter.cpp index 9984491aabb..3f433732d6e 100644 --- a/chromium/third_party/skia/src/effects/imagefilters/SkAlphaThresholdFilter.cpp +++ b/chromium/third_party/skia/src/effects/imagefilters/SkAlphaThresholdFilter.cpp @@ -19,7 +19,6 @@ #include "include/private/GrRecordingContext.h" #include "src/gpu/GrCaps.h" #include "src/gpu/GrColorSpaceXform.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/GrTextureProxy.h" @@ -110,17 +109,15 @@ GrSurfaceProxyView SkAlphaThresholdFilterImpl::createMaskTexture(GrRecordingCont } SkRegion::Iterator iter(fRegion); - rtContext->clear(nullptr, SK_PMColor4fTRANSPARENT, - GrRenderTargetContext::CanClearFullscreen::kYes); + rtContext->clear(SK_PMColor4fTRANSPARENT); - GrFixedClip clip(SkIRect::MakeWH(bounds.width(), bounds.height())); while (!iter.done()) { GrPaint paint; paint.setPorterDuffXPFactory(SkBlendMode::kSrc); SkRect rect = SkRect::Make(iter.rect()); - rtContext->drawRect(clip, std::move(paint), GrAA::kNo, inMatrix, rect); + rtContext->drawRect(nullptr, std::move(paint), GrAA::kNo, inMatrix, rect); iter.next(); } @@ -165,10 +162,12 @@ sk_sp<SkSpecialImage> SkAlphaThresholdFilterImpl::onFilterImage(const Context& c if (!maskView) { return nullptr; } + auto maskFP = GrTextureEffect::Make(std::move(maskView), kPremul_SkAlphaType, + SkMatrix::Translate(-bounds.x(), -bounds.y())); auto textureFP = GrTextureEffect::Make( std::move(inputView), input->alphaType(), - SkMatrix::MakeTrans(input->subset().x(), input->subset().y())); + SkMatrix::Translate(input->subset().x(), input->subset().y())); textureFP = GrColorSpaceXformEffect::Make(std::move(textureFP), input->getColorSpace(), input->alphaType(), ctx.colorSpace()); if (!textureFP) { @@ -176,17 +175,13 @@ sk_sp<SkSpecialImage> SkAlphaThresholdFilterImpl::onFilterImage(const Context& c } auto thresholdFP = GrAlphaThresholdFragmentProcessor::Make( - std::move(maskView), fInnerThreshold, fOuterThreshold, bounds); + std::move(textureFP), std::move(maskFP), fInnerThreshold, fOuterThreshold); if (!thresholdFP) { return nullptr; } - std::unique_ptr<GrFragmentProcessor> fpSeries[] = { std::move(textureFP), - std::move(thresholdFP) }; - auto fp = GrFragmentProcessor::RunInSeries(fpSeries, 2); - - return DrawWithFP(context, std::move(fp), bounds, ctx.colorType(), ctx.colorSpace(), - isProtected); + return DrawWithFP(context, std::move(thresholdFP), bounds, ctx.colorType(), + ctx.colorSpace(), isProtected); } #endif diff --git a/chromium/third_party/skia/src/effects/imagefilters/SkArithmeticImageFilter.cpp b/chromium/third_party/skia/src/effects/imagefilters/SkArithmeticImageFilter.cpp index b357cb8fefb..ae7ff489aa7 100644 --- a/chromium/third_party/skia/src/effects/imagefilters/SkArithmeticImageFilter.cpp +++ b/chromium/third_party/skia/src/effects/imagefilters/SkArithmeticImageFilter.cpp @@ -18,7 +18,6 @@ #if SK_SUPPORT_GPU #include "include/effects/SkRuntimeEffect.h" #include "include/private/GrRecordingContext.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrColorSpaceXform.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRenderTargetContext.h" @@ -354,7 +353,7 @@ sk_sp<SkSpecialImage> ArithmeticImageFilterImpl::filterImageGPU( if (background) { SkRect bgSubset = SkRect::Make(background->subset()); - SkMatrix backgroundMatrix = SkMatrix::MakeTrans( + SkMatrix backgroundMatrix = SkMatrix::Translate( SkIntToScalar(bgSubset.left() - backgroundOffset.fX), SkIntToScalar(bgSubset.top() - backgroundOffset.fY)); bgFP = GrTextureEffect::MakeSubset(std::move(backgroundView), background->alphaType(), @@ -363,13 +362,13 @@ sk_sp<SkSpecialImage> ArithmeticImageFilterImpl::filterImageGPU( background->alphaType(), ctx.colorSpace()); } else { - bgFP = GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT, + bgFP = GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT, GrConstColorProcessor::InputMode::kIgnore); } if (foreground) { SkRect fgSubset = SkRect::Make(foreground->subset()); - SkMatrix foregroundMatrix = SkMatrix::MakeTrans( + SkMatrix foregroundMatrix = SkMatrix::Translate( SkIntToScalar(fgSubset.left() - foregroundOffset.fX), SkIntToScalar(fgSubset.top() - foregroundOffset.fY)); auto fgFP = GrTextureEffect::MakeSubset(std::move(foregroundView), foreground->alphaType(), @@ -403,7 +402,7 @@ sk_sp<SkSpecialImage> ArithmeticImageFilterImpl::filterImageGPU( SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); - renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, + renderTargetContext->drawRect(nullptr, std::move(paint), GrAA::kNo, matrix, SkRect::Make(bounds)); return SkSpecialImage::MakeDeferredFromGpu(context, diff --git a/chromium/third_party/skia/src/effects/imagefilters/SkColorFilterImageFilter.cpp b/chromium/third_party/skia/src/effects/imagefilters/SkColorFilterImageFilter.cpp index b9154431c68..32e7dc8cde9 100644 --- a/chromium/third_party/skia/src/effects/imagefilters/SkColorFilterImageFilter.cpp +++ b/chromium/third_party/skia/src/effects/imagefilters/SkColorFilterImageFilter.cpp @@ -9,6 +9,7 @@ #include "include/core/SkCanvas.h" #include "include/core/SkColorFilter.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkImageFilter_Base.h" #include "src/core/SkReadBuffer.h" #include "src/core/SkSpecialImage.h" @@ -89,7 +90,7 @@ sk_sp<SkSpecialImage> SkColorFilterImageFilterImpl::onFilterImage(const Context& sk_sp<SkSpecialImage> input(this->filterInput(0, ctx, &inputOffset)); SkIRect inputBounds; - if (fColorFilter->affectsTransparentBlack()) { + if (as_CFB(fColorFilter)->affectsTransparentBlack()) { // If the color filter affects transparent black, the bounds are the entire clip. inputBounds = ctx.clipBounds(); } else if (!input) { @@ -119,7 +120,7 @@ sk_sp<SkSpecialImage> SkColorFilterImageFilterImpl::onFilterImage(const Context& // TODO: it may not be necessary to clear or drawPaint inside the input bounds // (see skbug.com/5075) - if (fColorFilter->affectsTransparentBlack()) { + if (as_CFB(fColorFilter)->affectsTransparentBlack()) { // The subsequent input->draw() call may not fill the entire canvas. For filters which // affect transparent black, ensure that the filter is applied everywhere. paint.setColor(SK_ColorTRANSPARENT); @@ -153,5 +154,5 @@ bool SkColorFilterImageFilterImpl::onIsColorFilterNode(SkColorFilter** filter) c } bool SkColorFilterImageFilterImpl::affectsTransparentBlack() const { - return fColorFilter->affectsTransparentBlack(); + return as_CFB(fColorFilter)->affectsTransparentBlack(); } diff --git a/chromium/third_party/skia/src/effects/imagefilters/SkDisplacementMapEffect.cpp b/chromium/third_party/skia/src/effects/imagefilters/SkDisplacementMapEffect.cpp index aa926f89051..fe5fe87ccd4 100644 --- a/chromium/third_party/skia/src/effects/imagefilters/SkDisplacementMapEffect.cpp +++ b/chromium/third_party/skia/src/effects/imagefilters/SkDisplacementMapEffect.cpp @@ -17,7 +17,6 @@ #if SK_SUPPORT_GPU #include "include/private/GrRecordingContext.h" #include "src/gpu/GrCaps.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrColorSpaceXform.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrRecordingContextPriv.h" @@ -338,7 +337,7 @@ sk_sp<SkSpecialImage> SkDisplacementMapEffectImpl::onFilterImage(const Context& } const auto isProtected = colorView.proxy()->isProtected(); - SkMatrix offsetMatrix = SkMatrix::MakeTrans(SkIntToScalar(colorOffset.fX - displOffset.fX), + SkMatrix offsetMatrix = SkMatrix::Translate(SkIntToScalar(colorOffset.fX - displOffset.fX), SkIntToScalar(colorOffset.fY - displOffset.fY)); std::unique_ptr<GrFragmentProcessor> fp = @@ -367,7 +366,7 @@ sk_sp<SkSpecialImage> SkDisplacementMapEffectImpl::onFilterImage(const Context& return nullptr; } - renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, + renderTargetContext->drawRect(nullptr, std::move(paint), GrAA::kNo, matrix, SkRect::Make(colorBounds)); offset->fX = bounds.left(); @@ -472,12 +471,12 @@ std::unique_ptr<GrFragmentProcessor> GrDisplacementMapEffect::Make(SkColorChanne GrSamplerState::Filter::kNearest); auto colorEffect = GrTextureEffect::MakeSubset(std::move(color), kPremul_SkAlphaType, - SkMatrix::MakeTrans(colorSubset.topLeft()), + SkMatrix::Translate(colorSubset.topLeft()), kColorSampler, SkRect::Make(colorSubset), caps); - auto dispM = SkMatrix::Concat(SkMatrix::MakeTrans(displSubset.topLeft()), offsetMatrix); + auto dispM = SkMatrix::Concat(SkMatrix::Translate(displSubset.topLeft()), offsetMatrix); auto dispEffect = GrTextureEffect::Make(std::move(displacement), kPremul_SkAlphaType, dispM, @@ -509,9 +508,8 @@ GrDisplacementMapEffect::GrDisplacementMapEffect(SkColorChannel xChannelSelector , fXChannelSelector(xChannelSelector) , fYChannelSelector(yChannelSelector) , fScale(scale) { - this->registerChildProcessor(std::move(displacement)); - color->setSampledWithExplicitCoords(); - this->registerChildProcessor(std::move(color)); + this->registerChild(std::move(displacement)); + this->registerExplicitlySampledChild(std::move(color)); this->addCoordTransform(&fCoordTransform); } @@ -520,15 +518,7 @@ GrDisplacementMapEffect::GrDisplacementMapEffect(const GrDisplacementMapEffect& , fXChannelSelector(that.fXChannelSelector) , fYChannelSelector(that.fYChannelSelector) , fScale(that.fScale) { - auto displacement = that.childProcessor(0).clone(); - if (that.childProcessor(0).isSampledWithExplicitCoords()) { - displacement->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(displacement)); - - auto color = that.childProcessor(1).clone(); - color->setSampledWithExplicitCoords(); - this->registerChildProcessor(std::move(color)); + this->cloneAndRegisterAllChildProcessors(that); this->addCoordTransform(&fCoordTransform); } diff --git a/chromium/third_party/skia/src/effects/imagefilters/SkLightingImageFilter.cpp b/chromium/third_party/skia/src/effects/imagefilters/SkLightingImageFilter.cpp index 89984d91c59..5181f11d64f 100644 --- a/chromium/third_party/skia/src/effects/imagefilters/SkLightingImageFilter.cpp +++ b/chromium/third_party/skia/src/effects/imagefilters/SkLightingImageFilter.cpp @@ -19,7 +19,6 @@ #if SK_SUPPORT_GPU #include "include/private/GrRecordingContext.h" #include "src/gpu/GrCaps.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrFragmentProcessor.h" #include "src/gpu/GrPaint.h" #include "src/gpu/GrRecordingContextPriv.h" @@ -444,7 +443,6 @@ private: void drawRect(GrRenderTargetContext*, GrSurfaceProxyView srcView, const SkMatrix& matrix, - const GrClip& clip, const SkRect& dstRect, BoundaryMode boundaryMode, const SkIRect* srcBounds, @@ -461,7 +459,6 @@ private: void SkLightingImageFilterInternal::drawRect(GrRenderTargetContext* renderTargetContext, GrSurfaceProxyView srcView, const SkMatrix& matrix, - const GrClip& clip, const SkRect& dstRect, BoundaryMode boundaryMode, const SkIRect* srcBounds, @@ -472,8 +469,8 @@ void SkLightingImageFilterInternal::drawRect(GrRenderTargetContext* renderTarget *renderTargetContext->caps()); paint.addColorFragmentProcessor(std::move(fp)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect, - srcRect); + renderTargetContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), + dstRect, srcRect); } sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU( @@ -499,9 +496,6 @@ sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU( SkIRect dstIRect = SkIRect::MakeWH(offsetBounds.width(), offsetBounds.height()); SkRect dstRect = SkRect::Make(dstIRect); - // setup new clip - GrFixedClip clip(dstIRect); - const SkIRect inputBounds = SkIRect::MakeWH(input->width(), input->height()); SkRect topLeft = SkRect::MakeXYWH(0, 0, 1, 1); SkRect top = SkRect::MakeXYWH(1, 0, dstRect.width() - 2, 1); @@ -514,23 +508,23 @@ sk_sp<SkSpecialImage> SkLightingImageFilterInternal::filterImageGPU( SkRect bottomRight = SkRect::MakeXYWH(dstRect.width() - 1, dstRect.height() - 1, 1, 1); const SkIRect* pSrcBounds = inputBounds.contains(offsetBounds) ? nullptr : &inputBounds; - this->drawRect(renderTargetContext.get(), inputView, matrix, clip, topLeft, + this->drawRect(renderTargetContext.get(), inputView, matrix, topLeft, kTopLeft_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(renderTargetContext.get(), inputView, matrix, clip, top, + this->drawRect(renderTargetContext.get(), inputView, matrix, top, kTop_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(renderTargetContext.get(), inputView, matrix, clip, topRight, + this->drawRect(renderTargetContext.get(), inputView, matrix, topRight, kTopRight_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(renderTargetContext.get(), inputView, matrix, clip, left, + this->drawRect(renderTargetContext.get(), inputView, matrix, left, kLeft_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(renderTargetContext.get(), inputView, matrix, clip, interior, + this->drawRect(renderTargetContext.get(), inputView, matrix, interior, kInterior_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(renderTargetContext.get(), inputView, matrix, clip, right, + this->drawRect(renderTargetContext.get(), inputView, matrix, right, kRight_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(renderTargetContext.get(), inputView, matrix, clip, bottomLeft, + this->drawRect(renderTargetContext.get(), inputView, matrix, bottomLeft, kBottomLeft_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(renderTargetContext.get(), inputView, matrix, clip, bottom, + this->drawRect(renderTargetContext.get(), inputView, matrix, bottom, kBottom_BoundaryMode, pSrcBounds, offsetBounds); - this->drawRect(renderTargetContext.get(), std::move(inputView), matrix, clip, bottomRight, + this->drawRect(renderTargetContext.get(), std::move(inputView), matrix, bottomRight, kBottomRight_BoundaryMode, pSrcBounds, offsetBounds); return SkSpecialImage::MakeDeferredFromGpu( @@ -1638,8 +1632,7 @@ GrLightingEffect::GrLightingEffect(ClassID classID, child = GrTextureEffect::Make(std::move(view), kPremul_SkAlphaType, SkMatrix::I(), kSampler, caps); } - child->setSampledWithExplicitCoords(); - this->registerChildProcessor(std::move(child)); + this->registerExplicitlySampledChild(std::move(child)); this->addCoordTransform(&fCoordTransform); } @@ -1649,9 +1642,7 @@ GrLightingEffect::GrLightingEffect(const GrLightingEffect& that) , fSurfaceScale(that.fSurfaceScale) , fFilterMatrix(that.fFilterMatrix) , fBoundaryMode(that.fBoundaryMode) { - auto child = that.childProcessor(0).clone(); - child->setSampledWithExplicitCoords(); - this->registerChildProcessor(std::move(child)); + this->cloneAndRegisterAllChildProcessors(that); this->addCoordTransform(&fCoordTransform); } diff --git a/chromium/third_party/skia/src/effects/imagefilters/SkMagnifierImageFilter.cpp b/chromium/third_party/skia/src/effects/imagefilters/SkMagnifierImageFilter.cpp index 835dd1a2dcd..4300a390681 100644 --- a/chromium/third_party/skia/src/effects/imagefilters/SkMagnifierImageFilter.cpp +++ b/chromium/third_party/skia/src/effects/imagefilters/SkMagnifierImageFilter.cpp @@ -19,8 +19,7 @@ #if SK_SUPPORT_GPU #include "include/gpu/GrContext.h" #include "src/gpu/GrColorSpaceXform.h" -#include "src/gpu/GrCoordTransform.h" -#include "src/gpu/GrTexture.h" +#include "src/gpu/effects/GrTextureEffect.h" #include "src/gpu/effects/generated/GrMagnifierEffect.h" #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" @@ -136,9 +135,9 @@ sk_sp<SkSpecialImage> SkMagnifierImageFilterImpl::onFilterImage(const Context& c bounds.offset(input->subset().x(), input->subset().y()); SkRect srcRect = fSrcRect.makeOffset((1.f - invXZoom) * input->subset().x(), (1.f - invYZoom) * input->subset().y()); + auto inputFP = GrTextureEffect::Make(std::move(inputView), kPremul_SkAlphaType); - // TODO: Update generated fp file Make functions to take views instead of proxies - auto fp = GrMagnifierEffect::Make(std::move(inputView), + auto fp = GrMagnifierEffect::Make(std::move(inputFP), bounds, srcRect, invXZoom, diff --git a/chromium/third_party/skia/src/effects/imagefilters/SkMorphologyImageFilter.cpp b/chromium/third_party/skia/src/effects/imagefilters/SkMorphologyImageFilter.cpp index 6e024137d6d..35f35d7f8d6 100644 --- a/chromium/third_party/skia/src/effects/imagefilters/SkMorphologyImageFilter.cpp +++ b/chromium/third_party/skia/src/effects/imagefilters/SkMorphologyImageFilter.cpp @@ -20,7 +20,6 @@ #include "include/private/GrRecordingContext.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrCoordTransform.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/GrTexture.h" @@ -229,13 +228,6 @@ public: new GrMorphologyEffect(std::move(view), srcAlphaType, dir, radius, type, bounds)); } - MorphType type() const { return fType; } - bool useRange() const { return fUseRange; } - const float* range() const { return fRange; } - MorphDirection direction() const { return fDirection; } - int radius() const { return fRadius; } - int width() const { return 2 * fRadius + 1; } - const char* name() const override { return "Morphology"; } std::unique_ptr<GrFragmentProcessor> clone() const override { @@ -243,8 +235,9 @@ public: } private: - GrCoordTransform fCoordTransform; - TextureSampler fTextureSampler; + // We really just want the unaltered local coords, but the only way to get that right now is + // an identity coord transform. + GrCoordTransform fCoordTransform = {}; MorphDirection fDirection; int fRadius; MorphType fType; @@ -256,9 +249,6 @@ private: void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - - const TextureSampler& onTextureSampler(int i) const override { return fTextureSampler; } - GrMorphologyEffect(GrSurfaceProxyView, SkAlphaType srcAlphaType, MorphDirection, int radius, MorphType, const float range[2]); explicit GrMorphologyEffect(const GrMorphologyEffect&); @@ -268,138 +258,81 @@ private: typedef GrFragmentProcessor INHERITED; }; -/////////////////////////////////////////////////////////////////////////////// - -class GrGLMorphologyEffect : public GrGLSLFragmentProcessor { -public: - void emitCode(EmitArgs&) override; - - static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*); - -protected: - void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override; - -private: - GrGLSLProgramDataManager::UniformHandle fPixelSizeUni; - GrGLSLProgramDataManager::UniformHandle fRangeUni; - - typedef GrGLSLFragmentProcessor INHERITED; -}; - -void GrGLMorphologyEffect::emitCode(EmitArgs& args) { - const GrMorphologyEffect& me = args.fFp.cast<GrMorphologyEffect>(); - - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; - fPixelSizeUni = uniformHandler->addUniform(&me, kFragment_GrShaderFlag, kHalf_GrSLType, - "PixelSize"); - const char* pixelSizeInc = uniformHandler->getUniformCStr(fPixelSizeUni); - fRangeUni = uniformHandler->addUniform(&me, kFragment_GrShaderFlag, kFloat2_GrSLType, "Range"); - const char* range = uniformHandler->getUniformCStr(fRangeUni); - - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - SkString coords2D = fragBuilder->ensureCoords2D(args.fTransformedCoords[0].fVaryingPoint, - args.fFp.sampleMatrix()); - const char* func; - switch (me.type()) { - case MorphType::kErode: - fragBuilder->codeAppendf("\t\t%s = half4(1, 1, 1, 1);\n", args.fOutputColor); - func = "min"; - break; - case MorphType::kDilate: - fragBuilder->codeAppendf("\t\t%s = half4(0, 0, 0, 0);\n", args.fOutputColor); - func = "max"; - break; - default: - SK_ABORT("Unexpected type"); - func = ""; // suppress warning - break; - } +GrGLSLFragmentProcessor* GrMorphologyEffect::onCreateGLSLInstance() const { + class Impl : public GrGLSLFragmentProcessor { + public: + void emitCode(EmitArgs& args) override { + const GrMorphologyEffect& me = args.fFp.cast<GrMorphologyEffect>(); + + GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; + fRangeUni = uniformHandler->addUniform(&me, kFragment_GrShaderFlag, kFloat2_GrSLType, + "Range"); + const char* range = uniformHandler->getUniformCStr(fRangeUni); + + GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; + SkString coords2D = fragBuilder->ensureCoords2D( + args.fTransformedCoords[0].fVaryingPoint, args.fFp.sampleMatrix()); + + const char* func = me.fType == MorphType::kErode ? "min" : "max"; + + char initialValue = me.fType == MorphType::kErode ? '1' : '0'; + fragBuilder->codeAppendf("%s = half4(%c);", args.fOutputColor, initialValue); + + char dir = me.fDirection == MorphDirection::kX ? 'x' : 'y'; + + int width = 2 * me.fRadius + 1; + + // float2 coord = coord2D; + fragBuilder->codeAppendf("float2 coord = %s;", coords2D.c_str()); + // coord.x -= radius; + fragBuilder->codeAppendf("coord.%c -= %d;", dir, me.fRadius); + if (me.fUseRange) { + // highBound = min(highBound, coord.x + (width-1)); + fragBuilder->codeAppendf("float highBound = min(%s.y, coord.%c + %f);", range, dir, + float(width - 1)); + // coord.x = max(lowBound, coord.x); + fragBuilder->codeAppendf("coord.%c = max(%s.x, coord.%c);", dir, range, dir); + } + fragBuilder->codeAppendf("for (int i = 0; i < %d; i++) {", width); + SkString sample = this->invokeChild(0, args, "coord"); + fragBuilder->codeAppendf(" %s = %s(%s, %s);", args.fOutputColor, func, + args.fOutputColor, sample.c_str()); + // coord.x += 1; + fragBuilder->codeAppendf(" coord.%c += 1;", dir); + if (me.fUseRange) { + // coord.x = min(highBound, coord.x); + fragBuilder->codeAppendf(" coord.%c = min(highBound, coord.%c);", dir, dir); + } + fragBuilder->codeAppend("}"); + fragBuilder->codeAppendf("%s *= %s;", args.fOutputColor, args.fInputColor); + } - const char* dir; - switch (me.direction()) { - case MorphDirection::kX: - dir = "x"; - break; - case MorphDirection::kY: - dir = "y"; - break; - default: - SK_ABORT("Unknown filter direction."); - dir = ""; // suppress warning - } + protected: + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& proc) override { + const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>(); + if (m.fUseRange) { + pdman.set2f(fRangeUni, m.fRange[0], m.fRange[1]); + } + } - int width = me.width(); - - // float2 coord = coord2D; - fragBuilder->codeAppendf("\t\tfloat2 coord = %s;\n", coords2D.c_str()); - // coord.x -= radius * pixelSize; - fragBuilder->codeAppendf("\t\tcoord.%s -= %d.0 * %s; \n", dir, me.radius(), pixelSizeInc); - if (me.useRange()) { - // highBound = min(highBound, coord.x + (width-1) * pixelSize); - fragBuilder->codeAppendf("\t\tfloat highBound = min(%s.y, coord.%s + %f * %s);", - range, dir, float(width - 1), pixelSizeInc); - // coord.x = max(lowBound, coord.x); - fragBuilder->codeAppendf("\t\tcoord.%s = max(%s.x, coord.%s);", dir, range, dir); - } - fragBuilder->codeAppendf("\t\tfor (int i = 0; i < %d; i++) {\n", width); - fragBuilder->codeAppendf("\t\t\t%s = %s(%s, ", args.fOutputColor, func, args.fOutputColor); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], "coord"); - fragBuilder->codeAppend(");\n"); - // coord.x += pixelSize; - fragBuilder->codeAppendf("\t\t\tcoord.%s += %s;\n", dir, pixelSizeInc); - if (me.useRange()) { - // coord.x = min(highBound, coord.x); - fragBuilder->codeAppendf("\t\t\tcoord.%s = min(highBound, coord.%s);", dir, dir); - } - fragBuilder->codeAppend("\t\t}\n"); - fragBuilder->codeAppendf("%s *= %s;\n", args.fOutputColor, args.fInputColor); + private: + GrGLSLProgramDataManager::UniformHandle fRangeUni; + }; + return new Impl; } -void GrGLMorphologyEffect::GenKey(const GrProcessor& proc, - const GrShaderCaps&, GrProcessorKeyBuilder* b) { - const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>(); - uint32_t key = static_cast<uint32_t>(m.radius()); - key |= (static_cast<uint32_t>(m.type()) << 8); - key |= (static_cast<uint32_t>(m.direction()) << 9); - if (m.useRange()) { +void GrMorphologyEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const { + uint32_t key = static_cast<uint32_t>(fRadius); + key |= (static_cast<uint32_t>(fType) << 8); + key |= (static_cast<uint32_t>(fDirection) << 9); + if (fUseRange) { key |= 1 << 10; } b->add32(key); } -void GrGLMorphologyEffect::onSetData(const GrGLSLProgramDataManager& pdman, - const GrFragmentProcessor& proc) { - const GrMorphologyEffect& m = proc.cast<GrMorphologyEffect>(); - const auto& view = m.textureSampler(0).view(); - GrSurfaceProxy* proxy = view.proxy(); - GrTexture& texture = *proxy->peekTexture(); - - float pixelSize = 0.0f; - switch (m.direction()) { - case MorphDirection::kX: - pixelSize = 1.0f / texture.width(); - break; - case MorphDirection::kY: - pixelSize = 1.0f / texture.height(); - break; - default: - SK_ABORT("Unknown filter direction."); - } - pdman.set1f(fPixelSizeUni, pixelSize); - - if (m.useRange()) { - const float* range = m.range(); - if (MorphDirection::kY == m.direction() && - view.origin() == kBottomLeft_GrSurfaceOrigin) { - pdman.set2f(fRangeUni, 1.0f - (range[1]*pixelSize), 1.0f - (range[0]*pixelSize)); - } else { - pdman.set2f(fRangeUni, range[0] * pixelSize, range[1] * pixelSize); - } - } -} - -/////////////////////////////////////////////////////////////////////////////// - GrMorphologyEffect::GrMorphologyEffect(GrSurfaceProxyView view, SkAlphaType srcAlphaType, MorphDirection direction, @@ -407,17 +340,13 @@ GrMorphologyEffect::GrMorphologyEffect(GrSurfaceProxyView view, MorphType type, const float range[2]) : INHERITED(kGrMorphologyEffect_ClassID, ModulateForClampedSamplerOptFlags(srcAlphaType)) - , fCoordTransform(view.proxy(), view.origin()) - , fTextureSampler(std::move(view)) , fDirection(direction) , fRadius(radius) , fType(type) , fUseRange(SkToBool(range)) { - // Make sure the sampler's ctor uses the clamp wrap mode - SkASSERT(fTextureSampler.samplerState().wrapModeX() == GrSamplerState::WrapMode::kClamp && - fTextureSampler.samplerState().wrapModeY() == GrSamplerState::WrapMode::kClamp); this->addCoordTransform(&fCoordTransform); - this->setTextureSamplerCnt(1); + auto te = GrTextureEffect::Make(std::move(view), srcAlphaType); + this->registerExplicitlySampledChild(std::move(te)); if (fUseRange) { fRange[0] = range[0]; fRange[1] = range[1]; @@ -426,34 +355,24 @@ GrMorphologyEffect::GrMorphologyEffect(GrSurfaceProxyView view, GrMorphologyEffect::GrMorphologyEffect(const GrMorphologyEffect& that) : INHERITED(kGrMorphologyEffect_ClassID, that.optimizationFlags()) - , fCoordTransform(that.fCoordTransform) - , fTextureSampler(that.fTextureSampler) , fDirection(that.fDirection) , fRadius(that.fRadius) , fType(that.fType) , fUseRange(that.fUseRange) { this->addCoordTransform(&fCoordTransform); - this->setTextureSamplerCnt(1); + this->cloneAndRegisterAllChildProcessors(that); if (that.fUseRange) { fRange[0] = that.fRange[0]; fRange[1] = that.fRange[1]; } } -void GrMorphologyEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const { - GrGLMorphologyEffect::GenKey(*this, caps, b); -} - -GrGLSLFragmentProcessor* GrMorphologyEffect::onCreateGLSLInstance() const { - return new GrGLMorphologyEffect; -} bool GrMorphologyEffect::onIsEqual(const GrFragmentProcessor& sBase) const { const GrMorphologyEffect& s = sBase.cast<GrMorphologyEffect>(); - return (this->radius() == s.radius() && - this->direction() == s.direction() && - this->useRange() == s.useRange() && - this->type() == s.type()); + return this->fRadius == s.fRadius && + this->fDirection == s.fDirection && + this->fUseRange == s.fUseRange && + this->fType == s.fType; } /////////////////////////////////////////////////////////////////////////////// @@ -473,7 +392,6 @@ std::unique_ptr<GrFragmentProcessor> GrMorphologyEffect::TestCreate(GrProcessorT #endif static void apply_morphology_rect(GrRenderTargetContext* renderTargetContext, - const GrClip& clip, GrSurfaceProxyView view, SkAlphaType srcAlphaType, const SkIRect& srcRect, @@ -486,12 +404,11 @@ static void apply_morphology_rect(GrRenderTargetContext* renderTargetContext, paint.addColorFragmentProcessor(GrMorphologyEffect::Make(std::move(view), srcAlphaType, direction, radius, morphType, bounds)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + renderTargetContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::Make(dstRect), SkRect::Make(srcRect)); } static void apply_morphology_rect_no_bounds(GrRenderTargetContext* renderTargetContext, - const GrClip& clip, GrSurfaceProxyView view, SkAlphaType srcAlphaType, const SkIRect& srcRect, @@ -503,12 +420,11 @@ static void apply_morphology_rect_no_bounds(GrRenderTargetContext* renderTargetC paint.addColorFragmentProcessor( GrMorphologyEffect::Make(std::move(view), srcAlphaType, direction, radius, morphType)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - renderTargetContext->fillRectToRect(clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + renderTargetContext->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::Make(dstRect), SkRect::Make(srcRect)); } static void apply_morphology_pass(GrRenderTargetContext* renderTargetContext, - const GrClip& clip, GrSurfaceProxyView view, SkAlphaType srcAlphaType, const SkIRect& srcRect, @@ -541,17 +457,16 @@ static void apply_morphology_pass(GrRenderTargetContext* renderTargetContext, } if (middleSrcRect.width() <= 0) { // radius covers srcRect; use bounds over entire draw - apply_morphology_rect(renderTargetContext, clip, std::move(view), srcAlphaType, srcRect, + apply_morphology_rect(renderTargetContext, std::move(view), srcAlphaType, srcRect, dstRect, radius, morphType, bounds, direction); } else { // Draw upper and lower margins with bounds; middle without. - apply_morphology_rect(renderTargetContext, clip, view, srcAlphaType, lowerSrcRect, + apply_morphology_rect(renderTargetContext, view, srcAlphaType, lowerSrcRect, lowerDstRect, radius, morphType, bounds, direction); - apply_morphology_rect(renderTargetContext, clip, view, srcAlphaType, upperSrcRect, + apply_morphology_rect(renderTargetContext, view, srcAlphaType, upperSrcRect, upperDstRect, radius, morphType, bounds, direction); - apply_morphology_rect_no_bounds(renderTargetContext, clip, std::move(view), - srcAlphaType, middleSrcRect, middleDstRect, radius, - morphType, direction); + apply_morphology_rect_no_bounds(renderTargetContext, std::move(view), srcAlphaType, + middleSrcRect, middleDstRect, radius, morphType, direction); } } @@ -566,9 +481,6 @@ static sk_sp<SkSpecialImage> apply_morphology( GrSurfaceProxy* proxy = srcView.proxy(); - // setup new clip - const GrFixedClip clip(SkIRect::MakeSize(proxy->dimensions())); - const SkIRect dstRect = SkIRect::MakeWH(rect.width(), rect.height()); SkIRect srcRect = rect; // Map into proxy space @@ -583,13 +495,13 @@ static sk_sp<SkSpecialImage> apply_morphology( return nullptr; } - apply_morphology_pass(dstRTContext.get(), clip, std::move(srcView), srcAlphaType, + apply_morphology_pass(dstRTContext.get(), std::move(srcView), srcAlphaType, srcRect, dstRect, radius.fWidth, morphType, MorphDirection::kX); SkIRect clearRect = SkIRect::MakeXYWH(dstRect.fLeft, dstRect.fBottom, dstRect.width(), radius.fHeight); SkPMColor4f clearColor = MorphType::kErode == morphType ? SK_PMColor4fWHITE : SK_PMColor4fTRANSPARENT; - dstRTContext->clear(&clearRect, clearColor, GrRenderTargetContext::CanClearFullscreen::kNo); + dstRTContext->clear(clearRect, clearColor); srcView = dstRTContext->readSurfaceView(); srcAlphaType = dstRTContext->colorInfo().alphaType(); @@ -603,7 +515,7 @@ static sk_sp<SkSpecialImage> apply_morphology( return nullptr; } - apply_morphology_pass(dstRTContext.get(), clip, std::move(srcView), srcAlphaType, + apply_morphology_pass(dstRTContext.get(), std::move(srcView), srcAlphaType, srcRect, dstRect, radius.fHeight, morphType, MorphDirection::kY); srcView = dstRTContext->readSurfaceView(); diff --git a/chromium/third_party/skia/src/effects/imagefilters/SkXfermodeImageFilter.cpp b/chromium/third_party/skia/src/effects/imagefilters/SkXfermodeImageFilter.cpp index 84a2764e2c4..7569e1726e4 100644 --- a/chromium/third_party/skia/src/effects/imagefilters/SkXfermodeImageFilter.cpp +++ b/chromium/third_party/skia/src/effects/imagefilters/SkXfermodeImageFilter.cpp @@ -17,7 +17,6 @@ #if SK_SUPPORT_GPU #include "include/private/GrRecordingContext.h" #include "src/gpu/GrCaps.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrColorSpaceXform.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRenderTargetContext.h" @@ -264,7 +263,7 @@ sk_sp<SkSpecialImage> SkXfermodeImageFilterImpl::filterImageGPU( if (backgroundView.asTextureProxy()) { SkRect bgSubset = SkRect::Make(background->subset()); - SkMatrix bgMatrix = SkMatrix::MakeTrans( + SkMatrix bgMatrix = SkMatrix::Translate( SkIntToScalar(bgSubset.left() - backgroundOffset.fX), SkIntToScalar(bgSubset.top() - backgroundOffset.fY)); bgFP = GrTextureEffect::MakeSubset(std::move(backgroundView), background->alphaType(), @@ -273,13 +272,13 @@ sk_sp<SkSpecialImage> SkXfermodeImageFilterImpl::filterImageGPU( background->alphaType(), ctx.colorSpace()); } else { - bgFP = GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT, + bgFP = GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT, GrConstColorProcessor::InputMode::kIgnore); } if (foregroundView.asTextureProxy()) { SkRect fgSubset = SkRect::Make(foreground->subset()); - SkMatrix fgMatrix = SkMatrix::MakeTrans( + SkMatrix fgMatrix = SkMatrix::Translate( SkIntToScalar(fgSubset.left() - foregroundOffset.fX), SkIntToScalar(fgSubset.top() - foregroundOffset.fY)); auto fgFP = GrTextureEffect::MakeSubset(std::move(foregroundView), foreground->alphaType(), @@ -310,7 +309,7 @@ sk_sp<SkSpecialImage> SkXfermodeImageFilterImpl::filterImageGPU( SkMatrix matrix; matrix.setTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top())); - renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, + renderTargetContext->drawRect(nullptr, std::move(paint), GrAA::kNo, matrix, SkRect::Make(bounds)); return SkSpecialImage::MakeDeferredFromGpu(context, diff --git a/chromium/third_party/skia/src/gpu/GrAHardwareBufferUtils.cpp b/chromium/third_party/skia/src/gpu/GrAHardwareBufferUtils.cpp index b701dafb3bf..badb8eee5a6 100644 --- a/chromium/third_party/skia/src/gpu/GrAHardwareBufferUtils.cpp +++ b/chromium/third_party/skia/src/gpu/GrAHardwareBufferUtils.cpp @@ -486,6 +486,7 @@ static GrBackendTexture make_vk_backend_texture( // "foreign" device we can leave them as external. imageInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_EXTERNAL; imageInfo.fYcbcrConversionInfo = *ycbcrConversion; + imageInfo.fSharingMode = imageCreateInfo.sharingMode; *deleteProc = delete_vk_image; *updateProc = update_vk_image; diff --git a/chromium/third_party/skia/src/gpu/GrAppliedClip.h b/chromium/third_party/skia/src/gpu/GrAppliedClip.h index 594a627987d..75e614a659a 100644 --- a/chromium/third_party/skia/src/gpu/GrAppliedClip.h +++ b/chromium/third_party/skia/src/gpu/GrAppliedClip.h @@ -22,11 +22,19 @@ class GrAppliedHardClip { public: static const GrAppliedHardClip& Disabled() { - static GrAppliedHardClip kDisabled; + // The size doesn't really matter here since it's returned as const& so an actual scissor + // will never be set on it, and applied clips are not used to query or bounds test like + // the GrClip is. + static const GrAppliedHardClip kDisabled({1 << 29, 1 << 29}); return kDisabled; } - GrAppliedHardClip() = default; + GrAppliedHardClip(const SkISize& rtDims) : fScissorState(rtDims) {} + GrAppliedHardClip(const SkISize& logicalRTDims, const SkISize& backingStoreDims) + : fScissorState(backingStoreDims) { + fScissorState.set(SkIRect::MakeSize(logicalRTDims)); + } + GrAppliedHardClip(GrAppliedHardClip&& that) = default; GrAppliedHardClip(const GrAppliedHardClip&) = delete; @@ -81,7 +89,14 @@ private: */ class GrAppliedClip { public: - GrAppliedClip() = default; + static GrAppliedClip Disabled() { + return GrAppliedClip({1 << 29, 1 << 29}); + } + + GrAppliedClip(const SkISize& rtDims) : fHardClip(rtDims) {} + GrAppliedClip(const SkISize& logicalRTDims, const SkISize& backingStoreDims) + : fHardClip(logicalRTDims, backingStoreDims) {} + GrAppliedClip(GrAppliedClip&& that) = default; GrAppliedClip(const GrAppliedClip&) = delete; diff --git a/chromium/third_party/skia/src/gpu/GrBackendSurface.cpp b/chromium/third_party/skia/src/gpu/GrBackendSurface.cpp index 8f07bb1ee22..a1e0203ff46 100644 --- a/chromium/third_party/skia/src/gpu/GrBackendSurface.cpp +++ b/chromium/third_party/skia/src/gpu/GrBackendSurface.cpp @@ -7,6 +7,7 @@ #include "include/gpu/GrBackendSurface.h" +#include "src/gpu/GrBackendSurfaceMutableStateImpl.h" #include "src/gpu/gl/GrGLUtil.h" #ifdef SK_DAWN @@ -386,6 +387,8 @@ SkString GrBackendFormat::toStr() const { #endif /////////////////////////////////////////////////////////////////////////////////////////////////// +GrBackendTexture::GrBackendTexture() : fIsValid(false) {} + #ifdef SK_DAWN GrBackendTexture::GrBackendTexture(int width, int height, @@ -398,12 +401,24 @@ GrBackendTexture::GrBackendTexture(int width, , fDawnInfo(dawnInfo) {} #endif -GrBackendTexture::GrBackendTexture(int width, int height, const GrVkImageInfo& vkInfo) #ifdef SK_VULKAN +GrBackendTexture::GrBackendTexture(int width, int height, const GrVkImageInfo& vkInfo) : GrBackendTexture(width, height, vkInfo, - sk_sp<GrVkImageLayout>(new GrVkImageLayout(vkInfo.fImageLayout))) {} -#else - : fIsValid(false) {} + sk_sp<GrBackendSurfaceMutableStateImpl>( + new GrBackendSurfaceMutableStateImpl( + vkInfo.fImageLayout, vkInfo.fCurrentQueueFamily))) {} + +GrBackendTexture::GrBackendTexture(int width, + int height, + const GrVkImageInfo& vkInfo, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) + : fIsValid(true) + , fWidth(width) + , fHeight(height) + , fMipMapped(GrMipMapped(vkInfo.fLevelCount > 1)) + , fBackend(GrBackendApi::kVulkan) + , fVkInfo(vkInfo) + , fMutableState(std::move(mutableState)) {} #endif #ifdef SK_GL @@ -427,19 +442,6 @@ sk_sp<GrGLTextureParameters> GrBackendTexture::getGLTextureParams() const { } #endif -#ifdef SK_VULKAN -GrBackendTexture::GrBackendTexture(int width, - int height, - const GrVkImageInfo& vkInfo, - sk_sp<GrVkImageLayout> layout) - : fIsValid(true) - , fWidth(width) - , fHeight(height) - , fMipMapped(GrMipMapped(vkInfo.fLevelCount > 1)) - , fBackend(GrBackendApi::kVulkan) - , fVkInfo(vkInfo, layout.release()) {} -#endif - #ifdef SK_METAL GrBackendTexture::GrBackendTexture(int width, int height, @@ -566,10 +568,15 @@ GrBackendTexture& GrBackendTexture::operator=(const GrBackendTexture& that) { default: SK_ABORT("Unknown GrBackend"); } + fMutableState = that.fMutableState; fIsValid = true; return *this; } +sk_sp<GrBackendSurfaceMutableStateImpl> GrBackendTexture::getMutableState() const { + return fMutableState; +} + #ifdef SK_DAWN bool GrBackendTexture::getDawnTextureInfo(GrDawnTextureInfo* outInfo) const { if (this->isValid() && GrBackendApi::kDawn == fBackend) { @@ -583,7 +590,7 @@ bool GrBackendTexture::getDawnTextureInfo(GrDawnTextureInfo* outInfo) const { bool GrBackendTexture::getVkImageInfo(GrVkImageInfo* outInfo) const { #ifdef SK_VULKAN if (this->isValid() && GrBackendApi::kVulkan == fBackend) { - *outInfo = fVkInfo.snapImageInfo(); + *outInfo = fVkInfo.snapImageInfo(fMutableState.get()); return true; } #endif @@ -593,20 +600,11 @@ bool GrBackendTexture::getVkImageInfo(GrVkImageInfo* outInfo) const { void GrBackendTexture::setVkImageLayout(VkImageLayout layout) { #ifdef SK_VULKAN if (this->isValid() && GrBackendApi::kVulkan == fBackend) { - fVkInfo.setImageLayout(layout); + fMutableState->setImageLayout(layout); } #endif } -#ifdef SK_VULKAN -sk_sp<GrVkImageLayout> GrBackendTexture::getGrVkImageLayout() const { - if (this->isValid() && GrBackendApi::kVulkan == fBackend) { - return fVkInfo.getGrVkImageLayout(); - } - return nullptr; -} -#endif - #ifdef SK_METAL bool GrBackendTexture::getMtlTextureInfo(GrMtlTextureInfo* outInfo) const { if (this->isValid() && GrBackendApi::kMetal == fBackend) { @@ -674,6 +672,10 @@ bool GrBackendTexture::getMockTextureInfo(GrMockTextureInfo* outInfo) const { return false; } +void GrBackendTexture::setMutableState(const GrBackendSurfaceMutableState& state) { + fMutableState->set(state); +} + bool GrBackendTexture::isProtected() const { if (!this->isValid() || this->backend() != GrBackendApi::kVulkan) { return false; @@ -695,7 +697,8 @@ bool GrBackendTexture::isSameTexture(const GrBackendTexture& that) { #endif #ifdef SK_VULKAN case GrBackendApi::kVulkan: - return fVkInfo.snapImageInfo().fImage == that.fVkInfo.snapImageInfo().fImage; + return fVkInfo.snapImageInfo(fMutableState.get()).fImage == + that.fVkInfo.snapImageInfo(that.fMutableState.get()).fImage; #endif #ifdef SK_METAL case GrBackendApi::kMetal: @@ -703,7 +706,13 @@ bool GrBackendTexture::isSameTexture(const GrBackendTexture& that) { #endif #ifdef SK_DIRECT3D case GrBackendApi::kDirect3D: - return false; //TODO + return fD3DInfo.snapTextureResourceInfo().fResource == + that.fD3DInfo.snapTextureResourceInfo().fResource; +#endif +#ifdef SK_DAWN + case GrBackendApi::kDawn: { + return this->fDawnInfo.fTexture.Get() == that.fDawnInfo.fTexture.Get(); + } #endif case GrBackendApi::kMock: return fMockInfo.id() == that.fMockInfo.id(); @@ -723,7 +732,7 @@ GrBackendFormat GrBackendTexture::getBackendFormat() const { #endif #ifdef SK_VULKAN case GrBackendApi::kVulkan: { - auto info = fVkInfo.snapImageInfo(); + auto info = fVkInfo.snapImageInfo(fMutableState.get()); if (info.fYcbcrConversionInfo.isValid()) { SkASSERT(info.fFormat == info.fYcbcrConversionInfo.fFormat); return GrBackendFormat::MakeVk(info.fYcbcrConversionInfo); @@ -769,6 +778,12 @@ bool GrBackendTexture::TestingOnly_Equals(const GrBackendTexture& t0, const GrBa return false; } + // For our tests when checking equality we are assuming the both backendTexture objects will + // be using the same mutable state object. + if (t0.fMutableState != t1.fMutableState) { + return false; + } + switch (t0.fBackend) { #ifdef SK_GL case GrBackendApi::kOpenGL: @@ -800,6 +815,9 @@ bool GrBackendTexture::TestingOnly_Equals(const GrBackendTexture& t0, const GrBa //////////////////////////////////////////////////////////////////////////////////////////////////// +GrBackendRenderTarget::GrBackendRenderTarget() : fIsValid(false) {} + + #ifdef SK_DAWN GrBackendRenderTarget::GrBackendRenderTarget(int width, int height, @@ -816,6 +834,7 @@ GrBackendRenderTarget::GrBackendRenderTarget(int width, , fDawnInfo(dawnInfo) {} #endif +#ifdef SK_VULKAN GrBackendRenderTarget::GrBackendRenderTarget(int width, int height, int sampleCnt, @@ -830,26 +849,24 @@ GrBackendRenderTarget::GrBackendRenderTarget(int width, int height, int sampleCnt, const GrVkImageInfo& vkInfo) -#ifdef SK_VULKAN : GrBackendRenderTarget(width, height, sampleCnt, vkInfo, - sk_sp<GrVkImageLayout>(new GrVkImageLayout(vkInfo.fImageLayout))) {} -#else - : fIsValid(false) {} -#endif + sk_sp<GrBackendSurfaceMutableStateImpl>( + new GrBackendSurfaceMutableStateImpl( + vkInfo.fImageLayout, vkInfo.fCurrentQueueFamily))) {} -#ifdef SK_VULKAN GrBackendRenderTarget::GrBackendRenderTarget(int width, int height, int sampleCnt, const GrVkImageInfo& vkInfo, - sk_sp<GrVkImageLayout> layout) + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) : fIsValid(true) , fWidth(width) , fHeight(height) , fSampleCnt(std::max(1, sampleCnt)) , fStencilBits(0) // We always create stencil buffers internally for vulkan , fBackend(GrBackendApi::kVulkan) - , fVkInfo(vkInfo, layout.release()) {} + , fVkInfo(vkInfo) + , fMutableState(mutableState) {} #endif #ifdef SK_METAL @@ -926,6 +943,11 @@ void GrBackendRenderTarget::cleanup() { fVkInfo.cleanup(); } #endif +#ifdef SK_DIRECT3D + if (this->isValid() && GrBackendApi::kDirect3D == fBackend) { + fD3DInfo.cleanup(); + } +#endif } GrBackendRenderTarget::GrBackendRenderTarget(const GrBackendRenderTarget& that) : fIsValid(false) { @@ -979,10 +1001,15 @@ GrBackendRenderTarget& GrBackendRenderTarget::operator=(const GrBackendRenderTar default: SK_ABORT("Unknown GrBackend"); } + fMutableState = that.fMutableState; fIsValid = that.fIsValid; return *this; } +sk_sp<GrBackendSurfaceMutableStateImpl> GrBackendRenderTarget::getMutableState() const { + return fMutableState; +} + #ifdef SK_DAWN bool GrBackendRenderTarget::getDawnRenderTargetInfo(GrDawnRenderTargetInfo* outInfo) const { if (this->isValid() && GrBackendApi::kDawn == fBackend) { @@ -996,7 +1023,7 @@ bool GrBackendRenderTarget::getDawnRenderTargetInfo(GrDawnRenderTargetInfo* outI bool GrBackendRenderTarget::getVkImageInfo(GrVkImageInfo* outInfo) const { #ifdef SK_VULKAN if (this->isValid() && GrBackendApi::kVulkan == fBackend) { - *outInfo = fVkInfo.snapImageInfo(); + *outInfo = fVkInfo.snapImageInfo(fMutableState.get()); return true; } #endif @@ -1006,20 +1033,11 @@ bool GrBackendRenderTarget::getVkImageInfo(GrVkImageInfo* outInfo) const { void GrBackendRenderTarget::setVkImageLayout(VkImageLayout layout) { #ifdef SK_VULKAN if (this->isValid() && GrBackendApi::kVulkan == fBackend) { - fVkInfo.setImageLayout(layout); + fMutableState->setImageLayout(layout); } #endif } -#ifdef SK_VULKAN -sk_sp<GrVkImageLayout> GrBackendRenderTarget::getGrVkImageLayout() const { - if (this->isValid() && GrBackendApi::kVulkan == fBackend) { - return fVkInfo.getGrVkImageLayout(); - } - return nullptr; -} -#endif - #ifdef SK_METAL bool GrBackendRenderTarget::getMtlTextureInfo(GrMtlTextureInfo* outInfo) const { if (this->isValid() && GrBackendApi::kMetal == fBackend) { @@ -1074,7 +1092,7 @@ GrBackendFormat GrBackendRenderTarget::getBackendFormat() const { #endif #ifdef SK_VULKAN case GrBackendApi::kVulkan: { - auto info = fVkInfo.snapImageInfo(); + auto info = fVkInfo.snapImageInfo(fMutableState.get()); if (info.fYcbcrConversionInfo.isValid()) { SkASSERT(info.fFormat == info.fYcbcrConversionInfo.fFormat); return GrBackendFormat::MakeVk(info.fYcbcrConversionInfo); @@ -1117,6 +1135,10 @@ bool GrBackendRenderTarget::getMockRenderTargetInfo(GrMockRenderTargetInfo* outI return false; } +void GrBackendRenderTarget::setMutableState(const GrBackendSurfaceMutableState& state) { + fMutableState->set(state); +} + bool GrBackendRenderTarget::isProtected() const { if (!this->isValid() || this->backend() != GrBackendApi::kVulkan) { return false; diff --git a/chromium/third_party/skia/src/gpu/GrBackendSurfaceMutableStateImpl.h b/chromium/third_party/skia/src/gpu/GrBackendSurfaceMutableStateImpl.h new file mode 100644 index 00000000000..3e3bc92f4e4 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/GrBackendSurfaceMutableStateImpl.h @@ -0,0 +1,58 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrBackendSurfaceMutableStateImpl_DEFINED +#define GrBackendSurfaceMutableStateImpl_DEFINED + +#include "include/core/SkRefCnt.h" +#include "include/gpu/GrBackendSurfaceMutableState.h" + +class GrBackendSurfaceMutableStateImpl : public SkRefCnt { +public: +#ifdef SK_VULKAN + GrBackendSurfaceMutableStateImpl(VkImageLayout layout, uint32_t queueFamilyIndex) + : fState(layout, queueFamilyIndex) {} + + GrBackendSurfaceMutableStateImpl(GrVkSharedImageInfo sharedInfo) + : fState(sharedInfo.getImageLayout(), sharedInfo.getQueueFamilyIndex()) {} +#endif + + void set(const GrBackendSurfaceMutableState& state) { fState = state; } + +#ifdef SK_VULKAN + VkImageLayout getImageLayout() const { + SkASSERT(fState.fBackend == GrBackend::kVulkan); + return fState.fVkState.getImageLayout(); + } + + void setImageLayout(VkImageLayout layout) { + SkASSERT(fState.fBackend == GrBackend::kVulkan); + fState.fVkState.setImageLayout(layout); + } + + uint32_t getQueueFamilyIndex() const { + SkASSERT(fState.fBackend == GrBackend::kVulkan); + return fState.fVkState.getQueueFamilyIndex(); + } + + void setQueueFamilyIndex(uint32_t queueFamilyIndex) { + SkASSERT(fState.fBackend == GrBackend::kVulkan); + fState.fVkState.setQueueFamilyIndex(queueFamilyIndex); + } + + const GrVkSharedImageInfo& getVkSharedImageInfo() { + SkASSERT(fState.fBackend == GrBackend::kVulkan); + return fState.fVkState; + } +#endif + + +private: + GrBackendSurfaceMutableState fState; +}; + +#endif diff --git a/chromium/third_party/skia/src/gpu/GrBackendUtils.h b/chromium/third_party/skia/src/gpu/GrBackendUtils.h new file mode 100644 index 00000000000..cfbcb0ea302 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/GrBackendUtils.h @@ -0,0 +1,85 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrBackendUtils_DEFINED +#define GrBackendUtils_DEFINED + +#include "include/core/SkImage.h" + +#include "include/gpu/GrBackendSurface.h" + +#ifdef SK_METAL +#include "src/gpu/mtl/GrMtlCppUtil.h" +#endif + +static SkImage::CompressionType GrBackendFormatToCompressionType(const GrBackendFormat& format) { + switch (format.backend()) { + case GrBackendApi::kOpenGL: { +#ifdef SK_GL + GrGLFormat glFormat = format.asGLFormat(); + switch (glFormat) { + case GrGLFormat::kCOMPRESSED_ETC1_RGB8: + case GrGLFormat::kCOMPRESSED_RGB8_ETC2: + return SkImage::CompressionType::kETC2_RGB8_UNORM; + case GrGLFormat::kCOMPRESSED_RGB8_BC1: + return SkImage::CompressionType::kBC1_RGB8_UNORM; + case GrGLFormat::kCOMPRESSED_RGBA8_BC1: + return SkImage::CompressionType::kBC1_RGBA8_UNORM; + default: + return SkImage::CompressionType::kNone; + } +#endif + break; + } + case GrBackendApi::kVulkan: { +#ifdef SK_VULKAN + VkFormat vkFormat; + SkAssertResult(format.asVkFormat(&vkFormat)); + switch (vkFormat) { + case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: + return SkImage::CompressionType::kETC2_RGB8_UNORM; + case VK_FORMAT_BC1_RGB_UNORM_BLOCK: + return SkImage::CompressionType::kBC1_RGB8_UNORM; + case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: + return SkImage::CompressionType::kBC1_RGBA8_UNORM; + default: + return SkImage::CompressionType::kNone; + } +#endif + break; + } + case GrBackendApi::kMetal: { +#ifdef SK_METAL + return GrMtlBackendFormatToCompressionType(format); +#endif + break; + } + case GrBackendApi::kDirect3D: { +#ifdef SK_DIRECT3D + DXGI_FORMAT dxgiFormat; + SkAssertResult(format.asDxgiFormat(&dxgiFormat)); + switch (dxgiFormat) { + case DXGI_FORMAT_BC1_UNORM: + return SkImage::CompressionType::kBC1_RGBA8_UNORM; + default: + return SkImage::CompressionType::kNone; + } +#endif + break; + } + case GrBackendApi::kDawn: { + return SkImage::CompressionType::kNone; + } + case GrBackendApi::kMock: { + return format.asMockCompressionType(); + } + } + return SkImage::CompressionType::kNone; +} + +#endif + diff --git a/chromium/third_party/skia/src/gpu/GrBlockAllocator.h b/chromium/third_party/skia/src/gpu/GrBlockAllocator.h index fae9dabbf20..b683d7825eb 100644 --- a/chromium/third_party/skia/src/gpu/GrBlockAllocator.h +++ b/chromium/third_party/skia/src/gpu/GrBlockAllocator.h @@ -436,7 +436,7 @@ GrBlockAllocator::ByteRange GrBlockAllocator::allocate(size_t size) { <= std::numeric_limits<int32_t>::max()); if (size > kMaxAllocationSize) { - SK_ABORT("Allocation too large"); + SK_ABORT("Allocation too large (%zu bytes requested)", size); } int iSize = (int) size; diff --git a/chromium/third_party/skia/src/gpu/GrBlurUtils.cpp b/chromium/third_party/skia/src/gpu/GrBlurUtils.cpp index 66c145da008..084e8ef8b98 100644 --- a/chromium/third_party/skia/src/gpu/GrBlurUtils.cpp +++ b/chromium/third_party/skia/src/gpu/GrBlurUtils.cpp @@ -43,7 +43,7 @@ static GrSurfaceProxyView find_filtered_mask(GrProxyProvider* provider, const Gr // is already burnt into the mask this boils down to a rect draw. // Return true if the mask was successfully drawn. static bool draw_mask(GrRenderTargetContext* renderTargetContext, - const GrClip& clip, + const GrClip* clip, const SkMatrix& viewMatrix, const SkIRect& maskRect, GrPaint&& paint, @@ -53,7 +53,7 @@ static bool draw_mask(GrRenderTargetContext* renderTargetContext, return false; } - SkMatrix matrix = SkMatrix::MakeTrans(-SkIntToScalar(maskRect.fLeft), + SkMatrix matrix = SkMatrix::Translate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop)); matrix.preConcat(viewMatrix); paint.addCoverageFragmentProcessor( @@ -70,7 +70,7 @@ static void mask_release_proc(void* addr, void* /*context*/) { static bool sw_draw_with_mask_filter(GrRecordingContext* context, GrRenderTargetContext* renderTargetContext, - const GrClip& clipData, + const GrClip* clipData, const SkMatrix& viewMatrix, const GrStyledShape& shape, const SkMaskFilter* filter, @@ -200,14 +200,13 @@ static std::unique_ptr<GrRenderTargetContext> create_mask_GPU(GrRecordingContext maskPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); // setup new clip - const SkIRect clipRect = SkIRect::MakeWH(maskRect.width(), maskRect.height()); - GrFixedClip clip(clipRect); + GrFixedClip clip(rtContext->dimensions(), SkIRect::MakeWH(maskRect.width(), maskRect.height())); // Draw the mask into maskTexture with the path's integerized top-left at the origin using // maskPaint. SkMatrix viewMatrix = origViewMatrix; viewMatrix.postTranslate(-SkIntToScalar(maskRect.fLeft), -SkIntToScalar(maskRect.fTop)); - rtContext->drawShape(clip, std::move(maskPaint), GrAA::kYes, viewMatrix, shape); + rtContext->drawShape(&clip, std::move(maskPaint), GrAA::kYes, viewMatrix, shape); return rtContext; } @@ -239,14 +238,15 @@ static bool get_unclipped_shape_dev_bounds(const GrStyledShape& shape, const SkM // Gets the shape bounds, the clip bounds, and the intersection (if any). Returns false if there // is no intersection. static bool get_shape_and_clip_bounds(GrRenderTargetContext* renderTargetContext, - const GrClip& clip, + const GrClip* clip, const GrStyledShape& shape, const SkMatrix& matrix, SkIRect* unclippedDevShapeBounds, SkIRect* devClipBounds) { // compute bounds as intersection of rt size, clip, and path - *devClipBounds = clip.getConservativeBounds(renderTargetContext->width(), - renderTargetContext->height()); + *devClipBounds = clip ? clip->getConservativeBounds() + : SkIRect::MakeWH(renderTargetContext->width(), + renderTargetContext->height()); if (!get_unclipped_shape_dev_bounds(shape, matrix, unclippedDevShapeBounds)) { *unclippedDevShapeBounds = SkIRect::MakeEmpty(); @@ -258,7 +258,7 @@ static bool get_shape_and_clip_bounds(GrRenderTargetContext* renderTargetContext static void draw_shape_with_mask_filter(GrRecordingContext* context, GrRenderTargetContext* renderTargetContext, - const GrClip& clip, + const GrClip* clip, GrPaint&& paint, const SkMatrix& viewMatrix, const SkMaskFilterBase* maskFilter, @@ -282,12 +282,8 @@ static void draw_shape_with_mask_filter(GrRecordingContext* context, shape = tmpShape.get(); } - if (maskFilter->directFilterMaskGPU(context, - renderTargetContext, - std::move(paint), - clip, - viewMatrix, - *shape)) { + if (maskFilter->directFilterMaskGPU(context, renderTargetContext, std::move(paint), clip, + viewMatrix, *shape)) { // the mask filter was able to draw itself directly, so there's nothing // left to do. return; @@ -301,8 +297,7 @@ static void draw_shape_with_mask_filter(GrRecordingContext* context, SkIRect unclippedDevShapeBounds, devClipBounds; if (!get_shape_and_clip_bounds(renderTargetContext, clip, *shape, viewMatrix, - &unclippedDevShapeBounds, - &devClipBounds)) { + &unclippedDevShapeBounds, &devClipBounds)) { // TODO: just cons up an opaque mask here if (!inverseFilled) { return; @@ -439,7 +434,7 @@ static void draw_shape_with_mask_filter(GrRecordingContext* context, void GrBlurUtils::drawShapeWithMaskFilter(GrRecordingContext* context, GrRenderTargetContext* renderTargetContext, - const GrClip& clip, + const GrClip* clip, const GrStyledShape& shape, GrPaint&& paint, const SkMatrix& viewMatrix, @@ -450,7 +445,7 @@ void GrBlurUtils::drawShapeWithMaskFilter(GrRecordingContext* context, void GrBlurUtils::drawShapeWithMaskFilter(GrRecordingContext* context, GrRenderTargetContext* renderTargetContext, - const GrClip& clip, + const GrClip* clip, const SkPaint& paint, const SkMatrixProvider& matrixProvider, const GrStyledShape& shape) { diff --git a/chromium/third_party/skia/src/gpu/GrBlurUtils.h b/chromium/third_party/skia/src/gpu/GrBlurUtils.h index 45ce4efec6f..fa0be4ef52c 100644 --- a/chromium/third_party/skia/src/gpu/GrBlurUtils.h +++ b/chromium/third_party/skia/src/gpu/GrBlurUtils.h @@ -36,7 +36,7 @@ namespace GrBlurUtils { */ void drawShapeWithMaskFilter(GrRecordingContext*, GrRenderTargetContext*, - const GrClip&, + const GrClip*, const SkPaint&, const SkMatrixProvider&, const GrStyledShape&); @@ -47,7 +47,7 @@ namespace GrBlurUtils { */ void drawShapeWithMaskFilter(GrRecordingContext*, GrRenderTargetContext*, - const GrClip&, + const GrClip*, const GrStyledShape&, GrPaint&&, const SkMatrix& viewMatrix, diff --git a/chromium/third_party/skia/src/gpu/GrCaps.cpp b/chromium/third_party/skia/src/gpu/GrCaps.cpp index 43b8996170e..9cd3ea381c1 100644 --- a/chromium/third_party/skia/src/gpu/GrCaps.cpp +++ b/chromium/third_party/skia/src/gpu/GrCaps.cpp @@ -8,6 +8,7 @@ #include "include/gpu/GrBackendSurface.h" #include "include/gpu/GrContextOptions.h" #include "include/private/GrTypesPriv.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrCaps.h" #include "src/gpu/GrSurface.h" #include "src/gpu/GrSurfaceProxy.h" @@ -358,9 +359,11 @@ GrCaps::SupportedRead GrCaps::supportedReadPixelsColorType(GrColorType srcColorT // offset alignment is a multiple of 2 but not 4. case 2: read.fOffsetAlignmentForTransferBuffer *= 2; + break; // offset alignment is not a multiple of 2. default: read.fOffsetAlignmentForTransferBuffer *= 4; + break; } } return read; @@ -388,3 +391,37 @@ GrBackendFormat GrCaps::getDefaultBackendFormat(GrColorType colorType, } return format; } + +bool GrCaps::areColorTypeAndFormatCompatible(GrColorType grCT, + const GrBackendFormat& format) const { + if (GrColorType::kUnknown == grCT) { + return false; + } + + SkImage::CompressionType compression = GrBackendFormatToCompressionType(format); + if (compression != SkImage::CompressionType::kNone) { + return grCT == (SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x + : GrColorType::kRGBA_8888); + } + + return this->onAreColorTypeAndFormatCompatible(grCT, format); +} + +GrSwizzle GrCaps::getReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const { + SkImage::CompressionType compression = GrBackendFormatToCompressionType(format); + if (compression != SkImage::CompressionType::kNone) { + if (colorType == GrColorType::kRGB_888x || colorType == GrColorType::kRGBA_8888) { + return GrSwizzle::RGBA(); + } + SkDEBUGFAILF("Illegal color type (%d) and compressed format (%d) combination.", colorType, + compression); + return {}; + } + + return this->onGetReadSwizzle(format, colorType); +} + +bool GrCaps::isFormatCompressed(const GrBackendFormat& format) const { + return GrBackendFormatToCompressionType(format) != SkImage::CompressionType::kNone; +} + diff --git a/chromium/third_party/skia/src/gpu/GrCaps.h b/chromium/third_party/skia/src/gpu/GrCaps.h index 3ef0c61812a..f81ec565e53 100644 --- a/chromium/third_party/skia/src/gpu/GrCaps.h +++ b/chromium/third_party/skia/src/gpu/GrCaps.h @@ -13,6 +13,7 @@ #include "include/core/SkString.h" #include "include/gpu/GrDriverBugWorkarounds.h" #include "include/private/GrTypesPriv.h" +#include "src/core/SkCompressedDataUtils.h" #include "src/gpu/GrBlend.h" #include "src/gpu/GrSamplerState.h" #include "src/gpu/GrShaderCaps.h" @@ -191,12 +192,7 @@ public: virtual bool isFormatSRGB(const GrBackendFormat&) const = 0; - // This will return SkImage::CompressionType::kNone if the backend format is not compressed. - virtual SkImage::CompressionType compressionType(const GrBackendFormat&) const = 0; - - bool isFormatCompressed(const GrBackendFormat& format) const { - return this->compressionType(format) != SkImage::CompressionType::kNone; - } + bool isFormatCompressed(const GrBackendFormat& format) const; // Can a texture be made with the GrBackendFormat, and then be bound and sampled in a shader. virtual bool isFormatTexturable(const GrBackendFormat&) const = 0; @@ -396,14 +392,7 @@ public: bool validateSurfaceParams(const SkISize&, const GrBackendFormat&, GrRenderable renderable, int renderTargetSampleCnt, GrMipMapped) const; - bool areColorTypeAndFormatCompatible(GrColorType grCT, - const GrBackendFormat& format) const { - if (GrColorType::kUnknown == grCT) { - return false; - } - - return this->onAreColorTypeAndFormatCompatible(grCT, format); - } + bool areColorTypeAndFormatCompatible(GrColorType grCT, const GrBackendFormat& format) const; /** These are used when creating a new texture internally. */ GrBackendFormat getDefaultBackendFormat(GrColorType, GrRenderable) const; @@ -420,7 +409,7 @@ public: * Returns the GrSwizzle to use when sampling or reading back from a texture with the passed in * GrBackendFormat and GrColorType. */ - virtual GrSwizzle getReadSwizzle(const GrBackendFormat&, GrColorType) const = 0; + GrSwizzle getReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const; /** * Returns the GrSwizzle to use when writing colors to a surface with the passed in @@ -557,6 +546,9 @@ private: const GrBackendFormat& srcFormat, GrColorType dstColorType) const = 0; + virtual GrSwizzle onGetReadSwizzle(const GrBackendFormat&, GrColorType) const = 0; + + bool fSuppressPrints : 1; bool fWireframeMode : 1; diff --git a/chromium/third_party/skia/src/gpu/GrClip.h b/chromium/third_party/skia/src/gpu/GrClip.h index d85338b3756..ee6935d1d28 100644 --- a/chromium/third_party/skia/src/gpu/GrClip.h +++ b/chromium/third_party/skia/src/gpu/GrClip.h @@ -21,6 +21,8 @@ class GrContext; */ class GrClip { public: + virtual ~GrClip() {} + virtual bool quickContains(const SkRect&) const = 0; virtual bool quickContains(const SkRRect& rrect) const { return this->quickContains(rrect.getBounds()); @@ -30,9 +32,7 @@ public: * The returned bounds represent the limits of pixels that can be drawn; anything outside of the * bounds will be entirely clipped out. */ - virtual SkIRect getConservativeBounds(int width, int height) const { - return SkIRect::MakeWH(width, height); - } + virtual SkIRect getConservativeBounds() const = 0; /** * This computes a GrAppliedClip from the clip which in turn can be used to build a GrPipeline. @@ -45,22 +45,18 @@ public: virtual bool apply(GrRecordingContext*, GrRenderTargetContext*, bool useHWAA, bool hasUserStencilSettings, GrAppliedClip*, SkRect* bounds) const = 0; - virtual ~GrClip() {} - /** * This method quickly and conservatively determines whether the entire clip is equivalent to - * intersection with a rrect. This will only return true if the rrect does not fully contain - * the render target bounds. Moreover, the returned rrect need not be contained by the render + * intersection with a rrect. Moreover, the returned rrect need not be contained by the render * target bounds. We assume all draws will be implicitly clipped by the render target bounds. * - * @param rtBounds The bounds of the render target that the clip will be applied to. * @param rrect If return is true rrect will contain the rrect equivalent to the clip within * rtBounds. * @param aa If return is true aa will indicate whether the rrect clip is antialiased. * @return true if the clip is equivalent to a single rrect, false otherwise. * */ - virtual bool isRRect(const SkRect& rtBounds, SkRRect* rrect, GrAA* aa) const = 0; + virtual bool isRRect(SkRRect* rrect, GrAA* aa) const = 0; /** * This is the maximum distance that a draw may extend beyond a clip's boundary and still count @@ -151,24 +147,13 @@ public: * return 'bounds' has been intersected with a conservative bounds of the clip. A return value * of false indicates that the draw can be skipped as it is fully clipped out. */ - virtual bool apply(int rtWidth, int rtHeight, GrAppliedHardClip* out, SkRect* bounds) const = 0; + virtual bool apply(GrAppliedHardClip* out, SkRect* bounds) const = 0; private: bool apply(GrRecordingContext*, GrRenderTargetContext* rtc, bool useHWAA, bool hasUserStencilSettings, GrAppliedClip* out, SkRect* bounds) const final { - return this->apply(rtc->width(), rtc->height(), &out->hardClip(), bounds); + return this->apply(&out->hardClip(), bounds); } }; -/** - * Specialized implementation for no clip. - */ -class GrNoClip final : public GrHardClip { -private: - bool quickContains(const SkRect&) const final { return true; } - bool quickContains(const SkRRect&) const final { return true; } - bool apply(int rtWidth, int rtHeight, GrAppliedHardClip*, SkRect*) const final { return true; } - bool isRRect(const SkRect&, SkRRect*, GrAA*) const override { return false; } -}; - #endif diff --git a/chromium/third_party/skia/src/gpu/GrClipStackClip.cpp b/chromium/third_party/skia/src/gpu/GrClipStackClip.cpp index 37121fd858b..65532389342 100644 --- a/chromium/third_party/skia/src/gpu/GrClipStackClip.cpp +++ b/chromium/third_party/skia/src/gpu/GrClipStackClip.cpp @@ -15,7 +15,6 @@ #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrDeferredProxyUploader.h" #include "src/gpu/GrDrawingManager.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrGpuResourcePriv.h" #include "src/gpu/GrProxyProvider.h" #include "src/gpu/GrRecordingContextPriv.h" @@ -24,7 +23,6 @@ #include "src/gpu/GrStencilAttachment.h" #include "src/gpu/GrStyle.h" #include "src/gpu/GrTextureProxy.h" -#include "src/gpu/effects/GrConvexPolyEffect.h" #include "src/gpu/effects/GrRRectEffect.h" #include "src/gpu/effects/generated/GrDeviceSpaceEffect.h" #include "src/gpu/geometry/GrStyledShape.h" @@ -49,26 +47,27 @@ bool GrClipStackClip::quickContains(const SkRRect& rrect) const { return fStack->quickContains(rrect); } -bool GrClipStackClip::isRRect(const SkRect& origRTBounds, SkRRect* rr, GrAA* aa) const { +bool GrClipStackClip::isRRect(SkRRect* rr, GrAA* aa) const { if (!fStack) { return false; } - const SkRect* rtBounds = &origRTBounds; + + SkRect rtBounds = SkRect::MakeIWH(fDeviceSize.fWidth, fDeviceSize.fHeight); bool isAA; - if (fStack->isRRect(*rtBounds, rr, &isAA)) { + if (fStack->isRRect(rtBounds, rr, &isAA)) { *aa = GrAA(isAA); return true; } return false; } -SkIRect GrClipStackClip::getConservativeBounds(int width, int height) const { +SkIRect GrClipStackClip::getConservativeBounds() const { if (fStack) { SkRect devBounds; - fStack->getConservativeBounds(0, 0, width, height, &devBounds); + fStack->getConservativeBounds(0, 0, fDeviceSize.fWidth, fDeviceSize.fHeight, &devBounds); return devBounds.roundOut(); } else { - return this->GrClip::getConservativeBounds(width, height); + return SkIRect::MakeSize(fDeviceSize); } } @@ -79,7 +78,7 @@ static std::unique_ptr<GrFragmentProcessor> create_fp_for_mask(GrSurfaceProxyVie const GrCaps& caps) { GrSamplerState samplerState(GrSamplerState::WrapMode::kClampToBorder, GrSamplerState::Filter::kNearest); - auto m = SkMatrix::MakeTrans(-devBound.fLeft, -devBound.fTop); + auto m = SkMatrix::Translate(-devBound.fLeft, -devBound.fTop); auto subset = SkRect::Make(devBound.size()); // We scissor to devBounds. The mask's texel centers are aligned to device space // pixel centers. Hence this domain of texture coordinates. @@ -200,7 +199,9 @@ bool GrClipStackClip::UseSWOnlyPath(GrRecordingContext* context, bool GrClipStackClip::apply(GrRecordingContext* context, GrRenderTargetContext* renderTargetContext, bool useHWAA, bool hasUserStencilSettings, GrAppliedClip* out, SkRect* bounds) const { - SkRect devBounds = SkRect::MakeIWH(renderTargetContext->width(), renderTargetContext->height()); + SkASSERT(renderTargetContext->width() == fDeviceSize.fWidth && + renderTargetContext->height() == fDeviceSize.fHeight); + SkRect devBounds = SkRect::MakeIWH(fDeviceSize.fWidth, fDeviceSize.fHeight); if (!devBounds.intersect(*bounds)) { return false; } @@ -253,7 +254,8 @@ bool GrClipStackClip::apply(GrRecordingContext* context, GrRenderTargetContext* // The opsTask ID must not be looked up until AFTER producing the clip mask (if any). That step // can cause a flush or otherwise change which opstask our draw is going into. uint32_t opsTaskID = renderTargetContext->getOpsTask()->uniqueID(); - if (auto clipFPs = reducedClip.finishAndDetachAnalyticFPs(ccpr, opsTaskID)) { + if (auto clipFPs = reducedClip.finishAndDetachAnalyticFPs(context, *fMatrixProvider, ccpr, + opsTaskID)) { out->addCoverageFP(std::move(clipFPs)); } diff --git a/chromium/third_party/skia/src/gpu/GrClipStackClip.h b/chromium/third_party/skia/src/gpu/GrClipStackClip.h index 90ca8676fc8..ffbd0017cc3 100644 --- a/chromium/third_party/skia/src/gpu/GrClipStackClip.h +++ b/chromium/third_party/skia/src/gpu/GrClipStackClip.h @@ -20,17 +20,20 @@ class GrTextureProxy; */ class GrClipStackClip final : public GrClip { public: - GrClipStackClip(const SkClipStack* stack = nullptr) { this->reset(stack); } - - void reset(const SkClipStack* stack) { fStack = stack; } + GrClipStackClip(const SkISize& dimensions, + const SkClipStack* stack = nullptr, + const SkMatrixProvider* matrixProvider = nullptr) + : fDeviceSize(dimensions) + , fStack(stack) + , fMatrixProvider(matrixProvider) {} bool quickContains(const SkRect&) const final; bool quickContains(const SkRRect&) const final; - SkIRect getConservativeBounds(int width, int height) const final; + SkIRect getConservativeBounds() const final; bool apply(GrRecordingContext*, GrRenderTargetContext*, bool useHWAA, bool hasUserStencilSettings, GrAppliedClip* out, SkRect* bounds) const final; - bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA* aa) const override; + bool isRRect(SkRRect* rr, GrAA* aa) const override; sk_sp<GrTextureProxy> testingOnly_createClipMask(GrContext*) const; static const char kMaskTestTag[]; @@ -61,7 +64,11 @@ private: const GrRenderTargetContext*, const GrReducedClip&); - const SkClipStack* fStack; + // SkClipStack does not track device bounds explicitly, but it will refine these device bounds + // as clip elements are added to the stack. + SkISize fDeviceSize; + const SkClipStack* fStack; + const SkMatrixProvider* fMatrixProvider; // for applying clip shaders }; #endif // GrClipStackClip_DEFINED diff --git a/chromium/third_party/skia/src/gpu/GrColorInfo.cpp b/chromium/third_party/skia/src/gpu/GrColorInfo.cpp index ada27da5a64..22bdc98678c 100644 --- a/chromium/third_party/skia/src/gpu/GrColorInfo.cpp +++ b/chromium/third_party/skia/src/gpu/GrColorInfo.cpp @@ -11,7 +11,11 @@ GrColorInfo::GrColorInfo( GrColorType colorType, SkAlphaType alphaType, sk_sp<SkColorSpace> colorSpace) - : fColorSpace(std::move(colorSpace)), fColorType(colorType), fAlphaType(alphaType) {} + : fColorSpace(std::move(colorSpace)), fColorType(colorType), fAlphaType(alphaType) { + // sRGB sources are very common (SkColor, etc...), so we cache that transformation + fColorXformFromSRGB = GrColorSpaceXform::Make(sk_srgb_singleton(), kUnpremul_SkAlphaType, + fColorSpace.get(), kUnpremul_SkAlphaType); +} GrColorInfo::GrColorInfo(const SkColorInfo& ci) : GrColorInfo(SkColorTypeToGrColorType(ci.colorType()), @@ -20,16 +24,3 @@ GrColorInfo::GrColorInfo(const SkColorInfo& ci) GrColorInfo::GrColorInfo(const GrColorInfo&) = default; GrColorInfo& GrColorInfo::operator=(const GrColorInfo&) = default; - -GrColorSpaceXform* GrColorInfo::colorSpaceXformFromSRGB() const { - // TODO: Make this atomic if we start accessing this on multiple threads. - if (!fInitializedColorSpaceXformFromSRGB) { - // sRGB sources are very common (SkColor, etc...), so we cache that transformation - fColorXformFromSRGB = GrColorSpaceXform::Make(sk_srgb_singleton(), kUnpremul_SkAlphaType, - fColorSpace.get(), kUnpremul_SkAlphaType); - fInitializedColorSpaceXformFromSRGB = true; - } - // You can't be color-space aware in legacy mode - SkASSERT(fColorSpace || !fColorXformFromSRGB); - return fColorXformFromSRGB.get(); -} diff --git a/chromium/third_party/skia/src/gpu/GrColorInfo.h b/chromium/third_party/skia/src/gpu/GrColorInfo.h index 578575a5d6c..0af549a8ee5 100644 --- a/chromium/third_party/skia/src/gpu/GrColorInfo.h +++ b/chromium/third_party/skia/src/gpu/GrColorInfo.h @@ -29,10 +29,8 @@ public: SkColorSpace* colorSpace() const { return fColorSpace.get(); } sk_sp<SkColorSpace> refColorSpace() const { return fColorSpace; } - GrColorSpaceXform* colorSpaceXformFromSRGB() const; - sk_sp<GrColorSpaceXform> refColorSpaceXformFromSRGB() const { - return sk_ref_sp(this->colorSpaceXformFromSRGB()); - } + GrColorSpaceXform* colorSpaceXformFromSRGB() const { return fColorXformFromSRGB.get(); } + sk_sp<GrColorSpaceXform> refColorSpaceXformFromSRGB() const { return fColorXformFromSRGB; } GrColorType colorType() const { return fColorType; } SkAlphaType alphaType() const { return fAlphaType; } @@ -43,10 +41,9 @@ public: private: sk_sp<SkColorSpace> fColorSpace; - mutable sk_sp<GrColorSpaceXform> fColorXformFromSRGB; + sk_sp<GrColorSpaceXform> fColorXformFromSRGB; GrColorType fColorType = GrColorType::kUnknown; SkAlphaType fAlphaType = kUnknown_SkAlphaType; - mutable bool fInitializedColorSpaceXformFromSRGB = false; }; #endif diff --git a/chromium/third_party/skia/src/gpu/GrColorSpaceXform.cpp b/chromium/third_party/skia/src/gpu/GrColorSpaceXform.cpp index 0f97d21f9ef..b602b32ea4b 100644 --- a/chromium/third_party/skia/src/gpu/GrColorSpaceXform.cpp +++ b/chromium/third_party/skia/src/gpu/GrColorSpaceXform.cpp @@ -97,7 +97,7 @@ GrColorSpaceXformEffect::GrColorSpaceXformEffect(std::unique_ptr<GrFragmentProce : INHERITED(kGrColorSpaceXformEffect_ClassID, OptFlags(child.get())) , fColorXform(std::move(colorXform)) { if (child) { - this->registerChildProcessor(std::move(child)); + this->registerChild(std::move(child)); } } diff --git a/chromium/third_party/skia/src/gpu/GrContext.cpp b/chromium/third_party/skia/src/gpu/GrContext.cpp index 291c4348e7a..cc951f52643 100644 --- a/chromium/third_party/skia/src/gpu/GrContext.cpp +++ b/chromium/third_party/skia/src/gpu/GrContext.cpp @@ -30,9 +30,9 @@ #include "src/gpu/SkGr.h" #include "src/gpu/ccpr/GrCoverageCountingPathRenderer.h" #include "src/gpu/effects/GrSkSLFP.h" +#include "src/gpu/text/GrSDFTOptions.h" #include "src/gpu/text/GrStrikeCache.h" #include "src/gpu/text/GrTextBlobCache.h" -#include "src/gpu/text/GrTextContext.h" #include "src/image/SkImage_GpuBase.h" #include "src/image/SkSurface_Gpu.h" #include <atomic> @@ -41,16 +41,14 @@ SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == this) #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this) -#define ASSERT_SINGLE_OWNER \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());) +#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(this->singleOwner()) #define RETURN_IF_ABANDONED if (this->abandoned()) { return; } #define RETURN_FALSE_IF_ABANDONED if (this->abandoned()) { return false; } #define RETURN_NULL_IF_ABANDONED if (this->abandoned()) { return nullptr; } //////////////////////////////////////////////////////////////////////////////// -GrContext::GrContext(GrBackendApi backend, const GrContextOptions& options, int32_t contextID) - : INHERITED(backend, options, contextID) { +GrContext::GrContext(sk_sp<GrContextThreadSafeProxy> proxy) : INHERITED(std::move(proxy)) { fResourceCache = nullptr; fResourceProvider = nullptr; } @@ -61,20 +59,19 @@ GrContext::~GrContext() { if (this->drawingManager()) { this->drawingManager()->cleanup(); } + fMappedBufferManager.reset(); delete fResourceProvider; delete fResourceCache; } -bool GrContext::init(sk_sp<const GrCaps> caps) { +bool GrContext::init() { ASSERT_SINGLE_OWNER - SkASSERT(fThreadSafeProxy); // needs to have been initialized by derived classes SkASSERT(this->proxyProvider()); - if (!INHERITED::init(std::move(caps))) { + if (!INHERITED::init()) { return false; } - SkASSERT(this->caps()); SkASSERT(this->getTextBlobCache()); if (fGpu) { @@ -106,7 +103,7 @@ bool GrContext::init(sk_sp<const GrCaps> caps) { } sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() { - return fThreadSafeProxy; + return INHERITED::threadSafeProxy(); } ////////////////////////////////////////////////////////////////////////////// @@ -170,6 +167,8 @@ bool GrContext::abandoned() { return false; } +bool GrContext::oomed() { return fGpu ? fGpu->checkAndResetOOMed() : false; } + void GrContext::resetGLTextureBindings() { if (this->abandoned() || this->backend() != GrBackendApi::kOpenGL) { return; @@ -305,35 +304,49 @@ bool GrContext::wait(int numSemaphores, const GrBackendSemaphore waitSemaphores[ std::unique_ptr<GrSemaphore> sema = fResourceProvider->wrapBackendSemaphore( waitSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillWait, kAdopt_GrWrapOwnership); - fGpu->waitSemaphore(sema.get()); + // If we failed to wrap the semaphore it means the client didn't give us a valid semaphore + // to begin with. Therefore, it is fine to not wait on it. + if (sema) { + fGpu->waitSemaphore(sema.get()); + } } return true; } //////////////////////////////////////////////////////////////////////////////// -GrSemaphoresSubmitted GrContext::flush(const GrFlushInfo& info, - const GrPrepareForExternalIORequests& externalRequests) { +GrSemaphoresSubmitted GrContext::flush(const GrFlushInfo& info) { ASSERT_SINGLE_OWNER if (this->abandoned()) { + if (info.fFinishedProc) { + info.fFinishedProc(info.fFinishedContext); + } + if (info.fSubmittedProc) { + info.fSubmittedProc(info.fSubmittedContext, false); + } return GrSemaphoresSubmitted::kNo; } - bool submitted = false; - if (this->drawingManager()->flush(nullptr, 0, SkSurface::BackendSurfaceAccess::kNoAccess, - info, externalRequests)) { - bool forceSync = SkToBool(info.fFlags & kSyncCpu_GrFlushFlag); - submitted = this->drawingManager()->submitToGpu(forceSync); - } + bool flushed = this->drawingManager()->flush( + nullptr, 0, SkSurface::BackendSurfaceAccess::kNoAccess, info, nullptr); - if (!submitted || (!this->priv().caps()->semaphoreSupport() && info.fNumSemaphores)) { + if (!flushed || (!this->priv().caps()->semaphoreSupport() && info.fNumSemaphores)) { return GrSemaphoresSubmitted::kNo; } return GrSemaphoresSubmitted::kYes; } -bool GrContext::submit(bool syncToCpu) { - return true; +bool GrContext::submit(bool syncCpu) { + ASSERT_SINGLE_OWNER + if (this->abandoned()) { + return false; + } + + if (!fGpu) { + return false; + } + + return fGpu->submitToGpu(syncCpu); } //////////////////////////////////////////////////////////////////////////////// @@ -461,71 +474,71 @@ GrBackendTexture GrContext::createBackendTexture(const SkSurfaceCharacterization return result; } +static GrBackendTexture create_and_update_backend_texture( + GrContext* context, + SkISize dimensions, + const GrBackendFormat& backendFormat, + GrMipMapped mipMapped, + GrRenderable renderable, + GrProtected isProtected, + sk_sp<GrRefCntedCallback> finishedCallback, + const GrGpu::BackendTextureData* data) { + GrGpu* gpu = context->priv().getGpu(); + + GrBackendTexture beTex = gpu->createBackendTexture(dimensions, backendFormat, renderable, + mipMapped, isProtected); + if (!beTex.isValid()) { + return {}; + } + + if (!context->priv().getGpu()->updateBackendTexture(beTex, std::move(finishedCallback), data)) { + context->deleteBackendTexture(beTex); + return {}; + } + return beTex; +} + + GrBackendTexture GrContext::createBackendTexture(const SkSurfaceCharacterization& c, const SkColor4f& color, GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { + sk_sp<GrRefCntedCallback> finishedCallback; + if (finishedProc) { + finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + if (!this->asDirectContext() || !c.isValid()) { - finishedProc(finishedContext); return {}; } if (this->abandoned()) { - finishedProc(finishedContext); return {}; } if (c.usesGLFBO0()) { - finishedProc(finishedContext); // If we are making the surface we will never use FBO0. return {}; } if (c.vulkanSecondaryCBCompatible()) { - finishedProc(finishedContext); return {}; } const GrBackendFormat format = this->defaultBackendFormat(c.colorType(), GrRenderable::kYes); if (!format.isValid()) { - finishedProc(finishedContext); return {}; } - GrBackendTexture result = this->createBackendTexture(c.width(), c.height(), format, color, - GrMipMapped(c.isMipMapped()), - GrRenderable::kYes, - c.isProtected(), finishedProc, - finishedContext); + GrGpu::BackendTextureData data(color); + GrBackendTexture result = create_and_update_backend_texture( + this, {c.width(), c.height()}, format, GrMipMapped(c.isMipMapped()), GrRenderable::kYes, + c.isProtected(), std::move(finishedCallback), &data); + SkASSERT(c.isCompatible(result)); return result; } -static GrBackendTexture create_and_update_backend_texture(GrContext* context, - SkISize dimensions, - const GrBackendFormat& backendFormat, - GrMipMapped mipMapped, - GrRenderable renderable, - GrProtected isProtected, - GrGpuFinishedProc finishedProc, - GrGpuFinishedContext finishedContext, - const GrGpu::BackendTextureData* data) { - GrGpu* gpu = context->priv().getGpu(); - - GrBackendTexture beTex = gpu->createBackendTexture(dimensions, backendFormat, renderable, - mipMapped, isProtected); - if (!beTex.isValid()) { - return {}; - } - - if (!context->priv().getGpu()->updateBackendTexture(beTex, finishedProc, finishedContext, - data)) { - context->deleteBackendTexture(beTex); - return {}; - } - return beTex; -} - GrBackendTexture GrContext::createBackendTexture(int width, int height, const GrBackendFormat& backendFormat, const SkColor4f& color, @@ -534,20 +547,23 @@ GrBackendTexture GrContext::createBackendTexture(int width, int height, GrProtected isProtected, GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { + sk_sp<GrRefCntedCallback> finishedCallback; + if (finishedProc) { + finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + TRACE_EVENT0("skia.gpu", TRACE_FUNC); if (!this->asDirectContext()) { - finishedProc(finishedContext); return {}; } if (this->abandoned()) { - finishedProc(finishedContext); return {}; } GrGpu::BackendTextureData data(color); return create_and_update_backend_texture(this, {width, height}, backendFormat, mipMapped, - renderable, isProtected, finishedProc, finishedContext, + renderable, isProtected, std::move(finishedCallback), &data); } @@ -559,27 +575,31 @@ GrBackendTexture GrContext::createBackendTexture(int width, int height, GrProtected isProtected, GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { + sk_sp<GrRefCntedCallback> finishedCallback; + if (finishedProc) { + finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + if (!this->asDirectContext()) { - finishedProc(finishedContext); return {}; } if (this->abandoned()) { - finishedProc(finishedContext); return {}; } GrBackendFormat format = this->defaultBackendFormat(skColorType, renderable); if (!format.isValid()) { - finishedProc(finishedContext); return {}; } GrColorType grColorType = SkColorTypeToGrColorType(skColorType); SkColor4f swizzledColor = this->caps()->getWriteSwizzle(format, grColorType).applyTo(color); - return this->createBackendTexture(width, height, format, swizzledColor, mipMapped, renderable, - isProtected, finishedProc, finishedContext); + GrGpu::BackendTextureData data(swizzledColor); + return create_and_update_backend_texture(this, {width, height}, format, mipMapped, + renderable, isProtected, std::move(finishedCallback), + &data); } GrBackendTexture GrContext::createBackendTexture(const SkPixmap srcData[], int numProvidedLevels, @@ -588,18 +608,20 @@ GrBackendTexture GrContext::createBackendTexture(const SkPixmap srcData[], int n GrGpuFinishedContext finishedContext) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); + sk_sp<GrRefCntedCallback> finishedCallback; + if (finishedProc) { + finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + if (!this->asDirectContext()) { - finishedProc(finishedContext); return {}; } if (this->abandoned()) { - finishedProc(finishedContext); return {}; } if (!srcData || numProvidedLevels <= 0) { - finishedProc(finishedContext); return {}; } @@ -615,7 +637,6 @@ GrBackendTexture GrContext::createBackendTexture(const SkPixmap srcData[], int n } if (numProvidedLevels != numExpectedLevels) { - finishedProc(finishedContext); return {}; } @@ -623,26 +644,29 @@ GrBackendTexture GrContext::createBackendTexture(const SkPixmap srcData[], int n GrGpu::BackendTextureData data(srcData); return create_and_update_backend_texture(this, {baseWidth, baseHeight}, backendFormat, - mipMapped, renderable, isProtected, finishedProc, - finishedContext, &data); + mipMapped, renderable, isProtected, + std::move(finishedCallback), &data); } bool GrContext::updateBackendTexture(const GrBackendTexture& backendTexture, const SkColor4f& color, GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { + sk_sp<GrRefCntedCallback> finishedCallback; + if (finishedProc) { + finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + if (!this->asDirectContext()) { - finishedProc(finishedContext); return false; } if (this->abandoned()) { - finishedProc(finishedContext); return false; } GrGpu::BackendTextureData data(color); - return fGpu->updateBackendTexture(backendTexture, finishedProc, finishedContext, &data); + return fGpu->updateBackendTexture(backendTexture, std::move(finishedCallback), &data); } bool GrContext::updateBackendTexture(const GrBackendTexture& backendTexture, @@ -650,18 +674,20 @@ bool GrContext::updateBackendTexture(const GrBackendTexture& backendTexture, int numLevels, GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { + sk_sp<GrRefCntedCallback> finishedCallback; + if (finishedProc) { + finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + if (!this->asDirectContext()) { - finishedProc(finishedContext); return false; } if (this->abandoned()) { - finishedProc(finishedContext); return false; } if (!srcData || numLevels <= 0) { - finishedProc(finishedContext); return false; } @@ -671,12 +697,11 @@ bool GrContext::updateBackendTexture(const GrBackendTexture& backendTexture, backendTexture.height()) + 1; } if (numLevels != numExpectedLevels) { - finishedProc(finishedContext); return false; } GrGpu::BackendTextureData data(srcData); - return fGpu->updateBackendTexture(backendTexture, finishedProc, finishedContext, &data); + return fGpu->updateBackendTexture(backendTexture, std::move(finishedCallback), &data); } ////////////////////////////////////////////////////////////////////////////// @@ -689,20 +714,23 @@ GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); + sk_sp<GrRefCntedCallback> finishedCallback; + if (finishedProc) { + finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + if (!this->asDirectContext()) { - finishedProc(finishedContext); return {}; } if (this->abandoned()) { - finishedProc(finishedContext); return {}; } GrGpu::BackendTextureData data(color); return fGpu->createCompressedBackendTexture({width, height}, backendFormat, - mipMapped, isProtected, finishedProc, - finishedContext, &data); + mipMapped, isProtected, std::move(finishedCallback), + &data); } GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height, @@ -713,16 +741,6 @@ GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); - if (!this->asDirectContext()) { - finishedProc(finishedContext); - return {}; - } - - if (this->abandoned()) { - finishedProc(finishedContext); - return {}; - } - GrBackendFormat format = this->compressedBackendFormat(compression); return this->createCompressedBackendTexture(width, height, format, color, mipMapped, isProtected, finishedProc, @@ -738,20 +756,23 @@ GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); + sk_sp<GrRefCntedCallback> finishedCallback; + if (finishedProc) { + finishedCallback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + if (!this->asDirectContext()) { - finishedProc(finishedContext); return {}; } if (this->abandoned()) { - finishedProc(finishedContext); return {}; } GrGpu::BackendTextureData data(compressedData, dataSize); return fGpu->createCompressedBackendTexture({width, height}, backendFormat, - mipMapped, isProtected, finishedProc, - finishedContext, &data); + mipMapped, isProtected, std::move(finishedCallback), + &data); } GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height, @@ -762,20 +783,49 @@ GrBackendTexture GrContext::createCompressedBackendTexture(int width, int height GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); + GrBackendFormat format = this->compressedBackendFormat(compression); + return this->createCompressedBackendTexture(width, height, format, data, dataSize, mipMapped, + isProtected, finishedProc, finishedContext); +} + +bool GrContext::setBackendTextureState(const GrBackendTexture& backendTexture, + const GrBackendSurfaceMutableState& state, + GrGpuFinishedProc finishedProc, + GrGpuFinishedContext finishedContext) { + sk_sp<GrRefCntedCallback> callback; + if (finishedProc) { + callback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + if (!this->asDirectContext()) { - finishedProc(finishedContext); - return {}; + return false; } if (this->abandoned()) { - finishedProc(finishedContext); - return {}; + return false; } - GrBackendFormat format = this->compressedBackendFormat(compression); - return this->createCompressedBackendTexture(width, height, format, data, dataSize, - mipMapped, isProtected, finishedProc, - finishedContext); + return fGpu->setBackendTextureState(backendTexture, state, std::move(callback)); +} + +bool GrContext::setBackendRenderTargetState(const GrBackendRenderTarget& backendRenderTarget, + const GrBackendSurfaceMutableState& state, + GrGpuFinishedProc finishedProc, + GrGpuFinishedContext finishedContext) { + sk_sp<GrRefCntedCallback> callback; + if (finishedProc) { + callback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); + } + + if (!this->asDirectContext()) { + return false; + } + + if (this->abandoned()) { + return false; + } + + return fGpu->setBackendRenderTargetState(backendRenderTarget, state, std::move(callback)); } void GrContext::deleteBackendTexture(GrBackendTexture backendTex) { @@ -789,6 +839,8 @@ void GrContext::deleteBackendTexture(GrBackendTexture backendTex) { fGpu->deleteBackendTexture(backendTex); } +////////////////////////////////////////////////////////////////////////////// + bool GrContext::precompileShader(const SkData& key, const SkData& data) { return fGpu->precompileShader(key, data); } diff --git a/chromium/third_party/skia/src/gpu/GrContextPriv.cpp b/chromium/third_party/skia/src/gpu/GrContextPriv.cpp index 702d82dbd94..3c014b13500 100644 --- a/chromium/third_party/skia/src/gpu/GrContextPriv.cpp +++ b/chromium/third_party/skia/src/gpu/GrContextPriv.cpp @@ -28,8 +28,7 @@ #define ASSERT_OWNED_PROXY(P) \ SkASSERT(!(P) || !((P)->peekTexture()) || (P)->peekTexture()->getContext() == fContext) -#define ASSERT_SINGLE_OWNER \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->singleOwner());) +#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fContext->singleOwner()) #define RETURN_VALUE_IF_ABANDONED(value) if (fContext->abandoned()) { return (value); } #define RETURN_IF_ABANDONED RETURN_VALUE_IF_ABANDONED(void) @@ -53,7 +52,7 @@ GrSemaphoresSubmitted GrContextPriv::flushSurfaces(GrSurfaceProxy* proxies[], in ASSERT_OWNED_PROXY(proxies[i]); } return fContext->drawingManager()->flushSurfaces( - proxies, numProxies, SkSurface::BackendSurfaceAccess::kNoAccess, info); + proxies, numProxies, SkSurface::BackendSurfaceAccess::kNoAccess, info, nullptr); } void GrContextPriv::flushSurface(GrSurfaceProxy* proxy) { @@ -182,7 +181,7 @@ void GrContextPriv::testingOnly_purgeAllUnlockedResources() { } void GrContextPriv::testingOnly_flushAndRemoveOnFlushCallbackObject(GrOnFlushCallbackObject* cb) { - fContext->flush(); + fContext->flushAndSubmit(); fContext->drawingManager()->testingOnly_removeOnFlushCallbackObject(cb); } #endif diff --git a/chromium/third_party/skia/src/gpu/GrContextPriv.h b/chromium/third_party/skia/src/gpu/GrContextPriv.h index d97f7adca6d..c5d3f72021e 100644 --- a/chromium/third_party/skia/src/gpu/GrContextPriv.h +++ b/chromium/third_party/skia/src/gpu/GrContextPriv.h @@ -74,7 +74,7 @@ public: /** * Create a GrContext without a resource cache */ - static sk_sp<GrContext> MakeDDL(const sk_sp<GrContextThreadSafeProxy>&); + static sk_sp<GrContext> MakeDDL(sk_sp<GrContextThreadSafeProxy>); /** * Finalizes all pending reads and writes to the surfaces and also performs an MSAA resolves diff --git a/chromium/third_party/skia/src/gpu/GrContextThreadSafeProxy.cpp b/chromium/third_party/skia/src/gpu/GrContextThreadSafeProxy.cpp index fb27ba1822c..6fd86bd1a9f 100644 --- a/chromium/third_party/skia/src/gpu/GrContextThreadSafeProxy.cpp +++ b/chromium/third_party/skia/src/gpu/GrContextThreadSafeProxy.cpp @@ -19,16 +19,24 @@ #include "src/gpu/vk/GrVkCaps.h" #endif +static int32_t next_id() { + static std::atomic<int32_t> nextID{1}; + int32_t id; + do { + id = nextID++; + } while (id == SK_InvalidGenID); + return id; +} + GrContextThreadSafeProxy::GrContextThreadSafeProxy(GrBackendApi backend, - const GrContextOptions& options, - uint32_t contextID) - : INHERITED(backend, options, contextID) { + const GrContextOptions& options) + : fBackend(backend), fOptions(options), fContextID(next_id()) { } GrContextThreadSafeProxy::~GrContextThreadSafeProxy() = default; -bool GrContextThreadSafeProxy::init(sk_sp<const GrCaps> caps) { - return INHERITED::init(std::move(caps)); +void GrContextThreadSafeProxy::init(sk_sp<const GrCaps> caps) { + fCaps = std::move(caps); } SkSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization( @@ -38,6 +46,7 @@ SkSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization( const SkSurfaceProps& surfaceProps, bool isMipMapped, bool willUseGLFBO0, bool isTextureable, GrProtected isProtected) { + SkASSERT(fCaps); if (!backendFormat.isValid()) { return SkSurfaceCharacterization(); // return an invalid characterization } @@ -49,39 +58,39 @@ SkSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization( return SkSurfaceCharacterization(); // return an invalid characterization } - if (!this->caps()->mipMapSupport()) { + if (!fCaps->mipMapSupport()) { isMipMapped = false; } GrColorType grColorType = SkColorTypeToGrColorType(ii.colorType()); - if (!this->caps()->areColorTypeAndFormatCompatible(grColorType, backendFormat)) { + if (!fCaps->areColorTypeAndFormatCompatible(grColorType, backendFormat)) { return SkSurfaceCharacterization(); // return an invalid characterization } - if (!this->caps()->isFormatAsColorTypeRenderable(grColorType, backendFormat, sampleCnt)) { + if (!fCaps->isFormatAsColorTypeRenderable(grColorType, backendFormat, sampleCnt)) { return SkSurfaceCharacterization(); // return an invalid characterization } - sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendFormat); + sampleCnt = fCaps->getRenderTargetSampleCount(sampleCnt, backendFormat); SkASSERT(sampleCnt); if (willUseGLFBO0 && isTextureable) { return SkSurfaceCharacterization(); // return an invalid characterization } - if (isTextureable && !this->caps()->isFormatTexturable(backendFormat)) { + if (isTextureable && !fCaps->isFormatTexturable(backendFormat)) { // Skia doesn't agree that this is textureable. return SkSurfaceCharacterization(); // return an invalid characterization } if (GrBackendApi::kVulkan == backendFormat.backend()) { - if (GrBackendApi::kVulkan != this->backend()) { + if (GrBackendApi::kVulkan != fBackend) { return SkSurfaceCharacterization(); // return an invalid characterization } #ifdef SK_VULKAN - const GrVkCaps* vkCaps = (const GrVkCaps*) this->caps(); + const GrVkCaps* vkCaps = (const GrVkCaps*) fCaps.get(); // The protection status of the characterization and the context need to match if (isProtected != GrProtected(vkCaps->supportsProtectedMemory())) { @@ -101,18 +110,34 @@ SkSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization( surfaceProps); } +GrBackendFormat GrContextThreadSafeProxy::defaultBackendFormat(SkColorType skColorType, + GrRenderable renderable) const { + SkASSERT(fCaps); + GrColorType grColorType = SkColorTypeToGrColorType(skColorType); + + GrBackendFormat format = fCaps->getDefaultBackendFormat(grColorType, renderable); + if (!format.isValid()) { + return GrBackendFormat(); + } + + SkASSERT(renderable == GrRenderable::kNo || + fCaps->isFormatAsColorTypeRenderable(grColorType, format)); + + return format; +} + +void GrContextThreadSafeProxy::abandonContext() { + fAbandoned.store(true, std::memory_order_relaxed); +} + +bool GrContextThreadSafeProxy::abandoned() const { + return fAbandoned.load(std::memory_order_relaxed); +} + //////////////////////////////////////////////////////////////////////////////// sk_sp<GrContextThreadSafeProxy> GrContextThreadSafeProxyPriv::Make( GrBackendApi backend, - const GrContextOptions& options, - uint32_t contextID, - sk_sp<const GrCaps> caps) { - sk_sp<GrContextThreadSafeProxy> proxy(new GrContextThreadSafeProxy(backend, options, - contextID)); - - if (!proxy->init(std::move(caps))) { - return nullptr; - } - return proxy; + const GrContextOptions& options) { + return sk_sp<GrContextThreadSafeProxy>(new GrContextThreadSafeProxy(backend, options)); } diff --git a/chromium/third_party/skia/src/gpu/GrContextThreadSafeProxyPriv.h b/chromium/third_party/skia/src/gpu/GrContextThreadSafeProxyPriv.h index 0efb995a357..c4873bb9847 100644 --- a/chromium/third_party/skia/src/gpu/GrContextThreadSafeProxyPriv.h +++ b/chromium/third_party/skia/src/gpu/GrContextThreadSafeProxyPriv.h @@ -9,6 +9,7 @@ #define GrContextThreadSafeProxyPriv_DEFINED #include "include/gpu/GrContextThreadSafeProxy.h" +#include "include/private/GrContext_Base.h" #include "src/gpu/GrCaps.h" @@ -19,21 +20,24 @@ */ class GrContextThreadSafeProxyPriv { public: - // from GrContext_Base - uint32_t contextID() const { return fProxy->contextID(); } + void init(sk_sp<const GrCaps> caps) const { fProxy->init(std::move(caps)); } - bool matches(GrContext_Base* candidate) const { return fProxy->matches(candidate); } + bool matches(GrContext_Base* candidate) const { + return fProxy == candidate->threadSafeProxy().get(); + } - const GrContextOptions& options() const { return fProxy->options(); } + GrBackend backend() const { return fProxy->fBackend; } + const GrContextOptions& options() const { return fProxy->fOptions; } + uint32_t contextID() const { return fProxy->fContextID; } - const GrCaps* caps() const { return fProxy->caps(); } - sk_sp<const GrCaps> refCaps() const { return fProxy->refCaps(); } + const GrCaps* caps() const { return fProxy->fCaps.get(); } + sk_sp<const GrCaps> refCaps() const { return fProxy->fCaps; } + + void abandonContext() { fProxy->abandonContext(); } + bool abandoned() const { return fProxy->abandoned(); } // GrContextThreadSafeProxyPriv - static sk_sp<GrContextThreadSafeProxy> Make(GrBackendApi, - const GrContextOptions&, - uint32_t contextID, - sk_sp<const GrCaps>); + static sk_sp<GrContextThreadSafeProxy> Make(GrBackendApi, const GrContextOptions&); private: explicit GrContextThreadSafeProxyPriv(GrContextThreadSafeProxy* proxy) : fProxy(proxy) {} diff --git a/chromium/third_party/skia/src/gpu/GrContext_Base.cpp b/chromium/third_party/skia/src/gpu/GrContext_Base.cpp index 034d0234875..34262997f02 100644 --- a/chromium/third_party/skia/src/gpu/GrContext_Base.cpp +++ b/chromium/third_party/skia/src/gpu/GrContext_Base.cpp @@ -9,53 +9,35 @@ #include "src/gpu/GrBaseContextPriv.h" #include "src/gpu/GrCaps.h" +#include "src/gpu/GrContextThreadSafeProxyPriv.h" #include "src/gpu/GrShaderUtils.h" #include "src/gpu/effects/GrSkSLFP.h" -static int32_t next_id() { - static std::atomic<int32_t> nextID{1}; - int32_t id; - do { - id = nextID++; - } while (id == SK_InvalidGenID); - return id; -} - -GrContext_Base::GrContext_Base(GrBackendApi backend, - const GrContextOptions& options, - uint32_t contextID) - : fBackend(backend) - , fOptions(options) - , fContextID(SK_InvalidGenID == contextID ? next_id() : contextID) { +GrContext_Base::GrContext_Base(sk_sp<GrContextThreadSafeProxy> proxy) + : fThreadSafeProxy(std::move(proxy)) { } GrContext_Base::~GrContext_Base() { } -bool GrContext_Base::init(sk_sp<const GrCaps> caps) { - SkASSERT(caps); +bool GrContext_Base::init() { + SkASSERT(fThreadSafeProxy->isValid()); - fCaps = caps; return true; } -const GrCaps* GrContext_Base::caps() const { return fCaps.get(); } -sk_sp<const GrCaps> GrContext_Base::refCaps() const { return fCaps; } - -GrBackendFormat GrContext_Base::defaultBackendFormat(SkColorType skColorType, - GrRenderable renderable) const { - const GrCaps* caps = this->caps(); - - GrColorType grColorType = SkColorTypeToGrColorType(skColorType); +uint32_t GrContext_Base::contextID() const { return fThreadSafeProxy->priv().contextID(); } +GrBackendApi GrContext_Base::backend() const { return fThreadSafeProxy->priv().backend(); } - GrBackendFormat format = caps->getDefaultBackendFormat(grColorType, renderable); - if (!format.isValid()) { - return GrBackendFormat(); - } +const GrContextOptions& GrContext_Base::options() const { + return fThreadSafeProxy->priv().options(); +} - SkASSERT(renderable == GrRenderable::kNo || - caps->isFormatAsColorTypeRenderable(grColorType, format)); +const GrCaps* GrContext_Base::caps() const { return fThreadSafeProxy->priv().caps(); } +sk_sp<const GrCaps> GrContext_Base::refCaps() const { return fThreadSafeProxy->priv().refCaps(); } - return format; +GrBackendFormat GrContext_Base::defaultBackendFormat(SkColorType skColorType, + GrRenderable renderable) const { + return fThreadSafeProxy->defaultBackendFormat(skColorType, renderable); } GrBackendFormat GrContext_Base::compressedBackendFormat(SkImage::CompressionType c) const { @@ -67,6 +49,8 @@ GrBackendFormat GrContext_Base::compressedBackendFormat(SkImage::CompressionType return format; } +sk_sp<GrContextThreadSafeProxy> GrContext_Base::threadSafeProxy() { return fThreadSafeProxy; } + /////////////////////////////////////////////////////////////////////////////////////////////////// sk_sp<const GrCaps> GrBaseContextPriv::refCaps() const { return fContext->refCaps(); diff --git a/chromium/third_party/skia/src/gpu/GrCopyRenderTask.cpp b/chromium/third_party/skia/src/gpu/GrCopyRenderTask.cpp index 0f46e69efcb..a578451b1a7 100644 --- a/chromium/third_party/skia/src/gpu/GrCopyRenderTask.cpp +++ b/chromium/third_party/skia/src/gpu/GrCopyRenderTask.cpp @@ -11,7 +11,8 @@ #include "src/gpu/GrOpFlushState.h" #include "src/gpu/GrResourceAllocator.h" -sk_sp<GrRenderTask> GrCopyRenderTask::Make(GrSurfaceProxyView srcView, +sk_sp<GrRenderTask> GrCopyRenderTask::Make(GrDrawingManager* drawingMgr, + GrSurfaceProxyView srcView, const SkIRect& srcRect, GrSurfaceProxyView dstView, const SkIPoint& dstPoint, @@ -41,34 +42,35 @@ sk_sp<GrRenderTask> GrCopyRenderTask::Make(GrSurfaceProxyView srcView, } sk_sp<GrCopyRenderTask> task(new GrCopyRenderTask( - std::move(srcView), clippedSrcRect, std::move(dstView), clippedDstPoint)); + drawingMgr, std::move(srcView), clippedSrcRect, std::move(dstView), clippedDstPoint)); return std::move(task); } -GrCopyRenderTask::GrCopyRenderTask(GrSurfaceProxyView srcView, +GrCopyRenderTask::GrCopyRenderTask(GrDrawingManager* drawingMgr, + GrSurfaceProxyView srcView, const SkIRect& srcRect, GrSurfaceProxyView dstView, const SkIPoint& dstPoint) - : GrRenderTask(std::move(dstView)) + : GrRenderTask() , fSrcView(std::move(srcView)) , fSrcRect(srcRect) , fDstPoint(dstPoint) { - fTargetView.proxy()->setLastRenderTask(this); + this->addTarget(drawingMgr, dstView); } void GrCopyRenderTask::gatherProxyIntervals(GrResourceAllocator* alloc) const { // This renderTask doesn't have "normal" ops. In this case we still need to add an interval (so // fEndOfOpsTaskOpIndices will remain in sync), so we create a fake op# to capture the fact that - // we read fSrcView and copy to fTargetView. + // we read fSrcView and copy to target view. alloc->addInterval(fSrcView.proxy(), alloc->curOp(), alloc->curOp(), GrResourceAllocator::ActualUse::kYes); - alloc->addInterval(fTargetView.proxy(), alloc->curOp(), alloc->curOp(), + alloc->addInterval(this->target(0).proxy(), alloc->curOp(), alloc->curOp(), GrResourceAllocator::ActualUse::kYes); alloc->incOps(); } bool GrCopyRenderTask::onExecute(GrOpFlushState* flushState) { - GrSurfaceProxy* dstProxy = fTargetView.proxy(); + GrSurfaceProxy* dstProxy = this->target(0).proxy(); GrSurfaceProxy* srcProxy = fSrcView.proxy(); if (!srcProxy->isInstantiated() || !dstProxy->isInstantiated()) { return false; diff --git a/chromium/third_party/skia/src/gpu/GrCopyRenderTask.h b/chromium/third_party/skia/src/gpu/GrCopyRenderTask.h index a9c79ea43c7..4ecd3c7f1dc 100644 --- a/chromium/third_party/skia/src/gpu/GrCopyRenderTask.h +++ b/chromium/third_party/skia/src/gpu/GrCopyRenderTask.h @@ -12,21 +12,21 @@ class GrCopyRenderTask final : public GrRenderTask { public: - static sk_sp<GrRenderTask> Make(GrSurfaceProxyView srcView, + static sk_sp<GrRenderTask> Make(GrDrawingManager*, + GrSurfaceProxyView srcView, const SkIRect& srcRect, GrSurfaceProxyView dstView, const SkIPoint& dstPoint, const GrCaps*); private: - GrCopyRenderTask(GrSurfaceProxyView srcView, + GrCopyRenderTask(GrDrawingManager*, + GrSurfaceProxyView srcView, const SkIRect& srcRect, GrSurfaceProxyView dstView, const SkIPoint& dstPoint); bool onIsUsed(GrSurfaceProxy* proxy) const override { - // This case should be handled by GrRenderTask. - SkASSERT(proxy != fTargetView.proxy()); return proxy == fSrcView.proxy(); } // If instantiation failed, at flush time we simply will skip doing the copy. diff --git a/chromium/third_party/skia/src/gpu/GrDDLContext.cpp b/chromium/third_party/skia/src/gpu/GrDDLContext.cpp index 1f77417a208..ee77eaf8044 100644 --- a/chromium/third_party/skia/src/gpu/GrDDLContext.cpp +++ b/chromium/third_party/skia/src/gpu/GrDDLContext.cpp @@ -21,8 +21,7 @@ class GrDDLContext final : public GrContext { public: GrDDLContext(sk_sp<GrContextThreadSafeProxy> proxy) - : INHERITED(proxy->backend(), proxy->priv().options(), proxy->priv().contextID()) { - fThreadSafeProxy = std::move(proxy); + : INHERITED(std::move(proxy)) { } ~GrDDLContext() override {} @@ -38,8 +37,8 @@ public: } void freeGpuResources() override { - SkASSERT(0); // freeing resources in a DDL Recorder doesn't make a whole lot of sense - INHERITED::freeGpuResources(); + // freeing resources in a DDL Recorder doesn't make a whole lot of sense but some of + // our tests do it anyways } private: @@ -47,11 +46,8 @@ private: // GrRecordingContext! GrContext* asDirectContext() override { return nullptr; } - bool init(sk_sp<const GrCaps> caps) override { - SkASSERT(caps); - SkASSERT(fThreadSafeProxy); // should've been set in the ctor - - if (!INHERITED::init(std::move(caps))) { + bool init() override { + if (!INHERITED::init()) { return false; } @@ -59,8 +55,6 @@ private: // splitting. this->setupDrawingManager(true, true); - SkASSERT(this->caps()); - return true; } @@ -79,8 +73,9 @@ private: if (this->backend() == GrBackendApi::kVulkan || this->backend() == GrBackendApi::kMetal || + this->backend() == GrBackendApi::kDirect3D || this->backend() == GrBackendApi::kDawn) { - // Currently, Vulkan, Metal and Dawn require a live renderTarget to + // Currently Vulkan, Metal, Direct3D, and Dawn require a live renderTarget to // compute the key return; } @@ -153,10 +148,10 @@ private: typedef GrContext INHERITED; }; -sk_sp<GrContext> GrContextPriv::MakeDDL(const sk_sp<GrContextThreadSafeProxy>& proxy) { - sk_sp<GrContext> context(new GrDDLContext(proxy)); +sk_sp<GrContext> GrContextPriv::MakeDDL(sk_sp<GrContextThreadSafeProxy> proxy) { + sk_sp<GrContext> context(new GrDDLContext(std::move(proxy))); - if (!context->init(proxy->priv().refCaps())) { + if (!context->init()) { return nullptr; } return context; diff --git a/chromium/third_party/skia/src/gpu/GrDataUtils.cpp b/chromium/third_party/skia/src/gpu/GrDataUtils.cpp index a6102fd24ca..7e6a6c734eb 100644 --- a/chromium/third_party/skia/src/gpu/GrDataUtils.cpp +++ b/chromium/third_party/skia/src/gpu/GrDataUtils.cpp @@ -7,6 +7,7 @@ #include "src/gpu/GrDataUtils.h" +#include "include/third_party/skcms/skcms.h" #include "src/core/SkColorSpaceXformSteps.h" #include "src/core/SkCompressedDataUtils.h" #include "src/core/SkConvertPixels.h" @@ -595,10 +596,10 @@ bool GrConvertPixels(const GrImageInfo& dstInfo, void* dst, size_t dstRB, if (hasConversion) { loadSwizzle.apply(&pipeline); if (srcIsSRGB) { - pipeline.append(SkRasterPipeline::from_srgb); + pipeline.append_transfer_function(*skcms_sRGB_TransferFunction()); } if (alphaOrCSConversion) { - steps->apply(&pipeline, srcIsNormalized); + steps->apply(&pipeline); } if (clampGamut) { append_clamp_gamut(&pipeline); @@ -606,14 +607,14 @@ bool GrConvertPixels(const GrImageInfo& dstInfo, void* dst, size_t dstRB, if (doLumToAlpha) { pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_alpha); // If we ever needed to convert from linear-encoded gray to sRGB-encoded - // gray we'd have a problem here because the subsequent to_srgb stage + // gray we'd have a problem here because the subsequent transfer function stage // ignores the alpha channel (where we just stashed the gray). There are // several ways that could be fixed but given our current set of color types // this should never happen. SkASSERT(!dstIsSRGB); } if (dstIsSRGB) { - pipeline.append(SkRasterPipeline::to_srgb); + pipeline.append_transfer_function(*skcms_sRGB_Inverse_TransferFunction()); } storeSwizzle.apply(&pipeline); } else { @@ -664,14 +665,14 @@ bool GrClearImage(const GrImageInfo& dstInfo, void* dst, size_t dstRB, SkColor4f if (doLumToAlpha) { pipeline.append(SkRasterPipeline::StockStage::bt709_luminance_or_luma_to_alpha); // If we ever needed to convert from linear-encoded gray to sRGB-encoded - // gray we'd have a problem here because the subsequent to_srgb stage + // gray we'd have a problem here because the subsequent transfer function stage // ignores the alpha channel (where we just stashed the gray). There are // several ways that could be fixed but given our current set of color types // this should never happen. SkASSERT(!dstIsSRGB); } if (dstIsSRGB) { - pipeline.append(SkRasterPipeline::to_srgb); + pipeline.append_transfer_function(*skcms_sRGB_Inverse_TransferFunction()); } storeSwizzle.apply(&pipeline); SkRasterPipeline_MemoryCtx dstCtx{dst, SkToInt(dstRB/dstInfo.bpp())}; diff --git a/chromium/third_party/skia/src/gpu/GrDefaultGeoProcFactory.cpp b/chromium/third_party/skia/src/gpu/GrDefaultGeoProcFactory.cpp index 4f93238d1ae..94ba1846cbd 100644 --- a/chromium/third_party/skia/src/gpu/GrDefaultGeoProcFactory.cpp +++ b/chromium/third_party/skia/src/gpu/GrDefaultGeoProcFactory.cpp @@ -57,6 +57,7 @@ public: public: GLSLProcessor() : fViewMatrix(SkMatrix::InvalidMatrix()) + , fLocalMatrix(SkMatrix::InvalidMatrix()) , fColor(SK_PMColor4fILLEGAL) , fCoverage(0xff) {} @@ -111,14 +112,14 @@ public: &fViewMatrixUniform); // emit transforms using either explicit local coords or positions - const auto& coordsAttr = gp.fInLocalCoords.isInitialized() ? gp.fInLocalCoords - : gp.fInPosition; - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - coordsAttr.asShaderVar(), - gp.localMatrix(), - args.fFPCoordTransformHandler); + if (gp.fInLocalCoords.isInitialized()) { + SkASSERT(gp.localMatrix().isIdentity()); + gpArgs->fLocalCoordVar = gp.fInLocalCoords.asShaderVar(); + } else if (gp.fLocalCoordsWillBeRead) { + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, + gp.fInPosition.asShaderVar(), gp.localMatrix(), + &fLocalMatrixUniform); + } // Setup coverage as pass through if (gp.hasVertexCoverage() && !tweakAlpha) { @@ -144,8 +145,12 @@ public: const DefaultGeoProc& def = gp.cast<DefaultGeoProc>(); uint32_t key = def.fFlags; key |= (def.coverage() == 0xff) ? 0x80 : 0; - key |= (def.localCoordsWillBeRead() && def.localMatrix().hasPerspective()) ? 0x100 : 0; - key |= ComputePosKey(def.viewMatrix()) << 20; + key |= def.localCoordsWillBeRead() ? 0x100 : 0; + + bool usesLocalMatrix = def.localCoordsWillBeRead() && + !def.fInLocalCoords.isInitialized(); + key = AddMatrixKeys(key, def.viewMatrix(), + usesLocalMatrix ? def.localMatrix() : SkMatrix::I()); b->add32(key); } @@ -154,12 +159,9 @@ public: const CoordTransformRange& transformRange) override { const DefaultGeoProc& dgp = gp.cast<DefaultGeoProc>(); - if (!dgp.viewMatrix().isIdentity() && - !SkMatrixPriv::CheapEqual(fViewMatrix, dgp.viewMatrix())) - { - fViewMatrix = dgp.viewMatrix(); - pdman.setSkMatrix(fViewMatrixUniform, fViewMatrix); - } + this->setTransform(pdman, fViewMatrixUniform, dgp.viewMatrix(), &fViewMatrix); + this->setTransform(pdman, fLocalMatrixUniform, dgp.localMatrix(), &fLocalMatrix); + this->setTransformDataHelper(pdman, transformRange); if (!dgp.hasVertexColor() && dgp.color() != fColor) { pdman.set4fv(fColorUniform, 1, dgp.color().vec()); @@ -170,14 +172,15 @@ public: pdman.set1f(fCoverageUniform, GrNormalizeByteToFloat(dgp.coverage())); fCoverage = dgp.coverage(); } - this->setTransformDataHelper(dgp.fLocalMatrix, pdman, transformRange); } private: SkMatrix fViewMatrix; + SkMatrix fLocalMatrix; SkPMColor4f fColor; uint8_t fCoverage; UniformHandle fViewMatrixUniform; + UniformHandle fLocalMatrixUniform; UniformHandle fColorUniform; UniformHandle fCoverageUniform; diff --git a/chromium/third_party/skia/src/gpu/GrDrawingManager.cpp b/chromium/third_party/skia/src/gpu/GrDrawingManager.cpp index 83af6b41c7d..5ae2684c582 100644 --- a/chromium/third_party/skia/src/gpu/GrDrawingManager.cpp +++ b/chromium/third_party/skia/src/gpu/GrDrawingManager.cpp @@ -10,6 +10,7 @@ #include "include/core/SkDeferredDisplayList.h" #include "include/gpu/GrBackendSemaphore.h" #include "include/private/GrRecordingContext.h" +#include "src/core/SkDeferredDisplayListPriv.h" #include "src/core/SkTTopoSort.h" #include "src/gpu/GrAuditTrail.h" #include "src/gpu/GrClientMappedBufferManager.h" @@ -36,7 +37,7 @@ #include "src/gpu/GrTransferFromRenderTask.h" #include "src/gpu/GrWaitRenderTask.h" #include "src/gpu/ccpr/GrCoverageCountingPathRenderer.h" -#include "src/gpu/text/GrTextContext.h" +#include "src/gpu/text/GrSDFTOptions.h" #include "src/image/SkSurface_Gpu.h" GrDrawingManager::RenderTaskDAG::RenderTaskDAG(bool sortRenderTasks) @@ -57,27 +58,15 @@ void GrDrawingManager::RenderTaskDAG::reset() { fRenderTasks.reset(); } -void GrDrawingManager::RenderTaskDAG::removeRenderTask(int index) { - if (!fRenderTasks[index]->unique()) { - // TODO: Eventually this should be guaranteed unique: http://skbug.com/7111 - fRenderTasks[index]->endFlush(); - } - - fRenderTasks[index] = nullptr; -} - void GrDrawingManager::RenderTaskDAG::removeRenderTasks(int startIndex, int stopIndex) { for (int i = startIndex; i < stopIndex; ++i) { - if (!fRenderTasks[i]) { - continue; - } - this->removeRenderTask(i); + fRenderTasks[i] = nullptr; } } bool GrDrawingManager::RenderTaskDAG::isUsed(GrSurfaceProxy* proxy) const { - for (int i = 0; i < fRenderTasks.count(); ++i) { - if (fRenderTasks[i] && fRenderTasks[i]->isUsed(proxy)) { + for (const auto& task : fRenderTasks) { + if (task && task->isUsed(proxy)) { return true; } } @@ -134,7 +123,7 @@ void GrDrawingManager::RenderTaskDAG::prepForFlush() { GrOpsTask* curOpsTask = fRenderTasks[i]->asOpsTask(); if (prevOpsTask && curOpsTask) { - SkASSERT(prevOpsTask->fTargetView != curOpsTask->fTargetView); + SkASSERT(prevOpsTask->target(0).proxy() != curOpsTask->target(0).proxy()); } prevOpsTask = curOpsTask; @@ -151,7 +140,7 @@ void GrDrawingManager::RenderTaskDAG::closeAll(const GrCaps* caps) { } } -void GrDrawingManager::RenderTaskDAG::cleanup(const GrCaps* caps) { +void GrDrawingManager::RenderTaskDAG::cleanup(GrDrawingManager* drawingMgr, const GrCaps* caps) { for (int i = 0; i < fRenderTasks.count(); ++i) { if (!fRenderTasks[i]) { continue; @@ -160,13 +149,15 @@ void GrDrawingManager::RenderTaskDAG::cleanup(const GrCaps* caps) { // no renderTask should receive a dependency fRenderTasks[i]->makeClosed(*caps); + fRenderTasks[i]->disown(drawingMgr); + // We shouldn't need to do this, but it turns out some clients still hold onto opsTasks // after a cleanup. // MDB TODO: is this still true? if (!fRenderTasks[i]->unique()) { // TODO: Eventually this should be guaranteed unique. // https://bugs.chromium.org/p/skia/issues/detail?id=7111 - fRenderTasks[i]->endFlush(); + fRenderTasks[i]->endFlush(drawingMgr); } } @@ -176,22 +167,18 @@ void GrDrawingManager::RenderTaskDAG::cleanup(const GrCaps* caps) { /////////////////////////////////////////////////////////////////////////////////////////////////// GrDrawingManager::GrDrawingManager(GrRecordingContext* context, const GrPathRendererChain::Options& optionsForPathRendererChain, - const GrTextContext::Options& optionsForTextContext, bool sortRenderTasks, bool reduceOpsTaskSplitting) : fContext(context) , fOptionsForPathRendererChain(optionsForPathRendererChain) - , fOptionsForTextContext(optionsForTextContext) , fDAG(sortRenderTasks) - , fTextContext(nullptr) , fPathRendererChain(nullptr) , fSoftwarePathRenderer(nullptr) , fFlushing(false) - , fReduceOpsTaskSplitting(reduceOpsTaskSplitting) { -} + , fReduceOpsTaskSplitting(reduceOpsTaskSplitting) { } void GrDrawingManager::cleanup() { - fDAG.cleanup(fContext->priv().caps()); + fDAG.cleanup(this, fContext->priv().caps()); fPathRendererChain = nullptr; fSoftwarePathRenderer = nullptr; @@ -221,14 +208,20 @@ void GrDrawingManager::freeGpuResources() { } // MDB TODO: make use of the 'proxy' parameter. -bool GrDrawingManager::flush(GrSurfaceProxy* proxies[], int numProxies, - SkSurface::BackendSurfaceAccess access, const GrFlushInfo& info, - const GrPrepareForExternalIORequests& externalRequests) { +bool GrDrawingManager::flush( + GrSurfaceProxy* proxies[], + int numProxies, + SkSurface::BackendSurfaceAccess access, + const GrFlushInfo& info, + const GrBackendSurfaceMutableState* newState) { SkASSERT(numProxies >= 0); SkASSERT(!numProxies || proxies); GR_CREATE_TRACE_MARKER_CONTEXT("GrDrawingManager", "flush", fContext); if (fFlushing || this->wasAbandoned()) { + if (info.fSubmittedProc) { + info.fSubmittedProc(info.fSubmittedContext, false); + } if (info.fFinishedProc) { info.fFinishedProc(info.fFinishedContext); } @@ -238,18 +231,24 @@ bool GrDrawingManager::flush(GrSurfaceProxy* proxies[], int numProxies, SkDEBUGCODE(this->validate()); if (kNone_GrFlushFlags == info.fFlags && !info.fNumSemaphores && !info.fFinishedProc && - !externalRequests.hasRequests()) { + access == SkSurface::BackendSurfaceAccess::kNoAccess && !newState) { bool canSkip = numProxies > 0; for (int i = 0; i < numProxies && canSkip; ++i) { canSkip = !fDAG.isUsed(proxies[i]) && !this->isDDLTarget(proxies[i]); } if (canSkip) { + if (info.fSubmittedProc) { + info.fSubmittedProc(info.fSubmittedContext, true); + } return false; } } auto direct = fContext->priv().asDirectContext(); if (!direct) { + if (info.fSubmittedProc) { + info.fSubmittedProc(info.fSubmittedContext, false); + } if (info.fFinishedProc) { info.fFinishedProc(info.fFinishedContext); } @@ -258,12 +257,8 @@ bool GrDrawingManager::flush(GrSurfaceProxy* proxies[], int numProxies, direct->priv().clientMappedBufferManager()->process(); GrGpu* gpu = direct->priv().getGpu(); - if (!gpu) { - if (info.fFinishedProc) { - info.fFinishedProc(info.fFinishedContext); - } - return false; // Can't flush while DDL recording - } + // We have a non abandoned and direct GrContext. It must have a GrGpu. + SkASSERT(gpu); fFlushing = true; @@ -382,6 +377,7 @@ bool GrDrawingManager::flush(GrSurfaceProxy* proxies[], int numProxies, SkASSERT(!fDAG.renderTask(i) || fDAG.renderTask(i)->unique()); } #endif + fLastRenderTasks.reset(); fDAG.reset(); this->clearDDLTargets(); @@ -394,7 +390,7 @@ bool GrDrawingManager::flush(GrSurfaceProxy* proxies[], int numProxies, opMemoryPool->isEmpty(); #endif - gpu->executeFlushInfo(proxies, numProxies, access, info, externalRequests); + gpu->executeFlushInfo(proxies, numProxies, access, info, newState); // Give the cache a chance to purge resources that become purgeable due to flushing. if (flushed) { @@ -471,6 +467,7 @@ bool GrDrawingManager::executeRenderTasks(int startIndex, int stopIndex, GrOpFlu SkDebugf("WARNING: onFlushRenderTask failed to execute.\n"); } SkASSERT(onFlushRenderTask->unique()); + onFlushRenderTask->disown(this); onFlushRenderTask = nullptr; (*numRenderTasksExecuted)++; if (*numRenderTasksExecuted >= kMaxRenderTasksBeforeFlush) { @@ -505,15 +502,70 @@ bool GrDrawingManager::executeRenderTasks(int startIndex, int stopIndex, GrOpFlu // resources are the last to be purged by the resource cache. flushState->reset(); - fDAG.removeRenderTasks(startIndex, stopIndex); + this->removeRenderTasks(startIndex, stopIndex); return anyRenderTasksExecuted; } -GrSemaphoresSubmitted GrDrawingManager::flushSurfaces(GrSurfaceProxy* proxies[], int numProxies, - SkSurface::BackendSurfaceAccess access, - const GrFlushInfo& info) { +void GrDrawingManager::removeRenderTasks(int startIndex, int stopIndex) { + for (int i = startIndex; i < stopIndex; ++i) { + GrRenderTask* task = fDAG.renderTask(i); + if (!task) { + continue; + } + if (!task->unique()) { + // TODO: Eventually this should be guaranteed unique: http://skbug.com/7111 + task->endFlush(this); + } + task->disown(this); + } + fDAG.removeRenderTasks(startIndex, stopIndex); +} + +static void resolve_and_mipmap(GrGpu* gpu, GrSurfaceProxy* proxy) { + if (!proxy->isInstantiated()) { + return; + } + + // In the flushSurfaces case, we need to resolve MSAA immediately after flush. This is + // because clients expect the flushed surface's backing texture to be fully resolved + // upon return. + if (proxy->requiresManualMSAAResolve()) { + auto* rtProxy = proxy->asRenderTargetProxy(); + SkASSERT(rtProxy); + if (rtProxy->isMSAADirty()) { + SkASSERT(rtProxy->peekRenderTarget()); + gpu->resolveRenderTarget(rtProxy->peekRenderTarget(), rtProxy->msaaDirtyRect(), + GrGpu::ForExternalIO::kYes); + rtProxy->markMSAAResolved(); + } + } + // If, after a flush, any of the proxies of interest have dirty mipmaps, regenerate them in + // case their backend textures are being stolen. + // (This special case is exercised by the ReimportImageTextureWithMipLevels test.) + // FIXME: It may be more ideal to plumb down a "we're going to steal the backends" flag. + if (auto* textureProxy = proxy->asTextureProxy()) { + if (textureProxy->mipMapsAreDirty()) { + SkASSERT(textureProxy->peekTexture()); + gpu->regenerateMipMapLevels(textureProxy->peekTexture()); + textureProxy->markMipMapsClean(); + } + } +} + +GrSemaphoresSubmitted GrDrawingManager::flushSurfaces( + GrSurfaceProxy* proxies[], + int numProxies, + SkSurface::BackendSurfaceAccess access, + const GrFlushInfo& info, + const GrBackendSurfaceMutableState* newState) { if (this->wasAbandoned()) { + if (info.fSubmittedProc) { + info.fSubmittedProc(info.fSubmittedContext, false); + } + if (info.fFinishedProc) { + info.fFinishedProc(info.fFinishedContext); + } return GrSemaphoresSubmitted::kNo; } SkDEBUGCODE(this->validate()); @@ -522,59 +574,30 @@ GrSemaphoresSubmitted GrDrawingManager::flushSurfaces(GrSurfaceProxy* proxies[], auto direct = fContext->priv().asDirectContext(); if (!direct) { + if (info.fSubmittedProc) { + info.fSubmittedProc(info.fSubmittedContext, false); + } + if (info.fFinishedProc) { + info.fFinishedProc(info.fFinishedContext); + } return GrSemaphoresSubmitted::kNo; // Can't flush while DDL recording } GrGpu* gpu = direct->priv().getGpu(); - if (!gpu) { - return GrSemaphoresSubmitted::kNo; // Can't flush while DDL recording - } + // We have a non abandoned and direct GrContext. It must have a GrGpu. + SkASSERT(gpu); // TODO: It is important to upgrade the drawingmanager to just flushing the // portion of the DAG required by 'proxies' in order to restore some of the // semantics of this method. - bool didFlush = this->flush(proxies, numProxies, access, info, - GrPrepareForExternalIORequests()); + bool didFlush = this->flush(proxies, numProxies, access, info, newState); for (int i = 0; i < numProxies; ++i) { - GrSurfaceProxy* proxy = proxies[i]; - if (!proxy->isInstantiated()) { - continue; - } - // In the flushSurfaces case, we need to resolve MSAA immediately after flush. This is - // because the client will call through to this method when drawing into a target created by - // wrapBackendTextureAsRenderTarget, and will expect the original texture to be fully - // resolved upon return. - if (proxy->requiresManualMSAAResolve()) { - auto* rtProxy = proxy->asRenderTargetProxy(); - SkASSERT(rtProxy); - if (rtProxy->isMSAADirty()) { - SkASSERT(rtProxy->peekRenderTarget()); - gpu->resolveRenderTarget(rtProxy->peekRenderTarget(), rtProxy->msaaDirtyRect(), - GrGpu::ForExternalIO::kYes); - rtProxy->markMSAAResolved(); - } - } - // If, after a flush, any of the proxies of interest have dirty mipmaps, regenerate them in - // case their backend textures are being stolen. - // (This special case is exercised by the ReimportImageTextureWithMipLevels test.) - // FIXME: It may be more ideal to plumb down a "we're going to steal the backends" flag. - if (auto* textureProxy = proxy->asTextureProxy()) { - if (textureProxy->mipMapsAreDirty()) { - SkASSERT(textureProxy->peekTexture()); - gpu->regenerateMipMapLevels(textureProxy->peekTexture()); - textureProxy->markMipMapsClean(); - } - } + resolve_and_mipmap(gpu, proxies[i]); } SkDEBUGCODE(this->validate()); - bool submitted = false; - if (didFlush) { - submitted = this->submitToGpu(SkToBool(info.fFlags & kSyncCpu_GrFlushFlag)); - } - - if (!submitted || (!direct->priv().caps()->semaphoreSupport() && info.fNumSemaphores)) { + if (!didFlush || (!direct->priv().caps()->semaphoreSupport() && info.fNumSemaphores)) { return GrSemaphoresSubmitted::kNo; } return GrSemaphoresSubmitted::kYes; @@ -593,6 +616,31 @@ void GrDrawingManager::testingOnly_removeOnFlushCallbackObject(GrOnFlushCallback } #endif +void GrDrawingManager::setLastRenderTask(const GrSurfaceProxy* proxy, GrRenderTask* task) { +#ifdef SK_DEBUG + if (GrRenderTask* prior = this->getLastRenderTask(proxy)) { + SkASSERT(prior->isClosed()); + } +#endif + uint32_t key = proxy->uniqueID().asUInt(); + if (task) { + fLastRenderTasks.set(key, task); + } else if (fLastRenderTasks.find(key)) { + fLastRenderTasks.remove(key); + } +} + +GrRenderTask* GrDrawingManager::getLastRenderTask(const GrSurfaceProxy* proxy) const { + auto entry = fLastRenderTasks.find(proxy->uniqueID().asUInt()); + return entry ? *entry : nullptr; +} + +GrOpsTask* GrDrawingManager::getLastOpsTask(const GrSurfaceProxy* proxy) const { + GrRenderTask* task = this->getLastRenderTask(proxy); + return task ? task->asOpsTask() : nullptr; +} + + void GrDrawingManager::moveRenderTasksToDDL(SkDeferredDisplayList* ddl) { SkDEBUGCODE(this->validate()); @@ -604,6 +652,7 @@ void GrDrawingManager::moveRenderTasksToDDL(SkDeferredDisplayList* ddl) { SkASSERT(!fDAG.numRenderTasks()); for (auto& renderTask : ddl->fRenderTasks) { + renderTask->disown(this); renderTask->prePrepare(fContext); } @@ -633,7 +682,17 @@ void GrDrawingManager::copyRenderTasksFromDDL(const SkDeferredDisplayList* ddl, fActiveOpsTask = nullptr; } - this->addDDLTarget(newDest); + // Propagate the DDL proxy's state information to the replaying DDL. + if (ddl->priv().targetProxy()->isMSAADirty()) { + newDest->markMSAADirty(ddl->priv().targetProxy()->msaaDirtyRect(), + ddl->characterization().origin()); + } + GrTextureProxy* newTextureProxy = newDest->asTextureProxy(); + if (newTextureProxy && GrMipMapped::kYes == newTextureProxy->mipMapped()) { + newTextureProxy->markMipMapsDirty(); + } + + this->addDDLTarget(newDest, ddl->priv().targetProxy()); // Here we jam the proxy that backs the current replay SkSurface into the LazyProxyData. // The lazy proxy that references it (in the copied opsTasks) will steal its GrTexture. @@ -685,7 +744,7 @@ void GrDrawingManager::closeRenderTasksForNewRenderTask(GrSurfaceProxy* target) // split in case they use both the old and new content. (This is a bit of an overkill: they // really only need to be split if they ever reference proxy's contents again but that is // hard to predict/handle). - if (GrRenderTask* lastRenderTask = target->getLastRenderTask()) { + if (GrRenderTask* lastRenderTask = this->getLastRenderTask(target)) { lastRenderTask->closeThoseWhoDependOnMe(*fContext->priv().caps()); } } else if (fActiveOpsTask) { @@ -706,10 +765,10 @@ sk_sp<GrOpsTask> GrDrawingManager::newOpsTask(GrSurfaceProxyView surfaceView, GrSurfaceProxy* proxy = surfaceView.proxy(); this->closeRenderTasksForNewRenderTask(proxy); - sk_sp<GrOpsTask> opsTask(new GrOpsTask(fContext->priv().arenas(), + sk_sp<GrOpsTask> opsTask(new GrOpsTask(this, fContext->priv().arenas(), std::move(surfaceView), fContext->priv().auditTrail())); - SkASSERT(proxy->getLastRenderTask() == opsTask.get()); + SkASSERT(this->getLastRenderTask(proxy) == opsTask.get()); if (managedOpsTask) { fDAG.add(opsTask); @@ -749,7 +808,7 @@ void GrDrawingManager::newWaitRenderTask(sk_sp<GrSurfaceProxy> proxy, std::move(semaphores), numSemaphores); if (fReduceOpsTaskSplitting) { - GrRenderTask* lastTask = proxy->getLastRenderTask(); + GrRenderTask* lastTask = this->getLastRenderTask(proxy.get()); if (lastTask && !lastTask->isClosed()) { // We directly make the currently open renderTask depend on waitTask instead of using // the proxy version of addDependency. The waitTask will never need to trigger any @@ -773,12 +832,12 @@ void GrDrawingManager::newWaitRenderTask(sk_sp<GrSurfaceProxy> proxy, if (lastTask) { waitTask->addDependency(lastTask); } - proxy->setLastRenderTask(waitTask.get()); + this->setLastRenderTask(proxy.get(), waitTask.get()); } fDAG.add(waitTask); } else { - if (fActiveOpsTask && (fActiveOpsTask->fTargetView.proxy() == proxy.get())) { - SkASSERT(proxy->getLastRenderTask() == fActiveOpsTask); + if (fActiveOpsTask && (fActiveOpsTask->target(0).proxy() == proxy.get())) { + SkASSERT(this->getLastRenderTask(proxy.get()) == fActiveOpsTask); fDAG.addBeforeLast(waitTask); // In this case we keep the current renderTask open but just insert the new waitTask // before it in the list. The waitTask will never need to trigger any resolves or mip @@ -800,10 +859,10 @@ void GrDrawingManager::newWaitRenderTask(sk_sp<GrSurfaceProxy> proxy, // there is a lastTask on the proxy we make waitTask depend on that task. This // dependency isn't strictly needed but it does keep the DAG from reordering the // waitTask earlier and blocking more tasks. - if (GrRenderTask* lastTask = proxy->getLastRenderTask()) { + if (GrRenderTask* lastTask = this->getLastRenderTask(proxy.get())) { waitTask->addDependency(lastTask); } - proxy->setLastRenderTask(waitTask.get()); + this->setLastRenderTask(proxy.get(), waitTask.get()); this->closeRenderTasksForNewRenderTask(proxy.get()); fDAG.add(waitTask); } @@ -825,13 +884,15 @@ void GrDrawingManager::newTransferFromRenderTask(sk_sp<GrSurfaceProxy> srcProxy, this->closeRenderTasksForNewRenderTask(nullptr); GrRenderTask* task = fDAG.add(sk_make_sp<GrTransferFromRenderTask>( - srcProxy, srcRect, surfaceColorType, dstColorType, std::move(dstBuffer), dstOffset)); + srcProxy, srcRect, surfaceColorType, dstColorType, + std::move(dstBuffer), dstOffset)); const GrCaps& caps = *fContext->priv().caps(); // We always say GrMipMapped::kNo here since we are always just copying from the base layer. We // don't need to make sure the whole mip map chain is valid. - task->addDependency(srcProxy.get(), GrMipMapped::kNo, GrTextureResolveManager(this), caps); + task->addDependency(this, srcProxy.get(), GrMipMapped::kNo, + GrTextureResolveManager(this), caps); task->makeClosed(caps); // We have closed the previous active oplist but since a new oplist isn't being added there @@ -853,7 +914,7 @@ bool GrDrawingManager::newCopyRenderTask(GrSurfaceProxyView srcView, GrSurfaceProxy* srcProxy = srcView.proxy(); GrRenderTask* task = - fDAG.add(GrCopyRenderTask::Make(std::move(srcView), srcRect, std::move(dstView), + fDAG.add(GrCopyRenderTask::Make(this, std::move(srcView), srcRect, std::move(dstView), dstPoint, &caps)); if (!task) { return false; @@ -861,7 +922,7 @@ bool GrDrawingManager::newCopyRenderTask(GrSurfaceProxyView srcView, // We always say GrMipMapped::kNo here since we are always just copying from the base layer to // another base layer. We don't need to make sure the whole mip map chain is valid. - task->addDependency(srcProxy, GrMipMapped::kNo, GrTextureResolveManager(this), caps); + task->addDependency(this, srcProxy, GrMipMapped::kNo, GrTextureResolveManager(this), caps); task->makeClosed(caps); // We have closed the previous active oplist but since a new oplist isn't being added there @@ -871,14 +932,6 @@ bool GrDrawingManager::newCopyRenderTask(GrSurfaceProxyView srcView, return true; } -GrTextContext* GrDrawingManager::getTextContext() { - if (!fTextContext) { - fTextContext = GrTextContext::Make(fOptionsForTextContext); - } - - return fTextContext.get(); -} - /* * This method finds a path renderer that can draw the specified path on * the provided target. @@ -936,7 +989,7 @@ void GrDrawingManager::flushIfNecessary() { auto resourceCache = direct->priv().getResourceCache(); if (resourceCache && resourceCache->requestsFlush()) { if (this->flush(nullptr, 0, SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo(), - GrPrepareForExternalIORequests())) { + nullptr)) { this->submitToGpu(false); } resourceCache->purgeAsNeeded(); diff --git a/chromium/third_party/skia/src/gpu/GrDrawingManager.h b/chromium/third_party/skia/src/gpu/GrDrawingManager.h index fcb5466e18f..77c1dd95ce5 100644 --- a/chromium/third_party/skia/src/gpu/GrDrawingManager.h +++ b/chromium/third_party/skia/src/gpu/GrDrawingManager.h @@ -8,26 +8,30 @@ #ifndef GrDrawingManager_DEFINED #define GrDrawingManager_DEFINED -#include <set> #include "include/core/SkSurface.h" #include "include/private/SkTArray.h" +#include "include/private/SkTHash.h" #include "src/gpu/GrBufferAllocPool.h" #include "src/gpu/GrDeferredUpload.h" +#include "src/gpu/GrHashMapWithCache.h" #include "src/gpu/GrPathRenderer.h" #include "src/gpu/GrPathRendererChain.h" #include "src/gpu/GrResourceCache.h" -#include "src/gpu/text/GrTextContext.h" +#include "src/gpu/GrSurfaceProxy.h" // Enabling this will print out which path renderers are being chosen #define GR_PATH_RENDERER_SPEW 0 class GrCoverageCountingPathRenderer; +class GrGpuBuffer; class GrOnFlushCallbackObject; class GrOpFlushState; class GrOpsTask; class GrRecordingContext; class GrRenderTargetContext; class GrRenderTargetProxy; +class GrRenderTask; +class GrSemaphore; class GrSoftwarePathRenderer; class GrSurfaceContext; class GrSurfaceProxyView; @@ -78,8 +82,6 @@ public: GrRecordingContext* getContext() { return fContext; } - GrTextContext* getTextContext(); - GrPathRenderer* getPathRenderer(const GrPathRenderer::CanDrawPathArgs& args, bool allowSW, GrPathRendererChain::DrawType drawType, @@ -98,11 +100,13 @@ public: GrSemaphoresSubmitted flushSurfaces(GrSurfaceProxy* proxies[], int cnt, SkSurface::BackendSurfaceAccess access, - const GrFlushInfo& info); + const GrFlushInfo& info, + const GrBackendSurfaceMutableState* newState); GrSemaphoresSubmitted flushSurface(GrSurfaceProxy* proxy, SkSurface::BackendSurfaceAccess access, - const GrFlushInfo& info) { - return this->flushSurfaces(&proxy, 1, access, info); + const GrFlushInfo& info, + const GrBackendSurfaceMutableState* newState) { + return this->flushSurfaces(&proxy, 1, access, info, newState); } void addOnFlushCallbackObject(GrOnFlushCallbackObject*); @@ -111,6 +115,10 @@ public: void testingOnly_removeOnFlushCallbackObject(GrOnFlushCallbackObject*); #endif + GrRenderTask* getLastRenderTask(const GrSurfaceProxy*) const; + GrOpsTask* getLastOpsTask(const GrSurfaceProxy*) const; + void setLastRenderTask(const GrSurfaceProxy*, GrRenderTask*); + void moveRenderTasksToDDL(SkDeferredDisplayList* ddl); void copyRenderTasksFromDDL(const SkDeferredDisplayList*, GrRenderTargetProxy* newDest); @@ -130,7 +138,7 @@ private: void closeAll(const GrCaps* caps); // A yucky combination of closeAll and reset - void cleanup(const GrCaps* caps); + void cleanup(GrDrawingManager*, const GrCaps* caps); void gatherIDs(SkSTArray<8, uint32_t, true>* idArray) const; @@ -167,8 +175,8 @@ private: bool fSortRenderTasks; }; - GrDrawingManager(GrRecordingContext*, const GrPathRendererChain::Options&, - const GrTextContext::Options&, + GrDrawingManager(GrRecordingContext*, + const GrPathRendererChain::Options&, bool sortRenderTasks, bool reduceOpsTaskSplitting); @@ -185,11 +193,13 @@ private: bool executeRenderTasks(int startIndex, int stopIndex, GrOpFlushState*, int* numRenderTasksExecuted); + void removeRenderTasks(int startIndex, int stopIndex); + bool flush(GrSurfaceProxy* proxies[], int numProxies, SkSurface::BackendSurfaceAccess access, const GrFlushInfo&, - const GrPrepareForExternalIORequests&); + const GrBackendSurfaceMutableState* newState); bool submitToGpu(bool syncToCpu); @@ -206,7 +216,7 @@ private: GrRecordingContext* fContext; GrPathRendererChain::Options fOptionsForPathRendererChain; - GrTextContext::Options fOptionsForTextContext; + // This cache is used by both the vertex and index pools. It reuses memory across multiple // flushes. sk_sp<GrBufferAllocPool::CpuBufferCache> fCpuBufferCache; @@ -218,8 +228,6 @@ private: // These are the new renderTasks generated by the onFlush CBs SkSTArray<4, sk_sp<GrRenderTask>> fOnFlushRenderTasks; - std::unique_ptr<GrTextContext> fTextContext; - std::unique_ptr<GrPathRendererChain> fPathRendererChain; sk_sp<GrSoftwarePathRenderer> fSoftwarePathRenderer; @@ -229,15 +237,31 @@ private: SkTArray<GrOnFlushCallbackObject*> fOnFlushCBObjects; - void addDDLTarget(GrSurfaceProxy* proxy) { fDDLTargets.insert(proxy); } - bool isDDLTarget(GrSurfaceProxy* proxy) { return fDDLTargets.find(proxy) != fDDLTargets.end(); } - void clearDDLTargets() { fDDLTargets.clear(); } + void addDDLTarget(GrSurfaceProxy* newTarget, GrRenderTargetProxy* ddlTarget) { + fDDLTargets.set(newTarget->uniqueID().asUInt(), ddlTarget); + } + bool isDDLTarget(GrSurfaceProxy* newTarget) { + return SkToBool(fDDLTargets.find(newTarget->uniqueID().asUInt())); + } + GrRenderTargetProxy* getDDLTarget(GrSurfaceProxy* newTarget) { + auto entry = fDDLTargets.find(newTarget->uniqueID().asUInt()); + return entry ? *entry : nullptr; + } + void clearDDLTargets() { fDDLTargets.reset(); } // We play a trick with lazy proxies to retarget the base target of a DDL to the SkSurface - // it is replayed on. Because of this remapping we need to explicitly store the targets of - // DDL replaying. + // it is replayed on. 'fDDLTargets' stores this mapping from SkSurface unique proxy ID + // to the DDL's lazy proxy. // Note: we do not expect a whole lot of these per flush - std::set<GrSurfaceProxy*> fDDLTargets; + SkTHashMap<uint32_t, GrRenderTargetProxy*> fDDLTargets; + + struct SurfaceIDKeyTraits { + static uint32_t GetInvalidKey() { + return GrSurfaceProxy::UniqueID::InvalidID().asUInt(); + } + }; + + GrHashMapWithCache<uint32_t, GrRenderTask*, SurfaceIDKeyTraits, GrCheapHash> fLastRenderTasks; }; #endif diff --git a/chromium/third_party/skia/src/gpu/GrDynamicAtlas.cpp b/chromium/third_party/skia/src/gpu/GrDynamicAtlas.cpp index 00d0947728d..2bc309b7736 100644 --- a/chromium/third_party/skia/src/gpu/GrDynamicAtlas.cpp +++ b/chromium/third_party/skia/src/gpu/GrDynamicAtlas.cpp @@ -7,31 +7,33 @@ #include "src/gpu/GrDynamicAtlas.h" +#include "src/core/SkIPoint16.h" #include "src/gpu/GrOnFlushResourceProvider.h" #include "src/gpu/GrProxyProvider.h" +#include "src/gpu/GrRectanizerPow2.h" #include "src/gpu/GrRectanizerSkyline.h" #include "src/gpu/GrRenderTarget.h" -#include "src/gpu/GrRenderTargetContext.h" +#include "src/gpu/GrRenderTargetContextPriv.h" // Each Node covers a sub-rectangle of the final atlas. When a GrDynamicAtlas runs out of room, we // create a new Node the same size as all combined nodes in the atlas as-is, and then place the new // Node immediately below or beside the others (thereby doubling the size of the GyDynamicAtlas). class GrDynamicAtlas::Node { public: - Node(std::unique_ptr<Node> previous, int l, int t, int r, int b) - : fPrevious(std::move(previous)), fX(l), fY(t), fRectanizer(r - l, b - t) {} + Node(Node* previous, GrRectanizer* rectanizer, int x, int y) + : fPrevious(previous), fRectanizer(rectanizer), fX(x), fY(y) {} - Node* previous() const { return fPrevious.get(); } + Node* previous() const { return fPrevious; } bool addRect(int w, int h, SkIPoint16* loc) { // Pad all paths except those that are expected to take up an entire physical texture. - if (w < fRectanizer.width()) { - w = std::min(w + kPadding, fRectanizer.width()); + if (w < fRectanizer->width()) { + w = std::min(w + kPadding, fRectanizer->width()); } - if (h < fRectanizer.height()) { - h = std::min(h + kPadding, fRectanizer.height()); + if (h < fRectanizer->height()) { + h = std::min(h + kPadding, fRectanizer->height()); } - if (!fRectanizer.addRect(w, h, loc)) { + if (!fRectanizer->addRect(w, h, loc)) { return false; } loc->fX += fX; @@ -40,9 +42,9 @@ public: } private: - const std::unique_ptr<Node> fPrevious; + Node* const fPrevious; + GrRectanizer* const fRectanizer; const int fX, fY; - GrRectanizerSkyline fRectanizer; }; sk_sp<GrTextureProxy> GrDynamicAtlas::MakeLazyAtlasProxy( @@ -66,10 +68,12 @@ sk_sp<GrTextureProxy> GrDynamicAtlas::MakeLazyAtlasProxy( } GrDynamicAtlas::GrDynamicAtlas(GrColorType colorType, InternalMultisample internalMultisample, - SkISize initialSize, int maxAtlasSize, const GrCaps& caps) + SkISize initialSize, int maxAtlasSize, const GrCaps& caps, + RectanizerAlgorithm algorithm) : fColorType(colorType) , fInternalMultisample(internalMultisample) - , fMaxAtlasSize(maxAtlasSize) { + , fMaxAtlasSize(maxAtlasSize) + , fRectanizerAlgorithm(algorithm) { SkASSERT(fMaxAtlasSize <= caps.maxTextureSize()); this->reset(initialSize, caps); } @@ -78,6 +82,7 @@ GrDynamicAtlas::~GrDynamicAtlas() { } void GrDynamicAtlas::reset(SkISize initialSize, const GrCaps& caps) { + fNodeAllocator.reset(); fWidth = std::min(SkNextPow2(initialSize.width()), fMaxAtlasSize); fHeight = std::min(SkNextPow2(initialSize.height()), fMaxAtlasSize); fTopNode = nullptr; @@ -95,18 +100,25 @@ void GrDynamicAtlas::reset(SkISize initialSize, const GrCaps& caps) { fBackingTexture = nullptr; } -bool GrDynamicAtlas::addRect(const SkIRect& devIBounds, SkIVector* offset) { +GrDynamicAtlas::Node* GrDynamicAtlas::makeNode(Node* previous, int l, int t, int r, int b) { + int width = r - l; + int height = b - t; + GrRectanizer* rectanizer = (fRectanizerAlgorithm == RectanizerAlgorithm::kSkyline) + ? (GrRectanizer*)fNodeAllocator.make<GrRectanizerSkyline>(width, height) + : fNodeAllocator.make<GrRectanizerPow2>(width, height); + return fNodeAllocator.make<Node>(previous, rectanizer, l, t); +} + +bool GrDynamicAtlas::addRect(int width, int height, SkIPoint16* location) { // This can't be called anymore once instantiate() has been called. SkASSERT(!this->isInstantiated()); - SkIPoint16 location; - if (!this->internalPlaceRect(devIBounds.width(), devIBounds.height(), &location)) { + if (!this->internalPlaceRect(width, height, location)) { return false; } - offset->set(location.x() - devIBounds.left(), location.y() - devIBounds.top()); - fDrawBounds.fWidth = std::max(fDrawBounds.width(), location.x() + devIBounds.width()); - fDrawBounds.fHeight = std::max(fDrawBounds.height(), location.y() + devIBounds.height()); + fDrawBounds.fWidth = std::max(fDrawBounds.width(), location->x() + width); + fDrawBounds.fHeight = std::max(fDrawBounds.height(), location->y() + height); return true; } @@ -126,10 +138,10 @@ bool GrDynamicAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) { if (h > fHeight) { fHeight = std::min(SkNextPow2(h), fMaxAtlasSize); } - fTopNode = std::make_unique<Node>(nullptr, 0, 0, fWidth, fHeight); + fTopNode = this->makeNode(nullptr, 0, 0, fWidth, fHeight); } - for (Node* node = fTopNode.get(); node; node = node->previous()) { + for (Node* node = fTopNode; node; node = node->previous()) { if (node->addRect(w, h, loc)) { return true; } @@ -143,11 +155,11 @@ bool GrDynamicAtlas::internalPlaceRect(int w, int h, SkIPoint16* loc) { if (fHeight <= fWidth) { int top = fHeight; fHeight = std::min(fHeight * 2, fMaxAtlasSize); - fTopNode = std::make_unique<Node>(std::move(fTopNode), 0, top, fWidth, fHeight); + fTopNode = this->makeNode(fTopNode, 0, top, fWidth, fHeight); } else { int left = fWidth; fWidth = std::min(fWidth * 2, fMaxAtlasSize); - fTopNode = std::make_unique<Node>(std::move(fTopNode), left, 0, fWidth, fHeight); + fTopNode = this->makeNode(fTopNode, left, 0, fWidth, fHeight); } } while (!fTopNode->addRect(w, h, loc)); @@ -187,7 +199,6 @@ std::unique_ptr<GrRenderTargetContext> GrDynamicAtlas::instantiate( } SkIRect clearRect = SkIRect::MakeSize(fDrawBounds); - rtc->clear(&clearRect, SK_PMColor4fTRANSPARENT, - GrRenderTargetContext::CanClearFullscreen::kYes); + rtc->priv().clearAtLeast(clearRect, SK_PMColor4fTRANSPARENT); return rtc; } diff --git a/chromium/third_party/skia/src/gpu/GrDynamicAtlas.h b/chromium/third_party/skia/src/gpu/GrDynamicAtlas.h index 7a7780cc8c8..e96ffe8f590 100644 --- a/chromium/third_party/skia/src/gpu/GrDynamicAtlas.h +++ b/chromium/third_party/skia/src/gpu/GrDynamicAtlas.h @@ -8,6 +8,7 @@ #ifndef GrDynamicAtlas_DEFINED #define GrDynamicAtlas_DEFINED +#include "src/core/SkArenaAlloc.h" #include "src/gpu/GrTextureProxy.h" class GrOnFlushResourceProvider; @@ -41,20 +42,27 @@ public: const GrCaps&, GrSurfaceProxy::UseAllocator); + enum class RectanizerAlgorithm { + kSkyline, + kPow2 + }; + GrDynamicAtlas(GrColorType colorType, InternalMultisample, SkISize initialSize, - int maxAtlasSize, const GrCaps&); + int maxAtlasSize, const GrCaps&, + RectanizerAlgorithm = RectanizerAlgorithm::kSkyline); virtual ~GrDynamicAtlas(); void reset(SkISize initialSize, const GrCaps& desc); + int maxAtlasSize() const { return fMaxAtlasSize; } GrTextureProxy* textureProxy() const { return fTextureProxy.get(); } bool isInstantiated() const { return fTextureProxy->isInstantiated(); } int currentWidth() const { return fWidth; } int currentHeight() const { return fHeight; } - // Attempts to add a rect to the atlas. If successful, returns the integer offset from - // device-space pixels where the path will be drawn, to atlas pixels where its mask resides. - bool addRect(const SkIRect& devIBounds, SkIVector* atlasOffset); + // Attempts to add a rect to the atlas. Returns true if successful, along with the rect's + // top-left location in the atlas. + bool addRect(int width, int height, SkIPoint16* location); const SkISize& drawBounds() { return fDrawBounds; } // Instantiates our texture proxy for the atlas and returns a pre-cleared GrRenderTargetContext @@ -70,16 +78,20 @@ public: private: class Node; + Node* makeNode(Node* previous, int l, int t, int r, int b); bool internalPlaceRect(int w, int h, SkIPoint16* loc); const GrColorType fColorType; const InternalMultisample fInternalMultisample; const int fMaxAtlasSize; + const RectanizerAlgorithm fRectanizerAlgorithm; int fWidth; int fHeight; - std::unique_ptr<Node> fTopNode; SkISize fDrawBounds; + SkSTArenaAlloc<512> fNodeAllocator; + Node* fTopNode = nullptr; + sk_sp<GrTextureProxy> fTextureProxy; sk_sp<GrTexture> fBackingTexture; }; diff --git a/chromium/third_party/skia/src/gpu/GrFPArgs.h b/chromium/third_party/skia/src/gpu/GrFPArgs.h index 3058f8681de..6b21e32602c 100644 --- a/chromium/third_party/skia/src/gpu/GrFPArgs.h +++ b/chromium/third_party/skia/src/gpu/GrFPArgs.h @@ -28,7 +28,13 @@ struct GrFPArgs { } class WithPreLocalMatrix; - class WithPostLocalMatrix; + + GrFPArgs withNewMatrixProvider(const SkMatrixProvider& provider) const { + GrFPArgs newArgs(fContext, provider, fFilterQuality, fDstColorInfo); + newArgs.fInputColorIsOpaque = fInputColorIsOpaque; + newArgs.fPreLocalMatrix = fPreLocalMatrix; + return newArgs; + } GrRecordingContext* fContext; const SkMatrixProvider& fMatrixProvider; @@ -65,4 +71,3 @@ private: }; #endif - diff --git a/chromium/third_party/skia/src/gpu/GrFixedClip.cpp b/chromium/third_party/skia/src/gpu/GrFixedClip.cpp index 51f2f9d7bda..2f75bc9a4bf 100644 --- a/chromium/third_party/skia/src/gpu/GrFixedClip.cpp +++ b/chromium/third_party/skia/src/gpu/GrFixedClip.cpp @@ -14,47 +14,33 @@ bool GrFixedClip::quickContains(const SkRect& rect) const { if (fWindowRectsState.enabled()) { return false; } + return !fScissorState.enabled() || GrClip::IsInsideClip(fScissorState.rect(), rect); } -SkIRect GrFixedClip::getConservativeBounds(int w, int h) const { - SkIRect devResult = this->GrClip::getConservativeBounds(w, h); - if (fScissorState.enabled()) { - if (!devResult.intersect(fScissorState.rect())) { - devResult.setEmpty(); - } - } - return devResult; +SkIRect GrFixedClip::getConservativeBounds() const { + return fScissorState.rect(); } -bool GrFixedClip::isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA* aa) const { +bool GrFixedClip::isRRect(SkRRect* rr, GrAA* aa) const { if (fWindowRectsState.enabled()) { return false; } - if (fScissorState.enabled()) { - SkRect rect = SkRect::Make(fScissorState.rect()); - if (!rect.intersects(rtBounds)) { - return false; - } - rr->setRect(rect); - *aa = GrAA::kNo; - return true; - } - return false; + // Whether or not the scissor test is enabled, the remaining clip is a rectangle described + // by scissorState.rect() (either the scissor or the rt bounds). + rr->setRect(SkRect::Make(fScissorState.rect())); + *aa = GrAA::kNo; + return true; }; -bool GrFixedClip::apply(int rtWidth, int rtHeight, GrAppliedHardClip* out, SkRect* bounds) const { - if (fScissorState.enabled()) { - SkIRect tightScissor = SkIRect::MakeWH(rtWidth, rtHeight); - if (!tightScissor.intersect(fScissorState.rect())) { - return false; - } - if (IsOutsideClip(tightScissor, *bounds)) { - return false; - } - if (!IsInsideClip(fScissorState.rect(), *bounds)) { - out->addScissor(tightScissor, bounds); - } +bool GrFixedClip::apply(GrAppliedHardClip* out, SkRect* bounds) const { + if (IsOutsideClip(fScissorState.rect(), *bounds)) { + return false; + } + if (!IsInsideClip(fScissorState.rect(), *bounds)) { + SkIRect tightScissor = bounds->roundOut(); + SkAssertResult(tightScissor.intersect(fScissorState.rect())); + out->addScissor(tightScissor, bounds); } if (fWindowRectsState.enabled()) { @@ -63,8 +49,3 @@ bool GrFixedClip::apply(int rtWidth, int rtHeight, GrAppliedHardClip* out, SkRec return true; } - -const GrFixedClip& GrFixedClip::Disabled() { - static const GrFixedClip disabled = GrFixedClip(); - return disabled; -} diff --git a/chromium/third_party/skia/src/gpu/GrFixedClip.h b/chromium/third_party/skia/src/gpu/GrFixedClip.h index 1f175f83bee..5abc3102c2f 100644 --- a/chromium/third_party/skia/src/gpu/GrFixedClip.h +++ b/chromium/third_party/skia/src/gpu/GrFixedClip.h @@ -17,17 +17,21 @@ */ class GrFixedClip final : public GrHardClip { public: - GrFixedClip() = default; - explicit GrFixedClip(const SkIRect& scissorRect) : fScissorState(scissorRect) {} + explicit GrFixedClip(const SkISize& rtDims) : fScissorState(rtDims) {} + GrFixedClip(const SkISize& rtDims, const SkIRect& scissorRect) + : GrFixedClip(rtDims) { + SkAssertResult(fScissorState.set(scissorRect)); + } const GrScissorState& scissorState() const { return fScissorState; } bool scissorEnabled() const { return fScissorState.enabled(); } - const SkIRect& scissorRect() const { SkASSERT(scissorEnabled()); return fScissorState.rect(); } + // Returns the scissor rect or rt bounds if the scissor test is not enabled. + const SkIRect& scissorRect() const { return fScissorState.rect(); } void disableScissor() { fScissorState.setDisabled(); } - void setScissor(const SkIRect& irect) { - fScissorState.set(irect); + bool SK_WARN_UNUSED_RESULT setScissor(const SkIRect& irect) { + return fScissorState.set(irect); } bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& irect) { return fScissorState.intersect(irect); @@ -43,11 +47,9 @@ public: } bool quickContains(const SkRect&) const override; - SkIRect getConservativeBounds(int w, int h) const override; - bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA*) const override; - bool apply(int rtWidth, int rtHeight, GrAppliedHardClip*, SkRect*) const override; - - static const GrFixedClip& Disabled(); + SkIRect getConservativeBounds() const override; + bool isRRect(SkRRect* rr, GrAA*) const override; + bool apply(GrAppliedHardClip*, SkRect*) const override; private: GrScissorState fScissorState; diff --git a/chromium/third_party/skia/src/gpu/GrFragmentProcessor.cpp b/chromium/third_party/skia/src/gpu/GrFragmentProcessor.cpp index e4b18c89fcf..9c668d3aed4 100644 --- a/chromium/third_party/skia/src/gpu/GrFragmentProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/GrFragmentProcessor.cpp @@ -13,7 +13,6 @@ #include "src/gpu/effects/generated/GrClampFragmentProcessor.h" #include "src/gpu/effects/generated/GrConstColorProcessor.h" #include "src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h" -#include "src/gpu/effects/generated/GrPremulInputFragmentProcessor.h" #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" #include "src/gpu/glsl/GrGLSLProgramDataManager.h" @@ -74,25 +73,47 @@ void GrFragmentProcessor::addCoordTransform(GrCoordTransform* transform) { fFlags |= kHasCoordTransforms_Flag; } -void GrFragmentProcessor::setSampleMatrix(SkSL::SampleMatrix matrix) { - if (matrix == fMatrix) { +void GrFragmentProcessor::setSampleMatrix(SkSL::SampleMatrix newMatrix) { + if (newMatrix == fMatrix) { return; } + SkASSERT(newMatrix.fKind != SkSL::SampleMatrix::Kind::kNone); SkASSERT(fMatrix.fKind != SkSL::SampleMatrix::Kind::kVariable); + if (this->numCoordTransforms() == 0 && + (newMatrix.fKind == SkSL::SampleMatrix::Kind::kConstantOrUniform || + newMatrix.fKind == SkSL::SampleMatrix::Kind::kMixed)) { + // as things stand, matrices only work when there's a coord transform, so we need to add + // an identity transform to keep the downstream code happy + static GrCoordTransform identity; + this->addCoordTransform(&identity); + } if (fMatrix.fKind == SkSL::SampleMatrix::Kind::kConstantOrUniform) { - SkASSERT(matrix.fKind == SkSL::SampleMatrix::Kind::kVariable || - (matrix.fKind == SkSL::SampleMatrix::Kind::kMixed && - matrix.fExpression == fMatrix.fExpression)); - fMatrix = SkSL::SampleMatrix(SkSL::SampleMatrix::Kind::kMixed, fMatrix.fOwner, - fMatrix.fExpression); + if (newMatrix.fKind == SkSL::SampleMatrix::Kind::kConstantOrUniform) { + // need to base this transform on the one that happened in our parent + // If we're already based on something, then we have to assume that parent is now + // based on yet another transform, so don't update our base pointer (or we'll skip + // the intermediate transform). + if (!fMatrix.fBase) { + fMatrix.fBase = newMatrix.fOwner; + } + } else { + SkASSERT(newMatrix.fKind == SkSL::SampleMatrix::Kind::kVariable); + fMatrix.fKind = SkSL::SampleMatrix::Kind::kMixed; + fMatrix.fBase = nullptr; + } } else { SkASSERT(fMatrix.fKind == SkSL::SampleMatrix::Kind::kNone); - fMatrix = matrix; + fMatrix = newMatrix; } - if (matrix.fKind == SkSL::SampleMatrix::Kind::kVariable) { - for (auto& child : fChildProcessors) { - child->setSampleMatrix(matrix); - } + for (auto& child : fChildProcessors) { + child->setSampleMatrix(newMatrix); + } +} + +void GrFragmentProcessor::setSampledWithExplicitCoords() { + fFlags |= kSampledWithExplicitCoords; + for (auto& child : fChildProcessors) { + child->setSampledWithExplicitCoords(); } } @@ -114,7 +135,26 @@ bool GrFragmentProcessor::isInstantiated() const { } #endif -int GrFragmentProcessor::registerChildProcessor(std::unique_ptr<GrFragmentProcessor> child) { +int GrFragmentProcessor::registerChild(std::unique_ptr<GrFragmentProcessor> child, + SkSL::SampleMatrix sampleMatrix, + bool explicitlySampled) { + // Configure child's sampling state first + if (explicitlySampled) { + child->setSampledWithExplicitCoords(); + } + if (sampleMatrix.fKind != SkSL::SampleMatrix::Kind::kNone) { + // FIXME(michaelludwig) - Temporary hack. Owner tracking will be moved off of SampleMatrix + // and into FP. Currently, coord transform compilation fails on sample_matrix GMs if the + // child isn't the owner. But the matrix effect (and expected behavior) require the owner + // to be 'this' FP. + if (this->classID() == kGrMatrixEffect_ClassID) { + sampleMatrix.fOwner = this; + } else { + sampleMatrix.fOwner = child.get(); + } + child->setSampleMatrix(sampleMatrix); + } + if (child->fFlags & kHasCoordTransforms_Flag) { fFlags |= kHasCoordTransforms_Flag; } @@ -127,6 +167,18 @@ int GrFragmentProcessor::registerChildProcessor(std::unique_ptr<GrFragmentProces return index; } +int GrFragmentProcessor::cloneAndRegisterChildProcessor(const GrFragmentProcessor& fp) { + std::unique_ptr<GrFragmentProcessor> clone = fp.clone(); + return this->registerChild(std::move(clone), fp.sampleMatrix(), + fp.isSampledWithExplicitCoords()); +} + +void GrFragmentProcessor::cloneAndRegisterAllChildProcessors(const GrFragmentProcessor& src) { + for (int i = 0; i < src.numChildProcessors(); ++i) { + this->cloneAndRegisterChildProcessor(src.childProcessor(i)); + } +} + bool GrFragmentProcessor::hasSameTransforms(const GrFragmentProcessor& that) const { if (this->numCoordTransforms() != that.numCoordTransforms()) { return false; @@ -156,56 +208,50 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MulInputByChildAlpha( return GrXfermodeFragmentProcessor::MakeFromDstProcessor(std::move(fp), SkBlendMode::kSrcIn); } -std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::PremulInput( - std::unique_ptr<GrFragmentProcessor> fp) { - if (!fp) { - return nullptr; - } - std::unique_ptr<GrFragmentProcessor> fpPipeline[] = { GrPremulInputFragmentProcessor::Make(), - std::move(fp) }; - return GrFragmentProcessor::RunInSeries(fpPipeline, 2); -} - std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ClampPremulOutput( std::unique_ptr<GrFragmentProcessor> fp) { if (!fp) { return nullptr; } - std::unique_ptr<GrFragmentProcessor> fpPipeline[] = { - std::move(fp), - GrClampFragmentProcessor::Make(true) - }; - return GrFragmentProcessor::RunInSeries(fpPipeline, 2); + return GrClampFragmentProcessor::Make(std::move(fp), /*clampToPremul=*/true); } std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::SwizzleOutput( std::unique_ptr<GrFragmentProcessor> fp, const GrSwizzle& swizzle) { class SwizzleFragmentProcessor : public GrFragmentProcessor { public: - static std::unique_ptr<GrFragmentProcessor> Make(const GrSwizzle& swizzle) { - return std::unique_ptr<GrFragmentProcessor>(new SwizzleFragmentProcessor(swizzle)); + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp, + const GrSwizzle& swizzle) { + return std::unique_ptr<GrFragmentProcessor>( + new SwizzleFragmentProcessor(std::move(fp), swizzle)); } const char* name() const override { return "Swizzle"; } const GrSwizzle& swizzle() const { return fSwizzle; } - std::unique_ptr<GrFragmentProcessor> clone() const override { return Make(fSwizzle); } + std::unique_ptr<GrFragmentProcessor> clone() const override { + return Make(this->childProcessor(0).clone(), fSwizzle); + } private: - SwizzleFragmentProcessor(const GrSwizzle& swizzle) - : INHERITED(kSwizzleFragmentProcessor_ClassID, kAll_OptimizationFlags) - , fSwizzle(swizzle) {} + SwizzleFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp, const GrSwizzle& swizzle) + : INHERITED(kSwizzleFragmentProcessor_ClassID, ProcessorOptimizationFlags(fp.get())) + , fSwizzle(swizzle) { + this->registerChild(std::move(fp)); + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { class GLFP : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs& args) override { + SkString childColor = this->invokeChild(0, args.fInputColor, args); + const SwizzleFragmentProcessor& sfp = args.fFp.cast<SwizzleFragmentProcessor>(); const GrSwizzle& swizzle = sfp.swizzle(); GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; fragBuilder->codeAppendf("%s = %s.%s;", - args.fOutputColor, args.fInputColor, swizzle.asString().c_str()); + args.fOutputColor, childColor.c_str(), swizzle.asString().c_str()); } }; return new GLFP; @@ -235,9 +281,7 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::SwizzleOutput( if (GrSwizzle::RGBA() == swizzle) { return fp; } - std::unique_ptr<GrFragmentProcessor> fpPipeline[] = { std::move(fp), - SwizzleFragmentProcessor::Make(swizzle) }; - return GrFragmentProcessor::RunInSeries(fpPipeline, 2); + return SwizzleFragmentProcessor::Make(std::move(fp), swizzle); } std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeInputPremulAndMulByOutput( @@ -259,7 +303,7 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeInputPremulAndMulB private: PremulFragmentProcessor(std::unique_ptr<GrFragmentProcessor> processor) : INHERITED(kPremulFragmentProcessor_ClassID, OptFlags(processor.get())) { - this->registerChildProcessor(std::move(processor)); + this->registerChild(std::move(processor)); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { @@ -359,7 +403,7 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::RunInSeries( : INHERITED(kSeriesFragmentProcessor_ClassID, OptFlags(children, cnt)) { SkASSERT(cnt > 1); for (int i = 0; i < cnt; ++i) { - this->registerChildProcessor(std::move(children[i])); + this->registerChild(std::move(children[i])); } } @@ -400,8 +444,8 @@ std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::RunInSeries( SkPMColor4f knownColor; int leadingFPsToEliminate = info.initialProcessorsToEliminate(&knownColor); if (leadingFPsToEliminate) { - std::unique_ptr<GrFragmentProcessor> colorFP( - GrConstColorProcessor::Make(knownColor, GrConstColorProcessor::InputMode::kIgnore)); + std::unique_ptr<GrFragmentProcessor> colorFP = GrConstColorProcessor::Make( + /*inputFP=*/nullptr, knownColor, GrConstColorProcessor::InputMode::kIgnore); if (leadingFPsToEliminate == cnt) { return colorFP; } diff --git a/chromium/third_party/skia/src/gpu/GrFragmentProcessor.h b/chromium/third_party/skia/src/gpu/GrFragmentProcessor.h index efc4c9ac78b..a0f540eea0e 100644 --- a/chromium/third_party/skia/src/gpu/GrFragmentProcessor.h +++ b/chromium/third_party/skia/src/gpu/GrFragmentProcessor.h @@ -8,6 +8,8 @@ #ifndef GrFragmentProcessor_DEFINED #define GrFragmentProcessor_DEFINED +#include <tuple> + #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrProcessor.h" #include "src/gpu/ops/GrOp.h" @@ -146,19 +148,10 @@ public: return SkToBool(fFlags & kSampledWithExplicitCoords); } - void setSampledWithExplicitCoords() { - fFlags |= kSampledWithExplicitCoords; - for (auto& child : fChildProcessors) { - child->setSampledWithExplicitCoords(); - } - } - SkSL::SampleMatrix sampleMatrix() const { return fMatrix; } - void setSampleMatrix(SkSL::SampleMatrix matrix); - /** * A GrDrawOp may premultiply its antialiasing coverage into its GrGeometryProcessor's color * output under the following scenario: @@ -316,6 +309,13 @@ public: // Sentinel type for range-for using FPItemIter. class FPItemEndIter {}; + // FIXME This should be private, but SkGr needs to mark the dither effect as sampled explicitly + // even though it's not added to another FP. Once varying generation doesn't add a redundant + // varying for it, this can be fully private. + void temporary_SetExplicitlySampled() { + this->setSampledWithExplicitCoords(); + } + protected: enum OptimizationFlags : uint32_t { kNone_OptimizationFlags, @@ -408,8 +408,37 @@ protected: * colors will be combined somehow to produce its output color. Registering these child * processors will allow the ProgramBuilder to automatically handle their transformed coords and * texture accesses and mangle their uniform and output color names. + * + * Depending on the 2nd and 3rd parameters, this corresponds to the following SkSL sample calls: + * - sample(child): Keep default arguments + * - sample(child, matrix): Provide approprate SampleMatrix matching SkSL + * - sample(child, float2): SampleMatrix() and 'true', or use 'registerExplicitlySampledChild' + * - sample(child, matrix)+sample(child, float2): Appropriate SampleMatrix and 'true' */ - int registerChildProcessor(std::unique_ptr<GrFragmentProcessor> child); + int registerChild(std::unique_ptr<GrFragmentProcessor> child, + SkSL::SampleMatrix sampleMatrix = SkSL::SampleMatrix(), + bool explicitlySampled = false); + + /** + * A helper for use when the child is only invoked with sample(float2), and not sample() + * or sample(matrix). + */ + int registerExplicitlySampledChild(std::unique_ptr<GrFragmentProcessor> child) { + return this->registerChild(std::move(child), SkSL::SampleMatrix(), true); + } + + /** + * This method takes an existing fragment processor, clones it, registers it as a child of this + * fragment processor, and returns its child index. It also takes care of any boilerplate in the + * cloning process. + */ + int cloneAndRegisterChildProcessor(const GrFragmentProcessor& fp); + + /** + * This method takes an existing fragment processor, clones all of its children, and registers + * the clones as children of this fragment processor. + */ + void cloneAndRegisterAllChildProcessors(const GrFragmentProcessor& src); void setTextureSamplerCnt(int cnt) { SkASSERT(cnt >= 0); @@ -455,6 +484,10 @@ private: bool hasSameTransforms(const GrFragmentProcessor&) const; + void setSampledWithExplicitCoords(); + + void setSampleMatrix(SkSL::SampleMatrix matrix); + enum PrivateFlags { kFirstPrivateFlag = kAll_OptimizationFlags + 1, kHasCoordTransforms_Flag = kFirstPrivateFlag, @@ -658,4 +691,18 @@ private: Src& fSrc; }; +/** + * Some fragment-processor creation methods have preconditions that might not be satisfied by the + * calling code. Those methods can return a `GrFPResult` from their factory methods. If creation + * succeeds, the new fragment processor is created and `success` is true. If a precondition is not + * met, `success` is set to false and the input FP is returned unchanged. + */ +using GrFPResult = std::tuple<bool /*success*/, std::unique_ptr<GrFragmentProcessor>>; +static inline GrFPResult GrFPFailure(std::unique_ptr<GrFragmentProcessor> fp) { + return {false, std::move(fp)}; +} +static inline GrFPResult GrFPSuccess(std::unique_ptr<GrFragmentProcessor> fp) { + return {true, std::move(fp)}; +} + #endif diff --git a/chromium/third_party/skia/src/gpu/GrGpu.cpp b/chromium/third_party/skia/src/gpu/GrGpu.cpp index 5bc99f00354..195d22e03c0 100644 --- a/chromium/third_party/skia/src/gpu/GrGpu.cpp +++ b/chromium/third_party/skia/src/gpu/GrGpu.cpp @@ -15,6 +15,7 @@ #include "src/core/SkMathPriv.h" #include "src/core/SkMipMap.h" #include "src/gpu/GrAuditTrail.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrCaps.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrDataUtils.h" @@ -42,6 +43,7 @@ static const size_t kMinStagingBufferSize = 32 * 1024; GrGpu::GrGpu(GrContext* context) : fResetBits(kAll_GrBackendState), fContext(context) {} GrGpu::~GrGpu() { + this->callSubmittedProcs(false); SkASSERT(fBusyStagingBuffers.isEmpty()); } @@ -261,7 +263,7 @@ sk_sp<GrTexture> GrGpu::createCompressedTexture(SkISize dimensions, } // TODO: expand CompressedDataIsCorrect to work here too - SkImage::CompressionType compressionType = this->caps()->compressionType(format); + SkImage::CompressionType compressionType = GrBackendFormatToCompressionType(format); if (dataSize < SkCompressedDataSize(compressionType, dimensions, nullptr, mipMapped == GrMipMapped::kYes)) { @@ -657,7 +659,7 @@ void GrGpu::executeFlushInfo(GrSurfaceProxy* proxies[], int numProxies, SkSurface::BackendSurfaceAccess access, const GrFlushInfo& info, - const GrPrepareForExternalIORequests& externalRequests) { + const GrBackendSurfaceMutableState* newState) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); GrResourceProvider* resourceProvider = fContext->priv().resourceProvider(); @@ -671,7 +673,11 @@ void GrGpu::executeFlushInfo(GrSurfaceProxy* proxies[], info.fSignalSemaphores[i], GrResourceProvider::SemaphoreWrapType::kWillSignal, kBorrow_GrWrapOwnership); - this->insertSemaphore(semaphores[i].get()); + // If we failed to wrap the semaphore it means the client didn't give us a valid + // semaphore to begin with. Therefore, it is fine to not signal it. + if (semaphores[i]) { + this->insertSemaphore(semaphores[i].get()); + } } else { semaphores[i] = resourceProvider->makeSemaphore(false); if (semaphores[i]) { @@ -685,8 +691,17 @@ void GrGpu::executeFlushInfo(GrSurfaceProxy* proxies[], if (info.fFinishedProc) { this->addFinishedProc(info.fFinishedProc, info.fFinishedContext); } - this->prepareSurfacesForBackendAccessAndExternalIO(proxies, numProxies, access, - externalRequests); + + if (info.fSubmittedProc) { + fSubmittedProcs.emplace_back(info.fSubmittedProc, info.fSubmittedContext); + } + + // We currently don't support passing in new surface state for multiple proxies here. The only + // time we have multiple proxies is if we are flushing a yuv SkImage which won't have state + // updates anyways. + SkASSERT(!newState || numProxies == 1); + SkASSERT(!newState || access == SkSurface::BackendSurfaceAccess::kNoAccess); + this->prepareSurfacesForBackendAccessAndStateUpdates(proxies, numProxies, access, newState); } bool GrGpu::submitToGpu(bool syncCpu) { @@ -699,9 +714,26 @@ bool GrGpu::submitToGpu(bool syncCpu) { bool submitted = this->onSubmitToGpu(syncCpu); + this->callSubmittedProcs(submitted); + return submitted; } +bool GrGpu::checkAndResetOOMed() { + if (fOOMed) { + fOOMed = false; + return true; + } + return false; +} + +void GrGpu::callSubmittedProcs(bool success) { + for (int i = 0; i < fSubmittedProcs.count(); ++i) { + fSubmittedProcs[i].fProc(fSubmittedProcs[i].fContext, success); + } + fSubmittedProcs.reset(); +} + #ifdef SK_ENABLE_DUMP_GPU void GrGpu::dumpJSON(SkJSONWriter* writer) const { writer->beginObject(); @@ -870,17 +902,11 @@ GrBackendTexture GrGpu::createBackendTexture(SkISize dimensions, } bool GrGpu::updateBackendTexture(const GrBackendTexture& backendTexture, - GrGpuFinishedProc finishedProc, - GrGpuFinishedContext finishedContext, + sk_sp<GrRefCntedCallback> finishedCallback, const BackendTextureData* data) { SkASSERT(data); const GrCaps* caps = this->caps(); - sk_sp<GrRefCntedCallback> callback; - if (finishedProc) { - callback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); - } - if (!backendTexture.isValid()) { return false; } @@ -901,28 +927,22 @@ bool GrGpu::updateBackendTexture(const GrBackendTexture& backendTexture, return false; } - return this->onUpdateBackendTexture(backendTexture, std::move(callback), data); + return this->onUpdateBackendTexture(backendTexture, std::move(finishedCallback), data); } GrBackendTexture GrGpu::createCompressedBackendTexture(SkISize dimensions, const GrBackendFormat& format, GrMipMapped mipMapped, GrProtected isProtected, - GrGpuFinishedProc finishedProc, - GrGpuFinishedContext finishedContext, + sk_sp<GrRefCntedCallback> finishedCallback, const BackendTextureData* data) { - sk_sp<GrRefCntedCallback> callback; - if (finishedProc) { - callback.reset(new GrRefCntedCallback(finishedProc, finishedContext)); - } - const GrCaps* caps = this->caps(); if (!format.isValid()) { return {}; } - SkImage::CompressionType compressionType = caps->compressionType(format); + SkImage::CompressionType compressionType = GrBackendFormatToCompressionType(format); if (compressionType == SkImage::CompressionType::kNone) { // Uncompressed formats must go through the createBackendTexture API return {}; @@ -943,7 +963,7 @@ GrBackendTexture GrGpu::createCompressedBackendTexture(SkISize dimensions, } return this->onCreateCompressedBackendTexture(dimensions, format, mipMapped, - isProtected, std::move(callback), data); + isProtected, std::move(finishedCallback), data); } GrStagingBuffer* GrGpu::findStagingBuffer(size_t size) { diff --git a/chromium/third_party/skia/src/gpu/GrGpu.h b/chromium/third_party/skia/src/gpu/GrGpu.h index 58723df5a05..d93c47fcfc4 100644 --- a/chromium/third_party/skia/src/gpu/GrGpu.h +++ b/chromium/third_party/skia/src/gpu/GrGpu.h @@ -350,8 +350,14 @@ public: // Returns a GrOpsRenderPass which GrOpsTasks send draw commands to instead of directly // to the Gpu object. The 'bounds' rect is the content rect of the renderTarget. + // If a 'stencil' is provided it will be the one bound to 'renderTarget'. If one is not + // provided but 'renderTarget' has a stencil buffer then that is a signal that the + // render target's stencil buffer should be ignored. virtual GrOpsRenderPass* getOpsRenderPass( - GrRenderTarget* renderTarget, GrSurfaceOrigin, const SkIRect& bounds, + GrRenderTarget* renderTarget, + GrStencilAttachment* stencil, + GrSurfaceOrigin, + const SkIRect& bounds, const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) = 0; @@ -361,8 +367,9 @@ public: // insert any numSemaphore semaphores on the gpu and set the backendSemaphores to match the // inserted semaphores. void executeFlushInfo(GrSurfaceProxy*[], int numProxies, - SkSurface::BackendSurfaceAccess access, const GrFlushInfo&, - const GrPrepareForExternalIORequests&); + SkSurface::BackendSurfaceAccess access, + const GrFlushInfo&, + const GrBackendSurfaceMutableState* newState); bool submitToGpu(bool syncCpu); @@ -382,6 +389,12 @@ public: virtual void checkFinishProcs() = 0; /** + * Checks if we detected an OOM from the underlying 3D API and if so returns true and resets + * the internal OOM state to false. Otherwise, returns false. + */ + bool checkAndResetOOMed(); + + /** * Put this texture in a safe and known state for use across multiple GrContexts. Depending on * the backend, this may return a GrSemaphore. If so, other contexts should wait on that * semaphore before using this texture. @@ -600,8 +613,7 @@ public: GrProtected); bool updateBackendTexture(const GrBackendTexture&, - GrGpuFinishedProc finishedProc, - GrGpuFinishedContext finishedContext, + sk_sp<GrRefCntedCallback> finishedCallback, const BackendTextureData*); /** @@ -612,10 +624,21 @@ public: const GrBackendFormat&, GrMipMapped, GrProtected, - GrGpuFinishedProc finishedProc, - GrGpuFinishedContext finishedContext, + sk_sp<GrRefCntedCallback> finishedCallback, const BackendTextureData*); + virtual bool setBackendTextureState(const GrBackendTexture&, + const GrBackendSurfaceMutableState&, + sk_sp<GrRefCntedCallback> finishedCallback) { + return false; + } + + virtual bool setBackendRenderTargetState(const GrBackendRenderTarget&, + const GrBackendSurfaceMutableState&, + sk_sp<GrRefCntedCallback> finishedCallback) { + return false; + } + /** * Frees a texture created by createBackendTexture(). If ownership of the backend * texture has been transferred to a GrContext using adopt semantics this should not be called. @@ -704,6 +727,8 @@ protected: void didWriteToSurface(GrSurface* surface, GrSurfaceOrigin origin, const SkIRect* bounds, uint32_t mipLevels = 1) const; + void setOOMed() { fOOMed = true; } + typedef SkTInternalLList<GrStagingBuffer> StagingBufferList; const StagingBufferList& availableStagingBuffers() { return fAvailableStagingBuffers; } const StagingBufferList& activeStagingBuffers() { return fActiveStagingBuffers; } @@ -815,9 +840,11 @@ private: virtual void addFinishedProc(GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) = 0; - virtual void prepareSurfacesForBackendAccessAndExternalIO( - GrSurfaceProxy* proxies[], int numProxies, SkSurface::BackendSurfaceAccess access, - const GrPrepareForExternalIORequests& externalRequests) {} + virtual void prepareSurfacesForBackendAccessAndStateUpdates( + GrSurfaceProxy* proxies[], + int numProxies, + SkSurface::BackendSurfaceAccess access, + const GrBackendSurfaceMutableState* newState) {} virtual bool onSubmitToGpu(bool syncCpu) = 0; @@ -843,6 +870,8 @@ private: void validateStagingBuffers() const; #endif + void callSubmittedProcs(bool success); + uint32_t fResetBits; // The context owns us, not vice-versa, so this ptr is not ref'ed by Gpu. GrContext* fContext; @@ -854,6 +883,17 @@ private: StagingBufferList fActiveStagingBuffers; StagingBufferList fBusyStagingBuffers; + struct SubmittedProc { + SubmittedProc(GrGpuSubmittedProc proc, GrGpuSubmittedContext context) + : fProc(proc), fContext(context) {} + + GrGpuSubmittedProc fProc; + GrGpuSubmittedContext fContext; + }; + SkSTArray<4, SubmittedProc> fSubmittedProcs; + + bool fOOMed = false; + friend class GrPathRendering; typedef SkRefCnt INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/GrHashMapWithCache.h b/chromium/third_party/skia/src/gpu/GrHashMapWithCache.h new file mode 100644 index 00000000000..8a24ecc525c --- /dev/null +++ b/chromium/third_party/skia/src/gpu/GrHashMapWithCache.h @@ -0,0 +1,84 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrHashMapWithCache_DEFINED +#define GrHashMapWithCache_DEFINED + +#include "include/private/SkChecksum.h" +#include "include/private/SkNoncopyable.h" +#include "include/private/SkTHash.h" + +// Cheaper than SkGoodHash and good enough for UniqueID tables. +struct GrCheapHash { + uint32_t operator()(uint32_t val) { + return SkChecksum::CheapMix(val); + } +}; + +/** A hash map that caches the most recently accessed entry. + The API is a subset of SkHashMap, and you must provide a + sentinel key that will never be present, such as SK_InvalidUniqueID. + + KeyTraits must have: + - static K GetInvalidKey() +*/ +template <typename K, typename V, typename KeyTraits, typename HashT = SkGoodHash> +class GrHashMapWithCache : public SkNoncopyable { +public: + // How many key/value pairs are in the table? + int count() const { return fMap.count(); } + + // Approximately how many bytes of memory do we use beyond sizeof(*this)? + size_t approxBytesUsed() const { return fMap.approxBytesUsed(); } + + // N.B. The pointers returned by set() and find() are valid only until the next call to set(). + + // If there is key/value entry in the table with this key, return a pointer to the value. + // If not, return null. + const V* find(const K& key) const { + if (key != fLastKey) { + fLastKey = key; + fLastValue = fMap.find(key); + } + return fLastValue; + } + + // Set key to val in the map, replacing any previous value with the same key. + // We copy both key and val, and return a pointer to the value copy now in the map. + const V* set(K key, V val) { + if (fLastValue && key == fLastKey) { + *fLastValue = std::move(val); + } else { + fLastKey = key; + fLastValue = fMap.set(std::move(key), std::move(val)); + } + return fLastValue; + } + + // Remove the key/value entry in the table with this key. + void remove(K key) { + // Match SkTHashMap requirement. The caller can find() if they're unsure. + SkASSERT(fMap.find(fLastKey)); + fLastKey = std::move(key); + fLastValue = nullptr; + fMap.remove(fLastKey); + } + + // Clear the map. + void reset() { + fLastKey = KeyTraits::GetInvalidKey(); + fLastValue = nullptr; + fMap.reset(); + } + +private: + SkTHashMap<K, V, HashT> fMap; + mutable K fLastKey = KeyTraits::GetInvalidKey(); + mutable V* fLastValue = nullptr; +}; + +#endif diff --git a/chromium/third_party/skia/src/gpu/GrImageContext.cpp b/chromium/third_party/skia/src/gpu/GrImageContext.cpp index 3f22c1e3ce7..8993a3831bd 100644 --- a/chromium/third_party/skia/src/gpu/GrImageContext.cpp +++ b/chromium/third_party/skia/src/gpu/GrImageContext.cpp @@ -8,33 +8,25 @@ #include "include/private/GrImageContext.h" #include "src/gpu/GrCaps.h" +#include "src/gpu/GrContextThreadSafeProxyPriv.h" #include "src/gpu/GrImageContextPriv.h" #include "src/gpu/GrProxyProvider.h" #include "src/gpu/effects/GrSkSLFP.h" -#define ASSERT_SINGLE_OWNER \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());) - /////////////////////////////////////////////////////////////////////////////////////////////////// -GrImageContext::GrImageContext(GrBackendApi backend, - const GrContextOptions& options, - uint32_t contextID) - : INHERITED(backend, options, contextID) { +GrImageContext::GrImageContext(sk_sp<GrContextThreadSafeProxy> proxy) + : INHERITED(std::move(proxy)) { fProxyProvider.reset(new GrProxyProvider(this)); } GrImageContext::~GrImageContext() {} void GrImageContext::abandonContext() { - ASSERT_SINGLE_OWNER - - fAbandoned = true; + fThreadSafeProxy->priv().abandonContext(); } bool GrImageContext::abandoned() { - ASSERT_SINGLE_OWNER - - return fAbandoned; + return fThreadSafeProxy->priv().abandoned(); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/chromium/third_party/skia/src/gpu/GrLegacyDirectContext.cpp b/chromium/third_party/skia/src/gpu/GrLegacyDirectContext.cpp index f7cae12c15a..4b027eaf3fe 100644 --- a/chromium/third_party/skia/src/gpu/GrLegacyDirectContext.cpp +++ b/chromium/third_party/skia/src/gpu/GrLegacyDirectContext.cpp @@ -31,6 +31,13 @@ #include "src/gpu/dawn/GrDawnGpu.h" #endif +#if GR_TEST_UTILS +# include "include/utils/SkRandom.h" +# if defined(SK_ENABLE_SCOPED_LSAN_SUPPRESSIONS) +# include <sanitizer/lsan_interface.h> +# endif +#endif + #ifdef SK_DISABLE_REDUCE_OPLIST_SPLITTING static const bool kDefaultReduceOpsTaskSplitting = false; #else @@ -40,7 +47,7 @@ static const bool kDefaultReduceOpsTaskSplitting = false; class GrLegacyDirectContext : public GrContext { public: GrLegacyDirectContext(GrBackendApi backend, const GrContextOptions& options) - : INHERITED(backend, options) + : INHERITED(GrContextThreadSafeProxyPriv::Make(backend, options)) , fAtlasManager(nullptr) { } @@ -48,7 +55,7 @@ public: // this if-test protects against the case where the context is being destroyed // before having been fully created if (this->priv().getGpu()) { - this->flush(); + this->flushAndSubmit(); } delete fAtlasManager; @@ -65,23 +72,21 @@ public: } void freeGpuResources() override { - this->flush(); + this->flushAndSubmit(); fAtlasManager->freeAll(); INHERITED::freeGpuResources(); } protected: - bool init(sk_sp<const GrCaps> caps) override { - SkASSERT(caps); - SkASSERT(!fThreadSafeProxy); - - fThreadSafeProxy = GrContextThreadSafeProxyPriv::Make(this->backend(), - this->options(), - this->contextID(), - caps); + bool init() override { + const GrGpu* gpu = this->priv().getGpu(); + if (!gpu) { + return false; + } - if (!INHERITED::init(std::move(caps))) { + fThreadSafeProxy->priv().init(gpu->refCaps()); + if (!INHERITED::init()) { return false; } @@ -94,8 +99,6 @@ protected: this->setupDrawingManager(true, reduceOpsTaskSplitting); - SkASSERT(this->caps()); - GrDrawOpAtlas::AllowMultitexturing allowMultitexturing; if (GrContextOptions::Enable::kNo == this->options().fAllowMultipleGlyphCacheTextures || // multitexturing supported only if range can represent the index + texcoords fully @@ -139,16 +142,52 @@ sk_sp<GrContext> GrContext::MakeGL() { return MakeGL(nullptr, defaultOptions); } +#if GR_TEST_UTILS +GrGLFunction<GrGLGetErrorFn> make_get_error_with_random_oom(GrGLFunction<GrGLGetErrorFn> original) { + // A SkRandom and a GrGLFunction<GrGLGetErrorFn> are too big to be captured by a + // GrGLFunction<GrGLGetError> (surprise, surprise). So we make a context object and + // capture that by pointer. However, GrGLFunction doesn't support calling a destructor + // on the thing it captures. So we leak the context. + struct GetErrorContext { + SkRandom fRandom; + GrGLFunction<GrGLGetErrorFn> fGetError; + }; + + auto errorContext = new GetErrorContext; + +#if defined(SK_ENABLE_SCOPED_LSAN_SUPPRESSIONS) + __lsan_ignore_object(errorContext); +#endif + + errorContext->fGetError = original; + + return GrGLFunction<GrGLGetErrorFn>([errorContext]() { + GrGLenum error = errorContext->fGetError(); + if (error == GR_GL_NO_ERROR && (errorContext->fRandom.nextU() % 300) == 0) { + error = GR_GL_OUT_OF_MEMORY; + } + return error; + }); +} +#endif + sk_sp<GrContext> GrContext::MakeGL(sk_sp<const GrGLInterface> glInterface, const GrContextOptions& options) { sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kOpenGL, options)); - - context->fGpu = GrGLGpu::Make(std::move(glInterface), options, context.get()); - if (!context->fGpu) { - return nullptr; +#if GR_TEST_UTILS + if (options.fRandomGLOOM) { + auto copy = sk_make_sp<GrGLInterface>(*glInterface); + copy->fFunctions.fGetError = + make_get_error_with_random_oom(glInterface->fFunctions.fGetError); +#if GR_GL_CHECK_ERROR + // Suppress logging GL errors since we'll be synthetically generating them. + copy->suppressErrorLogging(); +#endif + glInterface = std::move(copy); } - - if (!context->init(context->fGpu->refCaps())) { +#endif + context->fGpu = GrGLGpu::Make(std::move(glInterface), options, context.get()); + if (!context->init()) { return nullptr; } return context; @@ -165,11 +204,7 @@ sk_sp<GrContext> GrContext::MakeMock(const GrMockOptions* mockOptions, sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kMock, options)); context->fGpu = GrMockGpu::Make(mockOptions, options, context.get()); - if (!context->fGpu) { - return nullptr; - } - - if (!context->init(context->fGpu->refCaps())) { + if (!context->init()) { return nullptr; } @@ -191,13 +226,10 @@ sk_sp<GrContext> GrContext::MakeVulkan(const GrVkBackendContext& backendContext, sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kVulkan, options)); context->fGpu = GrVkGpu::Make(backendContext, options, context.get()); - if (!context->fGpu) { + if (!context->init()) { return nullptr; } - if (!context->init(context->fGpu->refCaps())) { - return nullptr; - } return context; #else return nullptr; @@ -214,13 +246,10 @@ sk_sp<GrContext> GrContext::MakeMetal(void* device, void* queue, const GrContext sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kMetal, options)); context->fGpu = GrMtlTrampoline::MakeGpu(context.get(), options, device, queue); - if (!context->fGpu) { + if (!context->init()) { return nullptr; } - if (!context->init(context->fGpu->refCaps())) { - return nullptr; - } return context; } #endif @@ -236,13 +265,10 @@ sk_sp<GrContext> GrContext::MakeDirect3D(const GrD3DBackendContext& backendConte sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kDirect3D, options)); context->fGpu = GrD3DGpu::Make(backendContext, options, context.get()); - if (!context->fGpu) { + if (!context->init()) { return nullptr; } - if (!context->init(context->fGpu->refCaps())) { - return nullptr; - } return context; } #endif @@ -257,13 +283,10 @@ sk_sp<GrContext> GrContext::MakeDawn(const wgpu::Device& device, const GrContext sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kDawn, options)); context->fGpu = GrDawnGpu::Make(device, options, context.get()); - if (!context->fGpu) { + if (!context->init()) { return nullptr; } - if (!context->init(context->fGpu->refCaps())) { - return nullptr; - } return context; } #endif diff --git a/chromium/third_party/skia/src/gpu/GrOnFlushResourceProvider.cpp b/chromium/third_party/skia/src/gpu/GrOnFlushResourceProvider.cpp index 0ca9f13ef47..93bf9dbe0df 100644 --- a/chromium/third_party/skia/src/gpu/GrOnFlushResourceProvider.cpp +++ b/chromium/third_party/skia/src/gpu/GrOnFlushResourceProvider.cpp @@ -52,12 +52,12 @@ void GrOnFlushResourceProvider::addTextureResolveTask(sk_sp<GrTextureProxy> text // Since we are bypassing normal DAG operation, we need to ensure the textureProxy's last render // task gets closed before making a texture resolve task. makeClosed is what will mark msaa and // mipmaps dirty. - if (GrRenderTask* renderTask = textureProxy->getLastRenderTask()) { + if (GrRenderTask* renderTask = fDrawingMgr->getLastRenderTask(textureProxy.get())) { renderTask->makeClosed(*this->caps()); } auto task = static_cast<GrTextureResolveRenderTask*>(fDrawingMgr->fOnFlushRenderTasks.push_back( sk_make_sp<GrTextureResolveRenderTask>()).get()); - task->addProxy(std::move(textureProxy), resolveFlags, *this->caps()); + task->addProxy(fDrawingMgr, std::move(textureProxy), resolveFlags, *this->caps()); task->makeClosed(*this->caps()); } diff --git a/chromium/third_party/skia/src/gpu/GrOpFlushState.cpp b/chromium/third_party/skia/src/gpu/GrOpFlushState.cpp index dfaa9d6e73c..8bc88f0d091 100644 --- a/chromium/third_party/skia/src/gpu/GrOpFlushState.cpp +++ b/chromium/third_party/skia/src/gpu/GrOpFlushState.cpp @@ -194,7 +194,7 @@ void GrOpFlushState::putBackVertices(int vertices, size_t vertexStride) { } GrAppliedClip GrOpFlushState::detachAppliedClip() { - return fOpArgs->appliedClip() ? std::move(*fOpArgs->appliedClip()) : GrAppliedClip(); + return fOpArgs->appliedClip() ? std::move(*fOpArgs->appliedClip()) : GrAppliedClip::Disabled(); } GrStrikeCache* GrOpFlushState::strikeCache() const { diff --git a/chromium/third_party/skia/src/gpu/GrOpsRenderPass.cpp b/chromium/third_party/skia/src/gpu/GrOpsRenderPass.cpp index 66e346b82fe..07b4eeebe3a 100644 --- a/chromium/third_party/skia/src/gpu/GrOpsRenderPass.cpp +++ b/chromium/third_party/skia/src/gpu/GrOpsRenderPass.cpp @@ -11,12 +11,13 @@ #include "include/gpu/GrContext.h" #include "src/gpu/GrCaps.h" #include "src/gpu/GrContextPriv.h" -#include "src/gpu/GrFixedClip.h" +#include "src/gpu/GrCpuBuffer.h" #include "src/gpu/GrGpu.h" #include "src/gpu/GrPrimitiveProcessor.h" #include "src/gpu/GrProgramInfo.h" #include "src/gpu/GrRenderTarget.h" #include "src/gpu/GrRenderTargetPriv.h" +#include "src/gpu/GrScissorState.h" #include "src/gpu/GrSimpleMesh.h" #include "src/gpu/GrTexturePriv.h" @@ -37,21 +38,22 @@ void GrOpsRenderPass::end() { this->resetActiveBuffers(); } -void GrOpsRenderPass::clear(const GrFixedClip& clip, const SkPMColor4f& color) { +void GrOpsRenderPass::clear(const GrScissorState& scissor, const SkPMColor4f& color) { SkASSERT(fRenderTarget); // A clear at this level will always be a true clear, so make sure clears were not supposed to // be redirected to draws instead SkASSERT(!this->gpu()->caps()->performColorClearsAsDraws()); - SkASSERT(!clip.scissorEnabled() || !this->gpu()->caps()->performPartialClearsAsDraws()); + SkASSERT(!scissor.enabled() || !this->gpu()->caps()->performPartialClearsAsDraws()); fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured; - this->onClear(clip, color); + this->onClear(scissor, color); } -void GrOpsRenderPass::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) { +void GrOpsRenderPass::clearStencilClip(const GrScissorState& scissor, bool insideStencilMask) { // As above, make sure the stencil clear wasn't supposed to be a draw rect with stencil settings SkASSERT(!this->gpu()->caps()->performStencilClearsAsDraws()); + SkASSERT(!scissor.enabled() || !this->gpu()->caps()->performPartialClearsAsDraws()); fDrawPipelineStatus = DrawPipelineStatus::kNotConfigured; - this->onClearStencilClip(clip, insideStencilMask); + this->onClearStencilClip(scissor, insideStencilMask); } void GrOpsRenderPass::executeDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler> drawable) { diff --git a/chromium/third_party/skia/src/gpu/GrOpsRenderPass.h b/chromium/third_party/skia/src/gpu/GrOpsRenderPass.h index 959d1a222f6..ec7960f366c 100644 --- a/chromium/third_party/skia/src/gpu/GrOpsRenderPass.h +++ b/chromium/third_party/skia/src/gpu/GrOpsRenderPass.h @@ -13,12 +13,12 @@ #include "src/gpu/ops/GrDrawOp.h" class GrOpFlushState; -class GrFixedClip; class GrGpu; class GrPipeline; class GrPrimitiveProcessor; class GrProgramInfo; class GrRenderTarget; +class GrScissorState; class GrSemaphore; struct SkIRect; struct SkRect; @@ -120,11 +120,17 @@ public: virtual void inlineUpload(GrOpFlushState*, GrDeferredTextureUploadFn&) = 0; /** - * Clear the owned render target. Ignores the draw state and clip. + * Clear the owned render target. Clears the full target if 'scissor' is disabled, otherwise it + * is restricted to 'scissor'. Must check caps.performPartialClearsAsDraws() before using an + * enabled scissor test; must check caps.performColorClearsAsDraws() before using this at all. */ - void clear(const GrFixedClip&, const SkPMColor4f&); + void clear(const GrScissorState& scissor, const SkPMColor4f&); - void clearStencilClip(const GrFixedClip&, bool insideStencilMask); + /** + * Same as clear() but modifies the stencil; check caps.performStencilClearsAsDraws() and + * caps.performPartialClearsAsDraws(). + */ + void clearStencilClip(const GrScissorState& scissor, bool insideStencilMask); /** * Executes the SkDrawable object for the underlying backend. @@ -189,8 +195,8 @@ private: virtual void onDrawIndexedIndirect(const GrBuffer*, size_t offset, int drawCount) { SK_ABORT("Not implemented."); // Only called if caps.nativeDrawIndirectSupport(). } - virtual void onClear(const GrFixedClip&, const SkPMColor4f&) = 0; - virtual void onClearStencilClip(const GrFixedClip&, bool insideStencilMask) = 0; + virtual void onClear(const GrScissorState&, const SkPMColor4f&) = 0; + virtual void onClearStencilClip(const GrScissorState&, bool insideStencilMask) = 0; virtual void onExecuteDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>) {} enum class DrawPipelineStatus { diff --git a/chromium/third_party/skia/src/gpu/GrOpsTask.cpp b/chromium/third_party/skia/src/gpu/GrOpsTask.cpp index c811883d774..1f0a55f747d 100644 --- a/chromium/third_party/skia/src/gpu/GrOpsTask.cpp +++ b/chromium/third_party/skia/src/gpu/GrOpsTask.cpp @@ -357,14 +357,14 @@ inline void GrOpsTask::OpChain::validate() const { //////////////////////////////////////////////////////////////////////////////// -GrOpsTask::GrOpsTask(GrRecordingContext::Arenas arenas, +GrOpsTask::GrOpsTask(GrDrawingManager* drawingMgr, GrRecordingContext::Arenas arenas, GrSurfaceProxyView view, GrAuditTrail* auditTrail) - : GrRenderTask(std::move(view)) + : GrRenderTask() , fArenas(arenas) , fAuditTrail(auditTrail) SkDEBUGCODE(, fNumClips(0)) { - fTargetView.proxy()->setLastRenderTask(this); + this->addTarget(drawingMgr, std::move(view)); } void GrOpsTask::deleteOps() { @@ -388,20 +388,16 @@ void GrOpsTask::removeClosedObserver(GrOpsTaskClosedObserver* observer) { } } -void GrOpsTask::endFlush() { +void GrOpsTask::endFlush(GrDrawingManager* drawingMgr) { fLastClipStackGenID = SK_InvalidUniqueID; this->deleteOps(); fClipAllocator.reset(); - GrSurfaceProxy* proxy = fTargetView.proxy(); - if (proxy && this == proxy->getLastRenderTask()) { - proxy->setLastRenderTask(nullptr); - } - - fTargetView.reset(); fDeferredProxies.reset(); fSampledProxies.reset(); fAuditTrail = nullptr; + + GrRenderTask::endFlush(drawingMgr); } void GrOpsTask::onPrePrepare(GrRecordingContext* context) { @@ -420,7 +416,7 @@ void GrOpsTask::onPrePrepare(GrRecordingContext* context) { for (const auto& chain : fOpChains) { if (chain.shouldExecute()) { chain.head()->prePrepare(context, - &fTargetView, + &fTargets[0], chain.appliedClip(), chain.dstProxyView()); } @@ -428,7 +424,7 @@ void GrOpsTask::onPrePrepare(GrRecordingContext* context) { } void GrOpsTask::onPrepare(GrOpFlushState* flushState) { - SkASSERT(fTargetView.proxy()->peekRenderTarget()); + SkASSERT(this->target(0).proxy()->peekRenderTarget()); SkASSERT(this->isClosed()); #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK TRACE_EVENT0("skia.gpu", TRACE_FUNC); @@ -449,7 +445,7 @@ void GrOpsTask::onPrepare(GrOpFlushState* flushState) { TRACE_EVENT0("skia.gpu", chain.head()->name()); #endif GrOpFlushState::OpArgs opArgs(chain.head(), - &fTargetView, + &fTargets[0], chain.appliedClip(), chain.dstProxyView()); @@ -457,7 +453,7 @@ void GrOpsTask::onPrepare(GrOpFlushState* flushState) { // Temporary debugging helper: for debugging prePrepare w/o going through DDLs // Delete once most of the GrOps have an onPrePrepare. - // chain.head()->prePrepare(flushState->gpu()->getContext(), &fTargetView, + // chain.head()->prePrepare(flushState->gpu()->getContext(), &this->target(0), // chain.appliedClip()); // GrOp::prePrepare may or may not have been called at this point @@ -469,9 +465,10 @@ void GrOpsTask::onPrepare(GrOpFlushState* flushState) { } static GrOpsRenderPass* create_render_pass( - GrGpu* gpu, GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds, - GrLoadOp colorLoadOp, const SkPMColor4f& loadClearColor, GrLoadOp stencilLoadOp, - GrStoreOp stencilStoreOp, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { + GrGpu* gpu, GrRenderTarget* rt, GrStencilAttachment* stencil, GrSurfaceOrigin origin, + const SkIRect& bounds, GrLoadOp colorLoadOp, const SkPMColor4f& loadClearColor, + GrLoadOp stencilLoadOp, GrStoreOp stencilStoreOp, + const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { const GrOpsRenderPass::LoadAndStoreInfo kColorLoadStoreInfo { colorLoadOp, GrStoreOp::kStore, @@ -488,8 +485,8 @@ static GrOpsRenderPass* create_render_pass( stencilStoreOp, }; - return gpu->getOpsRenderPass(rt, origin, bounds, kColorLoadStoreInfo, stencilLoadAndStoreInfo, - sampledProxies); + return gpu->getOpsRenderPass(rt, stencil, origin, bounds, + kColorLoadStoreInfo, stencilLoadAndStoreInfo, sampledProxies); } // TODO: this is where GrOp::renderTarget is used (which is fine since it @@ -504,8 +501,8 @@ bool GrOpsTask::onExecute(GrOpFlushState* flushState) { return false; } - SkASSERT(fTargetView.proxy()); - GrRenderTargetProxy* proxy = fTargetView.proxy()->asRenderTargetProxy(); + SkASSERT(this->numTargets() == 1); + GrRenderTargetProxy* proxy = this->target(0).proxy()->asRenderTargetProxy(); SkASSERT(proxy); TRACE_EVENT0("skia.gpu", TRACE_FUNC); @@ -553,6 +550,7 @@ bool GrOpsTask::onExecute(GrOpFlushState* flushState) { // once finished, meaning the stencil values will always remain cleared after the // initial clear. Just fall through to reloading the existing (cleared) stencil values // from memory. + [[fallthrough]]; case StencilContent::kPreserved: SkASSERT(stencil); stencilLoadOp = GrLoadOp::kLoad; @@ -571,7 +569,7 @@ bool GrOpsTask::onExecute(GrOpFlushState* flushState) { : GrStoreOp::kStore; GrOpsRenderPass* renderPass = create_render_pass( - flushState->gpu(), proxy->peekRenderTarget(), fTargetView.origin(), + flushState->gpu(), proxy->peekRenderTarget(), stencil, this->target(0).origin(), fClippedContentBounds, fColorLoadOp, fLoadClearColor, stencilLoadOp, stencilStoreOp, fSampledProxies); if (!renderPass) { @@ -590,7 +588,7 @@ bool GrOpsTask::onExecute(GrOpFlushState* flushState) { #endif GrOpFlushState::OpArgs opArgs(chain.head(), - &fTargetView, + &fTargets[0], chain.appliedClip(), chain.dstProxyView()); @@ -610,9 +608,9 @@ void GrOpsTask::setColorLoadOp(GrLoadOp op, const SkPMColor4f& color) { fColorLoadOp = op; fLoadClearColor = color; if (GrLoadOp::kClear == fColorLoadOp) { - GrSurfaceProxy* proxy = fTargetView.proxy(); + GrSurfaceProxy* proxy = this->target(0).proxy(); SkASSERT(proxy); - fTotalBounds = proxy->getBoundsRect(); + fTotalBounds = proxy->backingStoreBoundsRect(); } } @@ -631,7 +629,7 @@ bool GrOpsTask::resetForFullscreenClear(CanDiscardPreviousOps canDiscardPrevious // If the opsTask is using a render target which wraps a vulkan command buffer, we can't do // a clear load since we cannot change the render pass that we are using. Thus we fall back // to making a clear op in this case. - return !fTargetView.asRenderTargetProxy()->wrapsVkSecondaryCB(); + return !this->target(0).asRenderTargetProxy()->wrapsVkSecondaryCB(); } // Could not empty the task, so an op must be added to handle the clear @@ -757,7 +755,7 @@ void GrOpsTask::gatherProxyIntervals(GrResourceAllocator* alloc) const { alloc->addInterval(fDeferredProxies[i], 0, 0, GrResourceAllocator::ActualUse::kNo); } - GrSurfaceProxy* targetProxy = fTargetView.proxy(); + GrSurfaceProxy* targetProxy = this->target(0).proxy(); // Add the interval for all the writes to this GrOpsTasks's target if (fOpChains.count()) { @@ -776,7 +774,7 @@ void GrOpsTask::gatherProxyIntervals(GrResourceAllocator* alloc) const { auto gather = [ alloc SkDEBUGCODE(, this) ] (GrSurfaceProxy* p, GrMipMapped) { alloc->addInterval(p, alloc->curOp(), alloc->curOp(), GrResourceAllocator::ActualUse::kYes - SkDEBUGCODE(, fTargetView.proxy() == p)); + SkDEBUGCODE(, this->target(0).proxy() == p)); }; for (const OpChain& recordedOp : fOpChains) { recordedOp.visitProxies(gather); @@ -792,7 +790,7 @@ void GrOpsTask::recordOp( const DstProxyView* dstProxyView, const GrCaps& caps) { SkDEBUGCODE(op->validate();) SkASSERT(processorAnalysis.requiresDstTexture() == (dstProxyView && dstProxyView->proxy())); - GrSurfaceProxy* proxy = fTargetView.proxy(); + GrSurfaceProxy* proxy = this->target(0).proxy(); SkASSERT(proxy); // A closed GrOpsTask should never receive new/more ops @@ -892,9 +890,11 @@ GrRenderTask::ExpectedOutcome GrOpsTask::onMakeClosed( fClosedObservers.reset(); }); if (!this->isNoOp()) { - GrSurfaceProxy* proxy = fTargetView.proxy(); - SkRect clippedContentBounds = proxy->getBoundsRect(); - // TODO: If we can fix up GLPrograms test to always intersect the fTargetView proxy bounds + GrSurfaceProxy* proxy = this->target(0).proxy(); + // Use the entire backing store bounds since the GPU doesn't clip automatically to the + // logical dimensions. + SkRect clippedContentBounds = proxy->backingStoreBoundsRect(); + // TODO: If we can fix up GLPrograms test to always intersect the target proxy bounds // then we can simply assert here that the bounds intersect. if (clippedContentBounds.intersect(fTotalBounds)) { clippedContentBounds.roundOut(&fClippedContentBounds); diff --git a/chromium/third_party/skia/src/gpu/GrOpsTask.h b/chromium/third_party/skia/src/gpu/GrOpsTask.h index 0baf847e282..a40a51a9edd 100644 --- a/chromium/third_party/skia/src/gpu/GrOpsTask.h +++ b/chromium/third_party/skia/src/gpu/GrOpsTask.h @@ -51,7 +51,7 @@ private: public: // The Arenas must outlive the GrOpsTask, either by preserving the context that owns // the pool, or by moving the pool to the DDL that takes over the GrOpsTask. - GrOpsTask(GrRecordingContext::Arenas, GrSurfaceProxyView, GrAuditTrail*); + GrOpsTask(GrDrawingManager*, GrRecordingContext::Arenas, GrSurfaceProxyView, GrAuditTrail*); ~GrOpsTask() override; GrOpsTask* asOpsTask() override { return this; } @@ -68,7 +68,7 @@ public: /** * Empties the draw buffer of any queued up draws. */ - void endFlush() override; + void endFlush(GrDrawingManager*) override; void onPrePrepare(GrRecordingContext*) override; /** @@ -88,11 +88,11 @@ public: fSampledProxies.push_back(proxy); } - void addOp(std::unique_ptr<GrOp> op, GrTextureResolveManager textureResolveManager, - const GrCaps& caps) { - auto addDependency = [ textureResolveManager, &caps, this ] ( + void addOp(GrDrawingManager* drawingMgr, std::unique_ptr<GrOp> op, + GrTextureResolveManager textureResolveManager, const GrCaps& caps) { + auto addDependency = [ drawingMgr, textureResolveManager, &caps, this ] ( GrSurfaceProxy* p, GrMipMapped mipmapped) { - this->addDependency(p, mipmapped, textureResolveManager, caps); + this->addDependency(drawingMgr, p, mipmapped, textureResolveManager, caps); }; op->visitProxies(addDependency); @@ -100,19 +100,20 @@ public: this->recordOp(std::move(op), GrProcessorSet::EmptySetAnalysis(), nullptr, nullptr, caps); } - void addWaitOp(std::unique_ptr<GrOp> op, GrTextureResolveManager textureResolveManager, - const GrCaps& caps) { + void addWaitOp(GrDrawingManager* drawingMgr, std::unique_ptr<GrOp> op, + GrTextureResolveManager textureResolveManager, const GrCaps& caps) { fHasWaitOp = true; - this->addOp(std::move(op), textureResolveManager, caps); + this->addOp(drawingMgr, std::move(op), textureResolveManager, caps); } - void addDrawOp(std::unique_ptr<GrDrawOp> op, const GrProcessorSet::Analysis& processorAnalysis, + void addDrawOp(GrDrawingManager* drawingMgr, std::unique_ptr<GrDrawOp> op, + const GrProcessorSet::Analysis& processorAnalysis, GrAppliedClip&& clip, const DstProxyView& dstProxyView, GrTextureResolveManager textureResolveManager, const GrCaps& caps) { - auto addDependency = [ textureResolveManager, &caps, this ] ( + auto addDependency = [ drawingMgr, textureResolveManager, &caps, this ] ( GrSurfaceProxy* p, GrMipMapped mipmapped) { this->addSampledTexture(p); - this->addDependency(p, mipmapped, textureResolveManager, caps); + this->addDependency(drawingMgr, p, mipmapped, textureResolveManager, caps); }; op->visitProxies(addDependency); diff --git a/chromium/third_party/skia/src/gpu/GrPathRenderer.h b/chromium/third_party/skia/src/gpu/GrPathRenderer.h index 47e65362c11..0866e0106c4 100644 --- a/chromium/third_party/skia/src/gpu/GrPathRenderer.h +++ b/chromium/third_party/skia/src/gpu/GrPathRenderer.h @@ -14,7 +14,6 @@ class GrCaps; class GrClip; -class GrFixedClip; class GrHardClip; class GrPaint; class GrRecordingContext; @@ -127,7 +126,6 @@ public: SkASSERT(fContext); SkASSERT(fUserStencilSettings); SkASSERT(fRenderTargetContext); - SkASSERT(fClip); SkASSERT(fClipConservativeBounds); SkASSERT(fViewMatrix); SkASSERT(fShape); diff --git a/chromium/third_party/skia/src/gpu/GrPathRendererChain.cpp b/chromium/third_party/skia/src/gpu/GrPathRendererChain.cpp index ca2d7e4c867..cf7e271f306 100644 --- a/chromium/third_party/skia/src/gpu/GrPathRendererChain.cpp +++ b/chromium/third_party/skia/src/gpu/GrPathRendererChain.cpp @@ -32,7 +32,7 @@ GrPathRendererChain::GrPathRendererChain(GrRecordingContext* context, const Opti fChain.push_back(sk_make_sp<GrDashLinePathRenderer>()); } if (options.fGpuPathRenderers & GpuPathRenderers::kTessellation) { - if (caps.shaderCaps()->tessellationSupport() && caps.drawInstancedSupport()) { + if (caps.drawInstancedSupport()) { auto tess = sk_make_sp<GrTessellationPathRenderer>(caps); context->priv().addOnFlushCallbackObject(tess.get()); fChain.push_back(std::move(tess)); diff --git a/chromium/third_party/skia/src/gpu/GrPersistentCacheUtils.h b/chromium/third_party/skia/src/gpu/GrPersistentCacheUtils.h index fe932c26194..d6a15e73280 100644 --- a/chromium/third_party/skia/src/gpu/GrPersistentCacheUtils.h +++ b/chromium/third_party/skia/src/gpu/GrPersistentCacheUtils.h @@ -10,8 +10,8 @@ #include "include/core/SkData.h" #include "include/private/GrTypesPriv.h" -#include "src/core/SkReader32.h" -#include "src/core/SkWriter32.h" +#include "src/core/SkReadBuffer.h" +#include "src/core/SkWriteBuffer.h" #include "src/sksl/SkSLString.h" #include "src/sksl/ir/SkSLProgram.h" @@ -28,7 +28,7 @@ struct ShaderMetadata { }; // Increment this whenever the serialization format of cached shaders changes -static constexpr int kCurrentVersion = 1; +static constexpr int kCurrentVersion = 2; static inline sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType, const SkSL::String shaders[], @@ -39,12 +39,12 @@ static inline sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType, // kGrShaderTypeCount inputs. If the backend gives us fewer, we just replicate the last one. SkASSERT(numInputs >= 1 && numInputs <= kGrShaderTypeCount); - SkWriter32 writer; - writer.write32(kCurrentVersion); - writer.write32(shaderType); + SkBinaryWriteBuffer writer; + writer.writeInt(kCurrentVersion); + writer.writeUInt(shaderType); for (int i = 0; i < kGrShaderTypeCount; ++i) { - writer.writeString(shaders[i].c_str(), shaders[i].size()); - writer.writePad(&inputs[std::min(i, numInputs - 1)], sizeof(SkSL::Program::Inputs)); + writer.writeByteArray(shaders[i].c_str(), shaders[i].size()); + writer.writePad32(&inputs[std::min(i, numInputs - 1)], sizeof(SkSL::Program::Inputs)); } writer.writeBool(SkToBool(meta)); if (meta) { @@ -57,7 +57,7 @@ static inline sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType, writer.writeInt(meta->fAttributeNames.count()); for (const auto& attr : meta->fAttributeNames) { - writer.writeString(attr.c_str(), attr.size()); + writer.writeByteArray(attr.c_str(), attr.size()); } writer.writeBool(meta->fHasCustomColorOutput); @@ -66,30 +66,28 @@ static inline sk_sp<SkData> PackCachedShaders(SkFourByteTag shaderType, return writer.snapshotAsData(); } -static SkFourByteTag GetType(SkReader32* reader) { +static SkFourByteTag GetType(SkReadBuffer* reader) { constexpr SkFourByteTag kInvalidTag = ~0; - if (!reader->isAvailable(2 * sizeof(int))) { - return kInvalidTag; - } - if (reader->readInt() != kCurrentVersion) { - return kInvalidTag; - } - return reader->readU32(); + int version = reader->readInt(); + SkFourByteTag typeTag = reader->readUInt(); + return reader->validate(version == kCurrentVersion) ? typeTag : kInvalidTag; } -static inline void UnpackCachedShaders(SkReader32* reader, +static inline bool UnpackCachedShaders(SkReadBuffer* reader, SkSL::String shaders[], SkSL::Program::Inputs inputs[], int numInputs, ShaderMetadata* meta = nullptr) { for (int i = 0; i < kGrShaderTypeCount; ++i) { - size_t stringLen = 0; - const char* string = reader->readString(&stringLen); - shaders[i] = SkSL::String(string, stringLen); + size_t shaderLen = 0; + const char* shaderBuf = static_cast<const char*>(reader->skipByteArray(&shaderLen)); + if (shaderBuf) { + shaders[i].assign(shaderBuf, shaderLen); + } // GL, for example, only wants one set of Inputs if (i < numInputs) { - reader->read(&inputs[i], sizeof(inputs[i])); + reader->readPad32(&inputs[i], sizeof(inputs[i])); } else { reader->skip(sizeof(SkSL::Program::Inputs)); } @@ -104,15 +102,24 @@ static inline void UnpackCachedShaders(SkReader32* reader, } meta->fAttributeNames.resize(reader->readInt()); - for (int i = 0; i < meta->fAttributeNames.count(); ++i) { - size_t stringLen = 0; - const char* string = reader->readString(&stringLen); - meta->fAttributeNames[i] = SkSL::String(string, stringLen); + for (auto& attr : meta->fAttributeNames) { + size_t attrLen = 0; + const char* attrName = static_cast<const char*>(reader->skipByteArray(&attrLen)); + if (attrName) { + attr.assign(attrName, attrLen); + } } meta->fHasCustomColorOutput = reader->readBool(); meta->fHasSecondaryColorOutput = reader->readBool(); } + + if (!reader->isValid()) { + for (int i = 0; i < kGrShaderTypeCount; ++i) { + shaders[i].clear(); + } + } + return reader->isValid(); } } diff --git a/chromium/third_party/skia/src/gpu/GrPrimitiveProcessor.h b/chromium/third_party/skia/src/gpu/GrPrimitiveProcessor.h index 40d4c93d586..c7741833f55 100644 --- a/chromium/third_party/skia/src/gpu/GrPrimitiveProcessor.h +++ b/chromium/third_party/skia/src/gpu/GrPrimitiveProcessor.h @@ -36,6 +36,7 @@ class GrCoordTransform; */ class GrGLSLPrimitiveProcessor; +class GrGLSLUniformHandler; /** * GrPrimitiveProcessor defines an interface which all subclasses must implement. All @@ -56,12 +57,14 @@ public: constexpr Attribute(const char* name, GrVertexAttribType cpuType, GrSLType gpuType) - : fName(name), fCPUType(cpuType), fGPUType(gpuType) {} + : fName(name), fCPUType(cpuType), fGPUType(gpuType) { + SkASSERT(name && gpuType != kVoid_GrSLType); + } constexpr Attribute(const Attribute&) = default; Attribute& operator=(const Attribute&) = default; - constexpr bool isInitialized() const { return SkToBool(fName); } + constexpr bool isInitialized() const { return fGPUType != kVoid_GrSLType; } constexpr const char* name() const { return fName; } constexpr GrVertexAttribType cpuType() const { return fCPUType; } @@ -77,7 +80,7 @@ public: private: const char* fName = nullptr; GrVertexAttribType fCPUType = kFloat_GrVertexAttribType; - GrSLType fGPUType = kFloat_GrSLType; + GrSLType fGPUType = kVoid_GrSLType; }; class Iter { @@ -213,11 +216,15 @@ public: // We use these methods as a temporary back door to inject OpenGL tessellation code. Once // tessellation is supported by SkSL we can remove these. - virtual SkString getTessControlShaderGLSL(const char* versionAndExtensionDecls, + virtual SkString getTessControlShaderGLSL(const GrGLSLPrimitiveProcessor*, + const char* versionAndExtensionDecls, + const GrGLSLUniformHandler&, const GrShaderCaps&) const { SK_ABORT("Not implemented."); } - virtual SkString getTessEvaluationShaderGLSL(const char* versionAndExtensionDecls, + virtual SkString getTessEvaluationShaderGLSL(const GrGLSLPrimitiveProcessor*, + const char* versionAndExtensionDecls, + const GrGLSLUniformHandler&, const GrShaderCaps&) const { SK_ABORT("Not implemented."); } diff --git a/chromium/third_party/skia/src/gpu/GrProcessor.h b/chromium/third_party/skia/src/gpu/GrProcessor.h index cb4711c6960..80ec7e390a1 100644 --- a/chromium/third_party/skia/src/gpu/GrProcessor.h +++ b/chromium/third_party/skia/src/gpu/GrProcessor.h @@ -125,7 +125,6 @@ public: kGrPathProcessor_ClassID, kGrPerlinNoise2Effect_ClassID, kGrPipelineDynamicStateTestProcessor_ClassID, - kGrPremulInputFragmentProcessor_ClassID, kGrQuadEffect_ClassID, kGrRadialGradientLayout_ClassID, kGrRectBlurEffect_ClassID, @@ -162,9 +161,10 @@ public: kTessellate_GrFillBoundingBoxShader_ClassID, kTessellate_GrFillCubicHullShader_ClassID, kTessellate_GrFillTriangleShader_ClassID, - kTessellate_GrStencilCubicShader_ClassID, + kTessellate_GrMiddleOutCubicShader_ClassID, kTessellate_GrStencilTriangleShader_ClassID, - kTessellate_GrStencilWedgeShader_ClassID, + kTessellate_GrTessellateCubicShader_ClassID, + kTessellate_GrTessellateWedgeShader_ClassID, kTestFP_ClassID, kTestRectOp_ClassID, kFlatNormalsFP_ClassID, diff --git a/chromium/third_party/skia/src/gpu/GrProcessorSet.cpp b/chromium/third_party/skia/src/gpu/GrProcessorSet.cpp index fe64cb9233d..b8a0aef92cc 100644 --- a/chromium/third_party/skia/src/gpu/GrProcessorSet.cpp +++ b/chromium/third_party/skia/src/gpu/GrProcessorSet.cpp @@ -69,8 +69,9 @@ GrProcessorSet::GrProcessorSet(GrProcessorSet&& that) fFragmentProcessors[i] = std::move(that.fFragmentProcessors[i + that.fFragmentProcessorOffset]); } - that.fColorFragmentProcessorCnt = 0; that.fFragmentProcessors.reset(0); + that.fColorFragmentProcessorCnt = 0; + that.fFragmentProcessorOffset = 0; } GrProcessorSet::~GrProcessorSet() { diff --git a/chromium/third_party/skia/src/gpu/GrProgramInfo.h b/chromium/third_party/skia/src/gpu/GrProgramInfo.h index 373b3bbafdb..f8ce3fc7011 100644 --- a/chromium/third_party/skia/src/gpu/GrProgramInfo.h +++ b/chromium/third_party/skia/src/gpu/GrProgramInfo.h @@ -49,6 +49,7 @@ public: int numSamples() const { return fNumSamples; } int numStencilSamples() const { return fNumStencilSamples; } + bool isStencilEnabled() const { return fPipeline->isStencilEnabled(); } int numRasterSamples() const { return fPipeline->isStencilEnabled() ? fNumStencilSamples : fNumSamples; diff --git a/chromium/third_party/skia/src/gpu/GrProxyProvider.cpp b/chromium/third_party/skia/src/gpu/GrProxyProvider.cpp index cf20dd1d715..e2bfd767ff0 100644 --- a/chromium/third_party/skia/src/gpu/GrProxyProvider.cpp +++ b/chromium/third_party/skia/src/gpu/GrProxyProvider.cpp @@ -33,8 +33,7 @@ #include "src/gpu/SkGr.h" #include "src/image/SkImage_Base.h" -#define ASSERT_SINGLE_OWNER \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fImageContext->priv().singleOwner());) +#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fImageContext->priv().singleOwner()) GrProxyProvider::GrProxyProvider(GrImageContext* imageContext) : fImageContext(imageContext) {} @@ -54,6 +53,9 @@ bool GrProxyProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTexturePr return false; } + // Only the proxyProvider that created a proxy should be assigning unique keys to it. + SkASSERT(this->isDDLProvider() == proxy->creatingProvider()); + #ifdef SK_DEBUG { GrContext* direct = fImageContext->priv().asDirectContext(); @@ -189,9 +191,11 @@ sk_sp<GrTextureProxy> GrProxyProvider::createWrapped(sk_sp<GrTexture> tex, #endif if (tex->asRenderTarget()) { - return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), useAllocator)); + return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), useAllocator, + this->isDDLProvider())); } else { - return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), useAllocator)); + return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), useAllocator, + this->isDDLProvider())); } } @@ -424,19 +428,18 @@ sk_sp<GrTextureProxy> GrProxyProvider::createProxy(const GrBackendFormat& format ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated; if (renderable == GrRenderable::kYes) { - renderTargetSampleCnt = - caps->getRenderTargetSampleCount(renderTargetSampleCnt, format); + renderTargetSampleCnt = caps->getRenderTargetSampleCount(renderTargetSampleCnt, format); SkASSERT(renderTargetSampleCnt); // We know anything we instantiate later from this deferred path will be // both texturable and renderable return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy( *caps, format, dimensions, renderTargetSampleCnt, mipMapped, mipMapsStatus, fit, - budgeted, isProtected, surfaceFlags, useAllocator)); + budgeted, isProtected, surfaceFlags, useAllocator, this->isDDLProvider())); } return sk_sp<GrTextureProxy>(new GrTextureProxy(format, dimensions, mipMapped, mipMapsStatus, fit, budgeted, isProtected, surfaceFlags, - useAllocator)); + useAllocator, this->isDDLProvider())); } sk_sp<GrTextureProxy> GrProxyProvider::createCompressedTextureProxy( @@ -487,9 +490,9 @@ sk_sp<GrTextureProxy> GrProxyProvider::wrapBackendTexture(const GrBackendTexture GrWrapOwnership ownership, GrWrapCacheable cacheable, GrIOType ioType, - ReleaseProc releaseProc, - ReleaseContext releaseCtx) { + sk_sp<GrRefCntedCallback> releaseHelper) { SkASSERT(ioType != kWrite_GrIOType); + if (this->isAbandoned()) { return nullptr; } @@ -508,22 +511,23 @@ sk_sp<GrTextureProxy> GrProxyProvider::wrapBackendTexture(const GrBackendTexture return nullptr; } - if (releaseProc) { - tex->setRelease(releaseProc, releaseCtx); + if (releaseHelper) { + tex->setRelease(std::move(releaseHelper)); } SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture // Make sure we match how we created the proxy with SkBudgeted::kNo SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType()); - return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), UseAllocator::kNo)); + return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), UseAllocator::kNo, + this->isDDLProvider())); } -sk_sp<GrTextureProxy> GrProxyProvider::wrapCompressedBackendTexture(const GrBackendTexture& beTex, - GrWrapOwnership ownership, - GrWrapCacheable cacheable, - ReleaseProc releaseProc, - ReleaseContext releaseCtx) { +sk_sp<GrTextureProxy> GrProxyProvider::wrapCompressedBackendTexture( + const GrBackendTexture& beTex, + GrWrapOwnership ownership, + GrWrapCacheable cacheable, + sk_sp<GrRefCntedCallback> releaseHelper) { if (this->isAbandoned()) { return nullptr; } @@ -542,15 +546,16 @@ sk_sp<GrTextureProxy> GrProxyProvider::wrapCompressedBackendTexture(const GrBack return nullptr; } - if (releaseProc) { - tex->setRelease(releaseProc, releaseCtx); + if (releaseHelper) { + tex->setRelease(std::move(releaseHelper)); } SkASSERT(!tex->asRenderTarget()); // Strictly a GrTexture // Make sure we match how we created the proxy with SkBudgeted::kNo SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType()); - return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), UseAllocator::kNo)); + return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(tex), UseAllocator::kNo, + this->isDDLProvider())); } sk_sp<GrTextureProxy> GrProxyProvider::wrapRenderableBackendTexture( @@ -558,8 +563,7 @@ sk_sp<GrTextureProxy> GrProxyProvider::wrapRenderableBackendTexture( int sampleCnt, GrWrapOwnership ownership, GrWrapCacheable cacheable, - ReleaseProc releaseProc, - ReleaseContext releaseCtx) { + sk_sp<GrRefCntedCallback> releaseHelper) { if (this->isAbandoned()) { return nullptr; } @@ -583,21 +587,21 @@ sk_sp<GrTextureProxy> GrProxyProvider::wrapRenderableBackendTexture( return nullptr; } - if (releaseProc) { - tex->setRelease(releaseProc, releaseCtx); + if (releaseHelper) { + tex->setRelease(std::move(releaseHelper)); } SkASSERT(tex->asRenderTarget()); // A GrTextureRenderTarget // Make sure we match how we created the proxy with SkBudgeted::kNo SkASSERT(GrBudgetedType::kBudgeted != tex->resourcePriv().budgetedType()); - return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), UseAllocator::kNo)); + return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy(std::move(tex), UseAllocator::kNo, + this->isDDLProvider())); } sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendRenderTarget( const GrBackendRenderTarget& backendRT, - ReleaseProc releaseProc, - ReleaseContext releaseCtx) { + sk_sp<GrRefCntedCallback> releaseHelper) { if (this->isAbandoned()) { return nullptr; } @@ -615,8 +619,8 @@ sk_sp<GrSurfaceProxy> GrProxyProvider::wrapBackendRenderTarget( return nullptr; } - if (releaseProc) { - rt->setRelease(releaseProc, releaseCtx); + if (releaseHelper) { + rt->setRelease(std::move(releaseHelper)); } SkASSERT(!rt->asTexture()); // A GrRenderTarget that's not textureable @@ -730,7 +734,8 @@ sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& budgeted, isProtected, surfaceFlags, - useAllocator)); + useAllocator, + this->isDDLProvider())); } else { return sk_sp<GrTextureProxy>(new GrTextureProxy(std::move(callback), format, @@ -741,7 +746,8 @@ sk_sp<GrTextureProxy> GrProxyProvider::createLazyProxy(LazyInstantiateCallback&& budgeted, isProtected, surfaceFlags, - useAllocator)); + useAllocator, + this->isDDLProvider())); } } @@ -777,7 +783,7 @@ sk_sp<GrRenderTargetProxy> GrProxyProvider::createLazyRenderTargetProxy( return sk_sp<GrRenderTargetProxy>(new GrTextureRenderTargetProxy( *this->caps(), std::move(callback), format, dimensions, sampleCnt, textureInfo->fMipMapped, mipMapsStatus, fit, budgeted, isProtected, surfaceFlags, - useAllocator)); + useAllocator, this->isDDLProvider())); } GrRenderTargetProxy::WrapsVkSecondaryCB vkSCB = @@ -803,17 +809,20 @@ sk_sp<GrTextureProxy> GrProxyProvider::MakeFullyLazyProxy(LazyInstantiateCallbac SkASSERT(renderTargetSampleCnt == 1 || renderable == GrRenderable::kYes); GrInternalSurfaceFlags surfaceFlags = GrInternalSurfaceFlags::kNone; + // MakeFullyLazyProxy is only called at flush time so we know these texture proxies are + // not being created by a DDL provider. static constexpr SkISize kLazyDims = {-1, -1}; if (GrRenderable::kYes == renderable) { return sk_sp<GrTextureProxy>(new GrTextureRenderTargetProxy( caps, std::move(callback), format, kLazyDims, renderTargetSampleCnt, GrMipMapped::kNo, GrMipMapsStatus::kNotAllocated, SkBackingFit::kApprox, - SkBudgeted::kYes, isProtected, surfaceFlags, useAllocator)); + SkBudgeted::kYes, isProtected, surfaceFlags, useAllocator, GrDDLProvider::kNo)); } else { return sk_sp<GrTextureProxy>( new GrTextureProxy(std::move(callback), format, kLazyDims, GrMipMapped::kNo, GrMipMapsStatus::kNotAllocated, SkBackingFit::kApprox, - SkBudgeted::kYes, isProtected, surfaceFlags, useAllocator)); + SkBudgeted::kYes, isProtected, surfaceFlags, useAllocator, + GrDDLProvider::kNo)); } } @@ -858,6 +867,10 @@ void GrProxyProvider::processInvalidUniqueKeyImpl(const GrUniqueKey& key, GrText } } +GrDDLProvider GrProxyProvider::isDDLProvider() const { + return fImageContext->priv().asDirectContext() ? GrDDLProvider::kNo : GrDDLProvider::kYes; +} + uint32_t GrProxyProvider::contextID() const { return fImageContext->priv().contextID(); } diff --git a/chromium/third_party/skia/src/gpu/GrProxyProvider.h b/chromium/third_party/skia/src/gpu/GrProxyProvider.h index a275f297940..e1f681f04b6 100644 --- a/chromium/third_party/skia/src/gpu/GrProxyProvider.h +++ b/chromium/third_party/skia/src/gpu/GrProxyProvider.h @@ -115,12 +115,12 @@ public: GrWrapOwnership, GrWrapCacheable, GrIOType, - ReleaseProc = nullptr, - ReleaseContext = nullptr); + sk_sp<GrRefCntedCallback> = nullptr); - sk_sp<GrTextureProxy> wrapCompressedBackendTexture(const GrBackendTexture&, GrWrapOwnership, - GrWrapCacheable, ReleaseProc = nullptr, - ReleaseContext = nullptr); + sk_sp<GrTextureProxy> wrapCompressedBackendTexture(const GrBackendTexture&, + GrWrapOwnership, + GrWrapCacheable, + sk_sp<GrRefCntedCallback> releaseHelper); /* * Create a texture proxy that wraps a backend texture and is both texture-able and renderable @@ -129,15 +129,13 @@ public: int sampleCnt, GrWrapOwnership, GrWrapCacheable, - ReleaseProc = nullptr, - ReleaseContext = nullptr); + sk_sp<GrRefCntedCallback> releaseHelper); /* * Create a render target proxy that wraps a backend render target */ sk_sp<GrSurfaceProxy> wrapBackendRenderTarget(const GrBackendRenderTarget&, - ReleaseProc = nullptr, - ReleaseContext = nullptr); + sk_sp<GrRefCntedCallback> releaseHelper); /* * Create a render target proxy that wraps a backend texture @@ -223,6 +221,8 @@ public: */ void processInvalidUniqueKey(const GrUniqueKey&, GrTextureProxy*, InvalidateGPUResource); + GrDDLProvider isDDLProvider() const; + // TODO: remove these entry points - it is a bit sloppy to be getting context info from here uint32_t contextID() const; const GrCaps* caps() const; diff --git a/chromium/third_party/skia/src/gpu/GrRecordingContext.cpp b/chromium/third_party/skia/src/gpu/GrRecordingContext.cpp index 2c7c64d5730..9173931e4f1 100644 --- a/chromium/third_party/skia/src/gpu/GrRecordingContext.cpp +++ b/chromium/third_party/skia/src/gpu/GrRecordingContext.cpp @@ -8,6 +8,7 @@ #include "include/private/GrRecordingContext.h" #include "include/gpu/GrContext.h" +#include "include/gpu/GrContextThreadSafeProxy.h" #include "src/core/SkArenaAlloc.h" #include "src/gpu/GrAuditTrail.h" #include "src/gpu/GrCaps.h" @@ -22,9 +23,6 @@ #include "src/gpu/effects/GrSkSLFP.h" #include "src/gpu/text/GrTextBlobCache.h" -#define ASSERT_SINGLE_OWNER_PRIV \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());) - GrRecordingContext::ProgramData::ProgramData(std::unique_ptr<const GrProgramDesc> desc, const GrProgramInfo* info) : fDesc(std::move(desc)) @@ -36,44 +34,34 @@ GrRecordingContext::ProgramData::ProgramData(ProgramData&& other) , fInfo(other.fInfo) { } -GrRecordingContext::ProgramData::~ProgramData() {} +GrRecordingContext::ProgramData::~ProgramData() = default; -GrRecordingContext::GrRecordingContext(GrBackendApi backend, - const GrContextOptions& options, - uint32_t contextID) - : INHERITED(backend, options, contextID) +GrRecordingContext::GrRecordingContext(sk_sp<GrContextThreadSafeProxy> proxy) + : INHERITED(std::move(proxy)) , fAuditTrail(new GrAuditTrail()) { } -GrRecordingContext::~GrRecordingContext() { } +GrRecordingContext::~GrRecordingContext() = default; -/** - * TODO: move textblob draw calls below context (see comment below) - */ -static void textblobcache_overbudget_CB(void* data) { - SkASSERT(data); - GrRecordingContext* context = reinterpret_cast<GrRecordingContext*>(data); +bool GrRecordingContext::init() { - GrContext* direct = context->priv().asDirectContext(); - if (!direct) { - return; + if (!INHERITED::init()) { + return false; } - // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on - // GrRenderTargetContext to perform a necessary flush. The solution is to move drawText calls - // to below the GrContext level, but this is not trivial because they call drawPath on - // SkGpuDevice. - direct->flush(); -} - -bool GrRecordingContext::init(sk_sp<const GrCaps> caps) { + auto overBudget = [this]() { + if (GrContext* direct = this->priv().asDirectContext(); direct != nullptr) { - if (!INHERITED::init(std::move(caps))) { - return false; - } + // TODO: move text blob draw calls below context + // TextBlobs are drawn at the SkGpuDevice level, therefore they cannot rely on + // GrRenderTargetContext to perform a necessary flush. The solution is to move drawText + // calls to below the GrContext level, but this is not trivial because they call + // drawPath on SkGpuDevice. + direct->flushAndSubmit(); + } + }; - fTextBlobCache.reset(new GrTextBlobCache(textblobcache_overbudget_CB, this, - this->contextID())); + fTextBlobCache.reset(new GrTextBlobCache(overBudget, this->contextID())); return true; } @@ -99,19 +87,8 @@ void GrRecordingContext::setupDrawingManager(bool sortOpsTasks, bool reduceOpsTa prcOptions.fGpuPathRenderers &= ~GpuPathRenderers::kSmall; } - GrTextContext::Options textContextOptions; - textContextOptions.fMaxDistanceFieldFontSize = this->options().fGlyphsAsPathsFontSize; - textContextOptions.fMinDistanceFieldFontSize = this->options().fMinDistanceFieldFontSize; - textContextOptions.fDistanceFieldVerticesAlwaysHaveW = false; -#if SK_SUPPORT_ATLAS_TEXT - if (GrContextOptions::Enable::kYes == this->options().fDistanceFieldGlyphVerticesAlwaysHaveW) { - textContextOptions.fDistanceFieldVerticesAlwaysHaveW = true; - } -#endif - fDrawingManager.reset(new GrDrawingManager(this, prcOptions, - textContextOptions, sortOpsTasks, reduceOpsTaskSplitting)); } diff --git a/chromium/third_party/skia/src/gpu/GrRecordingContextPriv.h b/chromium/third_party/skia/src/gpu/GrRecordingContextPriv.h index 4337d3f3c4b..4e3e9a7a3da 100644 --- a/chromium/third_party/skia/src/gpu/GrRecordingContextPriv.h +++ b/chromium/third_party/skia/src/gpu/GrRecordingContextPriv.h @@ -9,6 +9,7 @@ #define GrRecordingContextPriv_DEFINED #include "include/private/GrRecordingContext.h" +#include "src/gpu/text/GrSDFTOptions.h" /** Class that exposes methods to GrRecordingContext that are only intended for use internal to Skia. This class is purely a privileged window into GrRecordingContext. It should never have @@ -102,6 +103,10 @@ public: return &fContext->fStats; } + GrSDFTOptions SDFTOptions() const { + return {this->options().fMinDistanceFieldFontSize, this->options().fGlyphsAsPathsFontSize}; + } + private: explicit GrRecordingContextPriv(GrRecordingContext* context) : fContext(context) {} GrRecordingContextPriv(const GrRecordingContextPriv&); // unimpl diff --git a/chromium/third_party/skia/src/gpu/GrRectanizer.h b/chromium/third_party/skia/src/gpu/GrRectanizer.h new file mode 100644 index 00000000000..0b1fff53348 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/GrRectanizer.h @@ -0,0 +1,44 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrRectanizer_DEFINED +#define GrRectanizer_DEFINED + +#include "include/gpu/GrTypes.h" + +struct SkIPoint16; + +class GrRectanizer { +public: + GrRectanizer(int width, int height) : fWidth(width), fHeight(height) { + SkASSERT(width >= 0); + SkASSERT(height >= 0); + } + + virtual ~GrRectanizer() {} + + virtual void reset() = 0; + + int width() const { return fWidth; } + int height() const { return fHeight; } + + // Attempt to add a rect. Return true on success; false on failure. If + // successful the position in the atlas is returned in 'loc'. + virtual bool addRect(int width, int height, SkIPoint16* loc) = 0; + virtual float percentFull() const = 0; + + /** + * Our factory, which returns the subclass du jour + */ + static GrRectanizer* Factory(int width, int height); + +private: + const int fWidth; + const int fHeight; +}; + +#endif diff --git a/chromium/third_party/skia/src/gpu/GrRectanizerPow2.cpp b/chromium/third_party/skia/src/gpu/GrRectanizerPow2.cpp new file mode 100644 index 00000000000..9a35bf298d2 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/GrRectanizerPow2.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2010 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/gpu/GrRectanizerPow2.h" + +bool GrRectanizerPow2::addRect(int width, int height, SkIPoint16* loc) { + if ((unsigned)width > (unsigned)this->width() || + (unsigned)height > (unsigned)this->height()) { + return false; + } + + int32_t area = width * height; // computed here since height will be modified + + height = GrNextPow2(height); + if (height < kMIN_HEIGHT_POW2) { + height = kMIN_HEIGHT_POW2; + } + + Row* row = &fRows[HeightToRowIndex(height)]; + SkASSERT(row->fRowHeight == 0 || row->fRowHeight == height); + + if (0 == row->fRowHeight) { + if (!this->canAddStrip(height)) { + return false; + } + this->initRow(row, height); + } else { + if (!row->canAddWidth(width, this->width())) { + if (!this->canAddStrip(height)) { + return false; + } + // that row is now "full", so retarget our Row record for + // another one + this->initRow(row, height); + } + } + + SkASSERT(row->fRowHeight == height); + SkASSERT(row->canAddWidth(width, this->width())); + *loc = row->fLoc; + row->fLoc.fX += width; + + SkASSERT(row->fLoc.fX <= this->width()); + SkASSERT(row->fLoc.fY <= this->height()); + SkASSERT(fNextStripY <= this->height()); + fAreaSoFar += area; + return true; +} + +/////////////////////////////////////////////////////////////////////////////// + +// factory is now in GrRectanizer_skyline.cpp +//GrRectanizer* GrRectanizer::Factory(int width, int height) { +// return new GrRectanizerPow2 (width, height); +//} diff --git a/chromium/third_party/skia/src/gpu/GrRectanizerPow2.h b/chromium/third_party/skia/src/gpu/GrRectanizerPow2.h new file mode 100644 index 00000000000..c96c9725b16 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/GrRectanizerPow2.h @@ -0,0 +1,83 @@ +/* +* Copyright 2014 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#ifndef GrRectanizerPow2_DEFINED +#define GrRectanizerPow2_DEFINED + +#include "include/private/SkMalloc.h" +#include "src/core/SkIPoint16.h" +#include "src/core/SkMathPriv.h" +#include "src/gpu/GrRectanizer.h" + +// This Rectanizer quantizes the incoming rects to powers of 2. Each power +// of two can have, at most, one active row/shelf. Once a row/shelf for +// a particular power of two gets full its fRows entry is recycled to point +// to a new row. +// The skyline algorithm almost always provides a better packing. +// +// Mark this class final in an effort to avoid the vtable when this subclass is used explicitly. +class GrRectanizerPow2 final : public GrRectanizer { +public: + GrRectanizerPow2(int w, int h) : INHERITED(w, h) { + this->reset(); + } + + ~GrRectanizerPow2() final {} + + void reset() final { + fNextStripY = 0; + fAreaSoFar = 0; + sk_bzero(fRows, sizeof(fRows)); + } + + bool addRect(int w, int h, SkIPoint16* loc) final; + + float percentFull() const final { + return fAreaSoFar / ((float)this->width() * this->height()); + } + +private: + static const int kMIN_HEIGHT_POW2 = 2; + static const int kMaxExponent = 16; + + struct Row { + SkIPoint16 fLoc; + // fRowHeight is actually known by this struct's position in fRows + // but it is used to signal if there exists an open row of this height + int fRowHeight; + + bool canAddWidth(int width, int containerWidth) const { + return fLoc.fX + width <= containerWidth; + } + }; + + Row fRows[kMaxExponent]; // 0-th entry will be unused + + int fNextStripY; + int32_t fAreaSoFar; + + static int HeightToRowIndex(int height) { + SkASSERT(height >= kMIN_HEIGHT_POW2); + int index = 32 - SkCLZ(height - 1); + SkASSERT(index < kMaxExponent); + return index; + } + + bool canAddStrip(int height) const { + return fNextStripY + height <= this->height(); + } + + void initRow(Row* row, int rowHeight) { + row->fLoc.set(0, fNextStripY); + row->fRowHeight = rowHeight; + fNextStripY += rowHeight; + } + + typedef GrRectanizer INHERITED; +}; + +#endif diff --git a/chromium/third_party/skia/src/gpu/GrRectanizerSkyline.cpp b/chromium/third_party/skia/src/gpu/GrRectanizerSkyline.cpp index 42aff7a657f..f36b733d1dc 100644 --- a/chromium/third_party/skia/src/gpu/GrRectanizerSkyline.cpp +++ b/chromium/third_party/skia/src/gpu/GrRectanizerSkyline.cpp @@ -116,3 +116,8 @@ void GrRectanizerSkyline::addSkylineLevel(int skylineIndex, int x, int y, int wi } } +/////////////////////////////////////////////////////////////////////////////// + +GrRectanizer* GrRectanizer::Factory(int width, int height) { + return new GrRectanizerSkyline(width, height); +} diff --git a/chromium/third_party/skia/src/gpu/GrRectanizerSkyline.h b/chromium/third_party/skia/src/gpu/GrRectanizerSkyline.h index 36af34db618..40e5c1cc163 100644 --- a/chromium/third_party/skia/src/gpu/GrRectanizerSkyline.h +++ b/chromium/third_party/skia/src/gpu/GrRectanizerSkyline.h @@ -9,17 +9,21 @@ #define GrRectanizerSkyline_DEFINED #include "include/private/SkTDArray.h" -#include "src/core/SkIPoint16.h" +#include "src/gpu/GrRectanizer.h" // Pack rectangles and track the current silhouette // Based, in part, on Jukka Jylanki's work at http://clb.demon.fi -class GrRectanizerSkyline { +// +// Mark this class final in an effort to avoid the vtable when this subclass is used explicitly. +class GrRectanizerSkyline final : public GrRectanizer { public: - GrRectanizerSkyline(int w, int h) : fWidth{w}, fHeight{h} { + GrRectanizerSkyline(int w, int h) : INHERITED(w, h) { this->reset(); } - void reset() { + ~GrRectanizerSkyline() final { } + + void reset() final { fAreaSoFar = 0; fSkyline.reset(); SkylineSegment* seg = fSkyline.append(1); @@ -28,10 +32,11 @@ public: seg->fWidth = this->width(); } - bool addRect(int w, int h, SkIPoint16* loc); + bool addRect(int w, int h, SkIPoint16* loc) final; - int width() const { return fWidth; } - int height() const { return fHeight; } + float percentFull() const final { + return fAreaSoFar / ((float)this->width() * this->height()); + } private: struct SkylineSegment { @@ -40,6 +45,10 @@ private: int fWidth; }; + SkTDArray<SkylineSegment> fSkyline; + + int32_t fAreaSoFar; + // Can a width x height rectangle fit in the free space represented by // the skyline segments >= 'skylineIndex'? If so, return true and fill in // 'y' with the y-location at which it fits (the x location is pulled from @@ -49,10 +58,7 @@ private: // at x,y. void addSkylineLevel(int skylineIndex, int x, int y, int width, int height); - const int fWidth; - const int fHeight; - SkTDArray<SkylineSegment> fSkyline; - int32_t fAreaSoFar; + typedef GrRectanizer INHERITED; }; -#endif // GrRectanizerSkyline_DEFINED +#endif diff --git a/chromium/third_party/skia/src/gpu/GrReducedClip.cpp b/chromium/third_party/skia/src/gpu/GrReducedClip.cpp index 469b7f94e48..533132edc7c 100644 --- a/chromium/third_party/skia/src/gpu/GrReducedClip.cpp +++ b/chromium/third_party/skia/src/gpu/GrReducedClip.cpp @@ -25,7 +25,9 @@ #include "src/gpu/effects/GrConvexPolyEffect.h" #include "src/gpu/effects/GrRRectEffect.h" #include "src/gpu/effects/generated/GrAARectEffect.h" +#include "src/gpu/effects/generated/GrDeviceSpaceEffect.h" #include "src/gpu/geometry/GrStyledShape.h" +#include "src/shaders/SkShaderBase.h" /** * There are plenty of optimizations that could be added here. Maybe flips could be folded into @@ -115,6 +117,13 @@ GrReducedClip::GrReducedClip(const SkClipStack& stack, const SkRect& queryBounds // Now that we have determined the bounds to use and filtered out the trivial cases, call // the helper that actually walks the stack. this->walkStack(stack, tighterQuery); + + if (fInitialState == InitialState::kAllOut && fMaskElements.isEmpty()) { + // The clip starts with no coverage and there are no elements to add coverage with + // expanding ops. We ignore the AAClipRectGenID since it is an implied intersection. + this->makeEmpty(); + return; + } } if (SK_InvalidGenID != fAAClipRectGenID && // Is there an AA clip rect? @@ -173,6 +182,18 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound break; } + if (element->getDeviceSpaceType() == Element::DeviceSpaceType::kShader) { + if (fShader) { + // Combine multiple shaders together with src-in blending. This works because all + // shaders are effectively intersections (difference ops have been modified to be + // 1 - alpha already). + fShader = SkShaders::Blend(SkBlendMode::kSrcIn, element->refShader(), fShader); + } else { + fShader = element->refShader(); + } + continue; + } + bool skippable = false; bool isFlip = false; // does this op just flip the in/out state of every point in the bounds @@ -480,6 +501,8 @@ void GrReducedClip::walkStack(const SkClipStack& stack, const SkRect& queryBound } GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const Element* element) { + SkASSERT(element->getDeviceSpaceType() != Element::DeviceSpaceType::kShader); + SkIRect elementIBounds; if (!element->isAA()) { element->getBounds().round(&elementIBounds); @@ -523,12 +546,17 @@ GrReducedClip::ClipResult GrReducedClip::clipInsideElement(const Element* elemen case Element::DeviceSpaceType::kPath: return this->addAnalyticFP(element->getDeviceSpacePath(), Invert(element->isInverseFilled()), GrAA(element->isAA())); + + case Element::DeviceSpaceType::kShader: + SkUNREACHABLE; } SK_ABORT("Unexpected DeviceSpaceType"); } GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const Element* element) { + SkASSERT(element->getDeviceSpaceType() != Element::DeviceSpaceType::kShader); + switch (element->getDeviceSpaceType()) { case Element::DeviceSpaceType::kEmpty: return ClipResult::kMadeEmpty; @@ -589,6 +617,9 @@ GrReducedClip::ClipResult GrReducedClip::clipOutsideElement(const Element* eleme case Element::DeviceSpaceType::kPath: return this->addAnalyticFP(element->getDeviceSpacePath(), Invert(!element->isInverseFilled()), GrAA(element->isAA())); + + case Element::DeviceSpaceType::kShader: + SkUNREACHABLE; } SK_ABORT("Unexpected DeviceSpaceType"); @@ -620,9 +651,10 @@ GrReducedClip::ClipResult GrReducedClip::addAnalyticFP(const SkRect& deviceSpace return ClipResult::kNotClipped; } - fAnalyticFPs.push_back(GrAARectEffect::Make(GetClipEdgeType(invert, aa), deviceSpaceRect)); - SkASSERT(fAnalyticFPs.back()); + fAnalyticFP = GrAARectEffect::Make(std::move(fAnalyticFP), GetClipEdgeType(invert, aa), + deviceSpaceRect); + SkASSERT(fAnalyticFP != nullptr); return ClipResult::kClipped; } @@ -632,9 +664,12 @@ GrReducedClip::ClipResult GrReducedClip::addAnalyticFP(const SkRRect& deviceSpac return ClipResult::kNotClipped; } - if (auto fp = GrRRectEffect::Make(GetClipEdgeType(invert, aa), deviceSpaceRRect, - *fCaps->shaderCaps())) { - fAnalyticFPs.push_back(std::move(fp)); + // Combine this analytic effect with the previous effect in the stack. + bool success; + std::tie(success, fAnalyticFP) = GrRRectEffect::Make(std::move(fAnalyticFP), + GetClipEdgeType(invert, aa), + deviceSpaceRRect, *fCaps->shaderCaps()); + if (success) { return ClipResult::kClipped; } @@ -650,8 +685,12 @@ GrReducedClip::ClipResult GrReducedClip::addAnalyticFP(const SkPath& deviceSpace return ClipResult::kNotClipped; } - if (auto fp = GrConvexPolyEffect::Make(GetClipEdgeType(invert, aa), deviceSpacePath)) { - fAnalyticFPs.push_back(std::move(fp)); + // Combine this analytic effect with the previous effect in the stack. + bool success; + std::tie(success, fAnalyticFP) = GrConvexPolyEffect::Make(std::move(fAnalyticFP), + GetClipEdgeType(invert, aa), + deviceSpacePath); + if (success) { return ClipResult::kClipped; } @@ -673,6 +712,7 @@ void GrReducedClip::makeEmpty() { fAAClipRectGenID = SK_InvalidGenID; fWindowRects.reset(); fMaskElements.reset(); + fShader.reset(); fInitialState = InitialState::kAllOut; } @@ -693,7 +733,7 @@ static bool stencil_element(GrRenderTargetContext* rtc, GrPaint paint; paint.setCoverageSetOpXPFactory((SkRegion::Op)element->getOp(), element->isInverseFilled()); - rtc->priv().stencilRect(clip, ss, std::move(paint), aa, viewMatrix, + rtc->priv().stencilRect(&clip, ss, std::move(paint), aa, viewMatrix, element->getDeviceSpaceRect()); return true; } @@ -704,7 +744,7 @@ static bool stencil_element(GrRenderTargetContext* rtc, path.toggleInverseFillType(); } - return rtc->priv().drawAndStencilPath(clip, ss, (SkRegion::Op)element->getOp(), + return rtc->priv().drawAndStencilPath(&clip, ss, (SkRegion::Op)element->getOp(), element->isInverseFilled(), aa, viewMatrix, path); } } @@ -724,7 +764,7 @@ static void draw_element(GrRenderTargetContext* rtc, SkDEBUGFAIL("Should never get here with an empty element."); break; case SkClipStack::Element::DeviceSpaceType::kRect: - rtc->drawRect(clip, std::move(paint), aa, viewMatrix, element->getDeviceSpaceRect()); + rtc->drawRect(&clip, std::move(paint), aa, viewMatrix, element->getDeviceSpaceRect()); break; default: { SkPath path; @@ -733,7 +773,7 @@ static void draw_element(GrRenderTargetContext* rtc, path.toggleInverseFillType(); } - rtc->drawPath(clip, std::move(paint), aa, viewMatrix, path, GrStyle::SimpleFill()); + rtc->drawPath(&clip, std::move(paint), aa, viewMatrix, path, GrStyle::SimpleFill()); break; } } @@ -742,7 +782,7 @@ static void draw_element(GrRenderTargetContext* rtc, bool GrReducedClip::drawAlphaClipMask(GrRenderTargetContext* rtc) const { // The texture may be larger than necessary, this rect represents the part of the texture // we populate with a rasterization of the clip. - GrFixedClip clip(SkIRect::MakeWH(fScissor.width(), fScissor.height())); + GrFixedClip clip(rtc->dimensions(), SkIRect::MakeWH(fScissor.width(), fScissor.height())); if (!fWindowRects.empty()) { clip.setWindowRectangles(fWindowRects.makeOffset(-fScissor.left(), -fScissor.top()), @@ -753,7 +793,15 @@ bool GrReducedClip::drawAlphaClipMask(GrRenderTargetContext* rtc) const { // clear the part that we care about. SkPMColor4f initialCoverage = InitialState::kAllIn == this->initialState() ? SK_PMColor4fWHITE : SK_PMColor4fTRANSPARENT; - rtc->priv().clear(clip, initialCoverage, GrRenderTargetContext::CanClearFullscreen::kYes); + if (clip.hasWindowRectangles()) { + GrPaint paint; + paint.setColor4f(initialCoverage); + paint.setPorterDuffXPFactory(SkBlendMode::kSrc); + rtc->drawRect(&clip, std::move(paint), GrAA::kNo, SkMatrix::I(), + SkRect::Make(clip.scissorRect())); + } else { + rtc->priv().clearAtLeast(clip.scissorRect(), initialCoverage); + } // Set the matrix so that rendered clip elements are transformed to mask space from clip space. SkMatrix translate; @@ -794,7 +842,7 @@ bool GrReducedClip::drawAlphaClipMask(GrRenderTargetContext* rtc) const { GrPaint paint; paint.setCoverageSetOpXPFactory(op, !invert); - rtc->priv().stencilRect(clip, &kDrawOutsideElement, std::move(paint), GrAA::kNo, + rtc->priv().stencilRect(&clip, &kDrawOutsideElement, std::move(paint), GrAA::kNo, translate, SkRect::Make(fScissor)); } else { // all the remaining ops can just be directly draw into the accumulation buffer @@ -842,21 +890,59 @@ bool GrReducedClip::drawStencilClipMask(GrRecordingContext* context, return true; } +static int count_fp_recursive(GrFragmentProcessor* fp) { + int count = 0; + if (fp != nullptr) { + count += 1; // count self + for (int index=0; index < fp->numChildProcessors(); ++index) { + count += count_fp_recursive(&fp->childProcessor(index)); // count children + } + } + return count; +} + +int GrReducedClip::numAnalyticFPs() const { + return fCCPRClipPaths.size() + count_fp_recursive(fAnalyticFP.get()); +} + std::unique_ptr<GrFragmentProcessor> GrReducedClip::finishAndDetachAnalyticFPs( + GrRecordingContext* context, const SkMatrixProvider& matrixProvider, GrCoverageCountingPathRenderer* ccpr, uint32_t opsTaskID) { - // Make sure finishAndDetachAnalyticFPs hasn't been called already. - SkDEBUGCODE(for (const auto& fp : fAnalyticFPs) { SkASSERT(fp); }) - - if (!fCCPRClipPaths.empty()) { - fAnalyticFPs.reserve(fAnalyticFPs.count() + fCCPRClipPaths.count()); - for (const SkPath& ccprClipPath : fCCPRClipPaths) { - SkASSERT(ccpr); - SkASSERT(fHasScissor); - auto fp = ccpr->makeClipProcessor(opsTaskID, ccprClipPath, fScissor, *fCaps); - fAnalyticFPs.push_back(std::move(fp)); + // Combine the analytic FP with any CCPR clip processors. + std::unique_ptr<GrFragmentProcessor> clipFP = std::move(fAnalyticFP); + + for (const SkPath& ccprClipPath : fCCPRClipPaths) { + SkASSERT(ccpr); + SkASSERT(fHasScissor); + clipFP = ccpr->makeClipProcessor(std::move(clipFP), opsTaskID, ccprClipPath, + fScissor, *fCaps); + } + fCCPRClipPaths.reset(); + + // Create the shader. + std::unique_ptr<GrFragmentProcessor> shaderFP; + if (fShader != nullptr) { + static const GrColorInfo kCoverageColorInfo{GrColorType::kUnknown, kPremul_SkAlphaType, + nullptr}; + GrFPArgs args(context, matrixProvider, kNone_SkFilterQuality, &kCoverageColorInfo); + shaderFP = as_SB(fShader)->asFragmentProcessor(args); + if (shaderFP != nullptr) { + shaderFP = GrFragmentProcessor::SwizzleOutput(std::move(shaderFP), GrSwizzle::AAAA()); } - fCCPRClipPaths.reset(); } - return GrFragmentProcessor::RunInSeries(fAnalyticFPs.begin(), fAnalyticFPs.count()); + // Combine the clip and shader FPs using RunInSeries. (RunInSeries will automatically return the + // input as-is if we only have one.) + SkSTArray<2, std::unique_ptr<GrFragmentProcessor>> seriesFPs; + if (clipFP != nullptr) { + seriesFPs.push_back(std::move(clipFP)); + } + if (shaderFP != nullptr) { + seriesFPs.push_back(std::move(shaderFP)); + } + + return seriesFPs.empty() + ? nullptr + : GrFragmentProcessor::RunInSeries(&seriesFPs.front(), seriesFPs.size()); } + diff --git a/chromium/third_party/skia/src/gpu/GrReducedClip.h b/chromium/third_party/skia/src/gpu/GrReducedClip.h index ca95bd09949..bcc45a0702e 100644 --- a/chromium/third_party/skia/src/gpu/GrReducedClip.h +++ b/chromium/third_party/skia/src/gpu/GrReducedClip.h @@ -53,6 +53,13 @@ public: bool hasScissor() const { return fHasScissor; } /** + * Indicates if there is a clip shader, representing the merge of all shader elements of the + * original stack. + */ + bool hasShader() const { return SkToBool(fShader); } + sk_sp<SkShader> shader() const { SkASSERT(fShader); return fShader; } + + /** * If nonempty, the clip mask is not valid inside these windows and the caller must clip them * out using the window rectangles GPU extension. */ @@ -85,7 +92,7 @@ public: bool drawAlphaClipMask(GrRenderTargetContext*) const; bool drawStencilClipMask(GrRecordingContext*, GrRenderTargetContext*) const; - int numAnalyticFPs() const { return fAnalyticFPs.count() + fCCPRClipPaths.count(); } + int numAnalyticFPs() const; /** * Called once the client knows the ID of the opsTask that the clip FPs will operate in. This @@ -97,6 +104,7 @@ public: * may cause flushes or otherwise change which opsTask the actual draw is going into. */ std::unique_ptr<GrFragmentProcessor> finishAndDetachAnalyticFPs( + GrRecordingContext*, const SkMatrixProvider& matrixProvider, GrCoverageCountingPathRenderer*, uint32_t opsTaskID); private: @@ -144,8 +152,11 @@ private: ElementList fMaskElements; uint32_t fMaskGenID; bool fMaskRequiresAA; - SkSTArray<4, std::unique_ptr<GrFragmentProcessor>> fAnalyticFPs; + std::unique_ptr<GrFragmentProcessor> fAnalyticFP; SkSTArray<4, SkPath> fCCPRClipPaths; // Will convert to FPs once we have an opsTask ID for CCPR. + // Will be the combination of all kShader elements or null if there's no clip shader. + // Does not count against the analytic FP limit. + sk_sp<SkShader> fShader; }; #endif diff --git a/chromium/third_party/skia/src/gpu/GrRenderTargetContext.cpp b/chromium/third_party/skia/src/gpu/GrRenderTargetContext.cpp index 7a53e76afb4..b4617c8ba3d 100644 --- a/chromium/third_party/skia/src/gpu/GrRenderTargetContext.cpp +++ b/chromium/third_party/skia/src/gpu/GrRenderTargetContext.cpp @@ -20,6 +20,7 @@ #include "src/core/SkGlyphRunPainter.h" #include "src/core/SkLatticeIter.h" #include "src/core/SkMatrixPriv.h" +#include "src/core/SkMatrixProvider.h" #include "src/core/SkRRectPriv.h" #include "src/core/SkSurfacePriv.h" #include "src/core/SkYUVMath.h" @@ -28,11 +29,11 @@ #include "src/gpu/GrBlurUtils.h" #include "src/gpu/GrCaps.h" #include "src/gpu/GrClientMappedBufferManager.h" +#include "src/gpu/GrClip.h" #include "src/gpu/GrColor.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrDataUtils.h" #include "src/gpu/GrDrawingManager.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrGpuResourcePriv.h" #include "src/gpu/GrImageContextPriv.h" #include "src/gpu/GrImageInfo.h" @@ -55,7 +56,6 @@ #include "src/gpu/geometry/GrStyledShape.h" #include "src/gpu/ops/GrAtlasTextOp.h" #include "src/gpu/ops/GrClearOp.h" -#include "src/gpu/ops/GrClearStencilClipOp.h" #include "src/gpu/ops/GrDrawAtlasOp.h" #include "src/gpu/ops/GrDrawOp.h" #include "src/gpu/ops/GrDrawVerticesOp.h" @@ -70,7 +70,8 @@ #include "src/gpu/ops/GrStencilPathOp.h" #include "src/gpu/ops/GrStrokeRectOp.h" #include "src/gpu/ops/GrTextureOp.h" -#include "src/gpu/text/GrTextContext.h" +#include "src/gpu/text/GrSDFTOptions.h" +#include "src/gpu/text/GrTextBlobCache.h" #include "src/gpu/text/GrTextTarget.h" class GrRenderTargetContext::TextTarget : public GrTextTarget { @@ -78,14 +79,13 @@ public: TextTarget(GrRenderTargetContext* renderTargetContext) : GrTextTarget(renderTargetContext->width(), renderTargetContext->height(), renderTargetContext->colorInfo()) - , fRenderTargetContext(renderTargetContext) - , fGlyphPainter{*renderTargetContext} {} + , fRenderTargetContext(renderTargetContext) {} - void addDrawOp(const GrClip& clip, std::unique_ptr<GrAtlasTextOp> op) override { + void addDrawOp(const GrClip* clip, std::unique_ptr<GrAtlasTextOp> op) override { fRenderTargetContext->addDrawOp(clip, std::move(op)); } - void drawShape(const GrClip& clip, + void drawShape(const GrClip* clip, const SkPaint& paint, const SkMatrixProvider& matrixProvider, const GrStyledShape& shape) override { @@ -112,20 +112,16 @@ public: } SkGlyphRunListPainter* glyphPainter() override { - return &fGlyphPainter; + return fRenderTargetContext->glyphPainter(); } private: GrRenderTargetContext* fRenderTargetContext; - SkGlyphRunListPainter fGlyphPainter; - }; #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == this->drawingManager()->getContext()) -#define ASSERT_SINGLE_OWNER \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());) -#define ASSERT_SINGLE_OWNER_PRIV \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fRenderTargetContext->singleOwner());) +#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(this->singleOwner()) +#define ASSERT_SINGLE_OWNER_PRIV GR_ASSERT_SINGLE_OWNER(fRenderTargetContext->singleOwner()) #define RETURN_IF_ABANDONED if (fContext->priv().abandoned()) { return; } #define RETURN_IF_ABANDONED_PRIV if (fRenderTargetContext->fContext->priv().abandoned()) { return; } #define RETURN_FALSE_IF_ABANDONED if (fContext->priv().abandoned()) { return false; } @@ -296,12 +292,11 @@ std::unique_ptr<GrRenderTargetContext> GrRenderTargetContext::MakeFromBackendTex int sampleCnt, GrSurfaceOrigin origin, const SkSurfaceProps* surfaceProps, - ReleaseProc releaseProc, - ReleaseContext releaseCtx) { + sk_sp<GrRefCntedCallback> releaseHelper) { SkASSERT(sampleCnt > 0); sk_sp<GrTextureProxy> proxy(context->priv().proxyProvider()->wrapRenderableBackendTexture( - tex, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, releaseProc, - releaseCtx)); + tex, sampleCnt, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, + std::move(releaseHelper))); if (!proxy) { return nullptr; } @@ -338,8 +333,13 @@ std::unique_ptr<GrRenderTargetContext> GrRenderTargetContext::MakeFromBackendRen const SkSurfaceProps* surfaceProps, ReleaseProc releaseProc, ReleaseContext releaseCtx) { + sk_sp<GrRefCntedCallback> releaseHelper; + if (releaseProc) { + releaseHelper.reset(new GrRefCntedCallback(releaseProc, releaseCtx)); + } + sk_sp<GrSurfaceProxy> proxy( - context->priv().proxyProvider()->wrapBackendRenderTarget(rt, releaseProc, releaseCtx)); + context->priv().proxyProvider()->wrapBackendRenderTarget(rt, std::move(releaseHelper))); if (!proxy) { return nullptr; } @@ -379,9 +379,10 @@ GrRenderTargetContext::GrRenderTargetContext(GrRecordingContext* context, : GrSurfaceContext(context, std::move(readView), colorType, kPremul_SkAlphaType, std::move(colorSpace)) , fWriteView(std::move(writeView)) - , fOpsTask(sk_ref_sp(this->asSurfaceProxy()->getLastOpsTask())) , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps)) - , fManagedOpsTask(managedOpsTask) { + , fManagedOpsTask(managedOpsTask) + , fGlyphPainter(*this) { + fOpsTask = sk_ref_sp(context->priv().drawingManager()->getLastOpsTask(this->asSurfaceProxy())); if (fOpsTask) { fOpsTask->addClosedObserver(this); } @@ -395,7 +396,7 @@ GrRenderTargetContext::GrRenderTargetContext(GrRecordingContext* context, #ifdef SK_DEBUG void GrRenderTargetContext::onValidate() const { if (fOpsTask && !fOpsTask->isClosed()) { - SkASSERT(fWriteView.proxy()->getLastRenderTask() == fOpsTask.get()); + SkASSERT(this->drawingManager()->getLastRenderTask(fWriteView.proxy()) == fOpsTask.get()); } } #endif @@ -448,9 +449,34 @@ GrOpsTask* GrRenderTargetContext::getOpsTask() { return fOpsTask.get(); } -void GrRenderTargetContext::drawGlyphRunList(const GrClip& clip, +static SkColor compute_canonical_color(const SkPaint& paint, bool lcd) { + SkColor canonicalColor = SkPaintPriv::ComputeLuminanceColor(paint); + if (lcd) { + // This is the correct computation for canonicalColor, but there are tons of cases where LCD + // can be modified. For now we just regenerate if any run in a textblob has LCD. + // TODO figure out where all of these modifications are and see if we can incorporate that + // logic at a higher level *OR* use sRGB + //canonicalColor = SkMaskGamma::CanonicalColor(canonicalColor); + + // TODO we want to figure out a way to be able to use the canonical color on LCD text, + // see the note above. We pick a dummy value for LCD text to ensure we always match the + // same key + return SK_ColorTRANSPARENT; + } else { + // A8, though can have mixed BMP text but it shouldn't matter because BMP text won't have + // gamma corrected masks anyways, nor color + U8CPU lum = SkComputeLuminance(SkColorGetR(canonicalColor), + SkColorGetG(canonicalColor), + SkColorGetB(canonicalColor)); + // reduce to our finite number of bits + canonicalColor = SkMaskGamma::CanonicalColor(SkColorSetRGB(lum, lum, lum)); + } + return canonicalColor; +} + +void GrRenderTargetContext::drawGlyphRunList(const GrClip* clip, const SkMatrixProvider& matrixProvider, - const SkGlyphRunList& blob) { + const SkGlyphRunList& glyphRunList) { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) @@ -463,46 +489,83 @@ void GrRenderTargetContext::drawGlyphRunList(const GrClip& clip, return; } - GrTextContext* atlasTextContext = this->drawingManager()->getTextContext(); - atlasTextContext->drawGlyphRunList(fContext, fTextTarget.get(), clip, matrixProvider, - fSurfaceProps, blob); -} + GrSDFTOptions options = fContext->priv().SDFTOptions(); + GrTextBlobCache* textBlobCache = fContext->priv().getTextBlobCache(); -void GrRenderTargetContext::discard() { - ASSERT_SINGLE_OWNER - RETURN_IF_ABANDONED - SkDEBUGCODE(this->validate();) - GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext); + // Get the first paint to use as the key paint. + const SkPaint& blobPaint = glyphRunList.paint(); - AutoCheckFlush acf(this->drawingManager()); + SkPoint drawOrigin = glyphRunList.origin(); - this->getOpsTask()->discard(); + SkMaskFilterBase::BlurRec blurRec; + // It might be worth caching these things, but its not clear at this time + // TODO for animated mask filters, this will fill up our cache. We need a safeguard here + const SkMaskFilter* mf = blobPaint.getMaskFilter(); + bool canCache = glyphRunList.canCache() && + !(blobPaint.getPathEffect() || (mf && !as_MFB(mf)->asABlur(&blurRec))); + + // If we're doing linear blending, then we can disable the gamma hacks. + // Otherwise, leave them on. In either case, we still want the contrast boost: + // TODO: Can we be even smarter about mask gamma based on the dest transfer function? + SkScalerContextFlags scalerContextFlags = this->colorInfo().isLinearlyBlended() + ? SkScalerContextFlags::kBoostContrast + : SkScalerContextFlags::kFakeGammaAndBoostContrast; + + sk_sp<GrTextBlob> blob; + GrTextBlob::Key key; + if (canCache) { + bool hasLCD = glyphRunList.anyRunsLCD(); + + // We canonicalize all non-lcd draws to use kUnknown_SkPixelGeometry + SkPixelGeometry pixelGeometry = + hasLCD ? fSurfaceProps.pixelGeometry() : kUnknown_SkPixelGeometry; + + GrColor canonicalColor = compute_canonical_color(blobPaint, hasLCD); + + key.fPixelGeometry = pixelGeometry; + key.fUniqueID = glyphRunList.uniqueID(); + key.fStyle = blobPaint.getStyle(); + key.fHasBlur = SkToBool(mf); + key.fCanonicalColor = canonicalColor; + key.fScalerContextFlags = scalerContextFlags; + blob = textBlobCache->find(key); + } + + const SkMatrix& drawMatrix(matrixProvider.localToDevice()); + if (blob != nullptr && blob->canReuse(blobPaint, blurRec, drawMatrix, drawOrigin)) { + // Reusing the blob. Move it to the front of LRU cache. + textBlobCache->makeMRU(blob.get()); + } else { + // Build or Rebuild the GrTextBlob + if (blob != nullptr) { + // We have to remake the blob because changes may invalidate our masks. + // TODO we could probably get away with reuse most of the time if the pointer is unique, + // but we'd have to clear the SubRun information + textBlobCache->remove(blob.get()); + } + if (canCache) { + blob = textBlobCache->makeCachedBlob(glyphRunList, key, blurRec, drawMatrix); + } else { + blob = GrTextBlob::Make(glyphRunList, drawMatrix); + } + bool supportsSDFT = fContext->priv().caps()->shaderCaps()->supportsDistanceFieldText(); + fGlyphPainter.processGlyphRunList( + glyphRunList, drawMatrix, fSurfaceProps, supportsSDFT, options, blob.get()); + } + + blob->insertOpsIntoTarget( + fTextTarget.get(), fSurfaceProps, blobPaint, clip, matrixProvider, drawOrigin); } -void GrRenderTargetContext::clear(const SkIRect* rect, - const SkPMColor4f& color, - CanClearFullscreen canClearFullscreen) { +void GrRenderTargetContext::discard() { ASSERT_SINGLE_OWNER RETURN_IF_ABANDONED SkDEBUGCODE(this->validate();) - GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext); + GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "discard", fContext); AutoCheckFlush acf(this->drawingManager()); - this->internalClear(rect ? GrFixedClip(*rect) : GrFixedClip::Disabled(), color, - canClearFullscreen); -} -void GrRenderTargetContextPriv::clear(const GrFixedClip& clip, - const SkPMColor4f& color, - CanClearFullscreen canClearFullscreen) { - ASSERT_SINGLE_OWNER_PRIV - RETURN_IF_ABANDONED_PRIV - SkDEBUGCODE(fRenderTargetContext->validate();) - GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clear", - fRenderTargetContext->fContext); - - AutoCheckFlush acf(fRenderTargetContext->drawingManager()); - fRenderTargetContext->internalClear(clip, color, canClearFullscreen); + this->getOpsTask()->discard(); } static void clear_to_grpaint(const SkPMColor4f& color, GrPaint* paint) { @@ -517,21 +580,46 @@ static void clear_to_grpaint(const SkPMColor4f& color, GrPaint* paint) { } } -void GrRenderTargetContext::internalClear(const GrFixedClip& clip, +// NOTE: We currently pass the premul color unmodified to the gpu, since we assume the GrRTC has a +// premul alpha type. If we ever support different alpha type render targets, this function should +// transform the color as appropriate. +void GrRenderTargetContext::internalClear(const SkIRect* scissor, const SkPMColor4f& color, - CanClearFullscreen canClearFullscreen) { - bool isFull = false; - if (!clip.hasWindowRectangles()) { - // TODO: wrt the shouldInitializeTextures path, it would be more performant to - // only clear the entire target if we knew it had not been cleared before. As - // is this could end up doing a lot of redundant clears. - isFull = !clip.scissorEnabled() || - (CanClearFullscreen::kYes == canClearFullscreen && - (this->caps()->preferFullscreenClears() || this->caps()->shouldInitializeTextures())) || - clip.scissorRect().contains(SkIRect::MakeWH(this->width(), this->height())); - } - - if (isFull) { + bool upgradePartialToFull) { + ASSERT_SINGLE_OWNER + RETURN_IF_ABANDONED + SkDEBUGCODE(this->validate();) + GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "clear", fContext); + + // There are three ways clears are handled: load ops, native clears, and draws. Load ops are + // only for fullscreen clears; native clears can be fullscreen or with scissors if the backend + // supports then. Drawing an axis-aligned rect is the fallback path. + GrScissorState scissorState(this->asSurfaceProxy()->backingStoreDimensions()); + if (scissor && !scissorState.set(*scissor)) { + // The clear is offscreen, so skip it (normally this would be handled by addDrawOp, + // except clear ops are not draw ops). + return; + } + + // If we have a scissor but it's okay to clear beyond it for performance reasons, then disable + // the test. We only do this when the clear would be handled by a load op or natively. + if (scissorState.enabled() && !this->caps()->performColorClearsAsDraws()) { + if (upgradePartialToFull && (this->caps()->preferFullscreenClears() || + this->caps()->shouldInitializeTextures())) { + // TODO: wrt the shouldInitializeTextures path, it would be more performant to + // only clear the entire target if we knew it had not been cleared before. As + // is this could end up doing a lot of redundant clears. + scissorState.setDisabled(); + } else { + // Unlike with stencil clears, we also allow clears up to the logical dimensions of the + // render target to overflow into any approx-fit padding of the backing store dimensions + scissorState.relaxTest(this->dimensions()); + } + } + + if (!scissorState.enabled()) { + // This is a fullscreen clear, so could be handled as a load op. Regardless, we can also + // discard all prior ops in the current task since the color buffer will be overwritten. GrOpsTask* opsTask = this->getOpsTask(); if (opsTask->resetForFullscreenClear(this->canDiscardPreviousOpsOnFullClear()) && !this->caps()->performColorClearsAsDraws()) { @@ -543,43 +631,24 @@ void GrRenderTargetContext::internalClear(const GrFixedClip& clip, // blow away the color buffer contents opsTask->setColorLoadOp(GrLoadOp::kDiscard); } + } - // Must add an op to the list (either because we couldn't use a load op, or because the - // clear load op isn't supported) - if (this->caps()->performColorClearsAsDraws()) { - SkRect rtRect = SkRect::MakeWH(this->width(), this->height()); - GrPaint paint; - clear_to_grpaint(color, &paint); - this->addDrawOp(GrFixedClip::Disabled(), - GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(), - rtRect)); - } else { - this->addOp(GrClearOp::Make( - fContext, SkIRect::MakeEmpty(), color, /* fullscreen */ true)); - } + // At this point we are either a partial clear or a fullscreen clear that couldn't be applied + // as a load op. + bool clearAsDraw = this->caps()->performColorClearsAsDraws() || + (scissorState.enabled() && this->caps()->performPartialClearsAsDraws()); + if (clearAsDraw) { + GrPaint paint; + clear_to_grpaint(color, &paint); + this->addDrawOp(nullptr, + GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(), + SkRect::Make(scissorState.rect()))); } else { - if (this->caps()->performPartialClearsAsDraws()) { - // performPartialClearsAsDraws() also returns true if any clear has to be a draw. - GrPaint paint; - clear_to_grpaint(color, &paint); - - this->addDrawOp(clip, - GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(), - SkRect::Make(clip.scissorRect()))); - } else { - std::unique_ptr<GrOp> op(GrClearOp::Make(fContext, clip, color, - this->asSurfaceProxy())); - // This version of the clear op factory can return null if the clip doesn't intersect - // with the surface proxy's boundary - if (!op) { - return; - } - this->addOp(std::move(op)); - } + this->addOp(GrClearOp::MakeColor(fContext, scissorState, color)); } } -void GrRenderTargetContext::drawPaint(const GrClip& clip, +void GrRenderTargetContext::drawPaint(const GrClip* clip, GrPaint&& paint, const SkMatrix& viewMatrix) { // Start with the render target, since that is the maximum content we could possibly fill. @@ -630,8 +699,12 @@ static bool make_vertex_finite(float* value) { return true; } +static SkIRect get_clip_bounds(const GrRenderTargetContext* rtc, const GrClip* clip) { + return clip ? clip->getConservativeBounds() : SkIRect::MakeWH(rtc->width(), rtc->height()); +} + GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimization( - const GrClip& clip, const SkPMColor4f* constColor, + const GrClip* clip, const SkPMColor4f* constColor, const GrUserStencilSettings* stencilSettings, GrAA* aa, DrawQuad* quad) { // Optimization requirements: // 1. kDiscard applies when clip bounds and quad bounds do not intersect @@ -645,16 +718,9 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi // better to just keep the old flags instead of introducing mixed edge flags. GrQuadAAFlags oldFlags = quad->fEdgeFlags; - SkRect rtRect; - if (stencilSettings) { - // Must use size at which the rendertarget will ultimately be allocated so that stencil - // buffer updates on approximately sized render targets don't get corrupted. - rtRect = this->asSurfaceProxy()->backingStoreBoundsRect(); - } else { - // Use the logical size of the render target, which allows for "fullscreen" clears even if - // the render target has an approximate backing fit - rtRect = SkRect::MakeWH(this->width(), this->height()); - } + // Use the logical size of the render target, which allows for "fullscreen" clears even if + // the render target has an approximate backing fit + SkRect rtRect = this->asSurfaceProxy()->getBoundsRect(); SkRect drawBounds = quad->fDevice.bounds(); if (constColor) { @@ -692,8 +758,8 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi // regular draws so that if we fully cover the render target, that can stop being anti-aliased. GrAA clipAA = stencilSettings ? *aa : GrAA::kNo; bool axisAlignedClip = true; - if (!clip.quickContains(rtRect)) { - if (!clip.isRRect(rtRect, &clipRRect, &clipAA)) { + if (clip && !clip->quickContains(rtRect)) { + if (!clip->isRRect(&clipRRect, &clipAA)) { axisAlignedClip = false; } } @@ -717,14 +783,14 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi drawBounds = quad->fDevice.bounds(); if (drawBounds.contains(rtRect)) { // Fullscreen clear - this->clear(nullptr, *constColor, CanClearFullscreen::kYes); + this->clear(*constColor); return QuadOptimization::kSubmitted; } else if (GrClip::IsPixelAligned(drawBounds) && drawBounds.width() > 256 && drawBounds.height() > 256) { // Scissor + clear (round shouldn't do anything since we are pixel aligned) SkIRect scissorRect; drawBounds.round(&scissorRect); - this->clear(&scissorRect, *constColor, CanClearFullscreen::kNo); + this->clear(scissorRect, *constColor); return QuadOptimization::kSubmitted; } } @@ -759,7 +825,7 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi // we can draw the rrect directly and ignore the edge flags GrPaint paint; clear_to_grpaint(*constColor, &paint); - this->drawRRect(GrFixedClip::Disabled(), std::move(paint), clipAA, SkMatrix::I(), + this->drawRRect(nullptr, std::move(paint), clipAA, SkMatrix::I(), clipRRect, GrStyle::SimpleFill()); return QuadOptimization::kSubmitted; } else { @@ -771,7 +837,7 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi } // Crop the quad to the conservative bounds of the clip. - SkRect clipBounds = SkRect::Make(clip.getConservativeBounds(rtRect.width(), rtRect.height())); + SkRect clipBounds = SkRect::Make(get_clip_bounds(this, clip)); // One final check for discarding, since we may have gone here directly due to a complex clip if (!clipBounds.intersects(drawBounds)) { @@ -786,7 +852,7 @@ GrRenderTargetContext::QuadOptimization GrRenderTargetContext::attemptQuadOptimi return QuadOptimization::kCropped; } -void GrRenderTargetContext::drawFilledQuad(const GrClip& clip, +void GrRenderTargetContext::drawFilledQuad(const GrClip* clip, GrPaint&& paint, GrAA aa, DrawQuad* quad, @@ -809,8 +875,7 @@ void GrRenderTargetContext::drawFilledQuad(const GrClip& clip, QuadOptimization opt = this->attemptQuadOptimization(clip, constColor, ss, &aa, quad); if (opt >= QuadOptimization::kClipApplied) { // These optimizations require caller to add an op themselves - const GrClip& finalClip = opt == QuadOptimization::kClipApplied ? GrFixedClip::Disabled() - : clip; + const GrClip* finalClip = opt == QuadOptimization::kClipApplied ? nullptr : clip; GrAAType aaType = ss ? (aa == GrAA::kYes ? GrAAType::kMSAA : GrAAType::kNone) : this->chooseAAType(aa); this->addDrawOp(finalClip, GrFillRectOp::Make(fContext, std::move(paint), aaType, @@ -819,7 +884,7 @@ void GrRenderTargetContext::drawFilledQuad(const GrClip& clip, // All other optimization levels were completely handled inside attempt(), so no extra op needed } -void GrRenderTargetContext::drawTexturedQuad(const GrClip& clip, +void GrRenderTargetContext::drawTexturedQuad(const GrClip* clip, GrSurfaceProxyView proxyView, SkAlphaType srcAlphaType, sk_sp<GrColorSpaceXform> textureXform, @@ -844,8 +909,7 @@ void GrRenderTargetContext::drawTexturedQuad(const GrClip& clip, SkASSERT(opt != QuadOptimization::kSubmitted); if (opt != QuadOptimization::kDiscarded) { // And the texture op if not discarded - const GrClip& finalClip = opt == QuadOptimization::kClipApplied ? GrFixedClip::Disabled() - : clip; + const GrClip* finalClip = opt == QuadOptimization::kClipApplied ? nullptr : clip; GrAAType aaType = this->chooseAAType(aa); auto clampType = GrColorTypeClampType(this->colorInfo().colorType()); auto saturate = clampType == GrClampType::kManual ? GrTextureOp::Saturate::kYes @@ -859,7 +923,7 @@ void GrRenderTargetContext::drawTexturedQuad(const GrClip& clip, } } -void GrRenderTargetContext::drawRect(const GrClip& clip, +void GrRenderTargetContext::drawRect(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -904,7 +968,7 @@ void GrRenderTargetContext::drawRect(const GrClip& clip, GrStyledShape(rect, *style)); } -void GrRenderTargetContext::drawQuadSet(const GrClip& clip, GrPaint&& paint, GrAA aa, +void GrRenderTargetContext::drawQuadSet(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const QuadSetEntry quads[], int cnt) { GrAAType aaType = this->chooseAAType(aa); @@ -956,7 +1020,7 @@ void GrRenderTargetContext::setNeedsStencil(bool useMixedSamplesIfNotMSAA) { if (this->caps()->performStencilClearsAsDraws()) { // There is a driver bug with clearing stencil. We must use an op to manually clear the // stencil buffer before the op that required 'setNeedsStencil'. - this->internalStencilClear(GrFixedClip::Disabled(), /* inside mask */ false); + this->internalStencilClear(nullptr, /* inside mask */ false); } else { this->getOpsTask()->setInitialStencilContent( GrOpsTask::StencilContent::kUserBitsCleared); @@ -964,41 +1028,32 @@ void GrRenderTargetContext::setNeedsStencil(bool useMixedSamplesIfNotMSAA) { } } -void GrRenderTargetContextPriv::clearStencilClip(const GrFixedClip& clip, bool insideStencilMask) { - ASSERT_SINGLE_OWNER_PRIV - RETURN_IF_ABANDONED_PRIV - SkDEBUGCODE(fRenderTargetContext->validate();) - GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContextPriv", "clearStencilClip", - fRenderTargetContext->fContext); - - AutoCheckFlush acf(fRenderTargetContext->drawingManager()); - - fRenderTargetContext->internalStencilClear(clip, insideStencilMask); -} - -void GrRenderTargetContext::internalStencilClear(const GrFixedClip& clip, bool insideStencilMask) { +void GrRenderTargetContext::internalStencilClear(const SkIRect* scissor, bool insideStencilMask) { this->setNeedsStencil(/* useMixedSamplesIfNotMSAA = */ false); - if (this->caps()->performStencilClearsAsDraws()) { + GrScissorState scissorState(this->asSurfaceProxy()->backingStoreDimensions()); + if (scissor && !scissorState.set(*scissor)) { + // The requested clear region is off screen, so nothing to do. + return; + } + + bool clearWithDraw = this->caps()->performStencilClearsAsDraws() || + (scissorState.enabled() && this->caps()->performPartialClearsAsDraws()); + if (clearWithDraw) { const GrUserStencilSettings* ss = GrStencilSettings::SetClipBitSettings(insideStencilMask); - SkRect rtRect = SkRect::MakeWH(this->width(), this->height()); // Configure the paint to have no impact on the color buffer GrPaint paint; paint.setXPFactory(GrDisableColorXPFactory::Get()); - this->addDrawOp(clip, GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(), - rtRect, ss)); + this->addDrawOp(nullptr, + GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(), + SkRect::Make(scissorState.rect()), ss)); } else { - std::unique_ptr<GrOp> op(GrClearStencilClipOp::Make(fContext, clip, insideStencilMask, - this->asRenderTargetProxy())); - if (!op) { - return; - } - this->addOp(std::move(op)); + this->addOp(GrClearOp::MakeStencilClip(fContext, scissorState, insideStencilMask)); } } -void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip, +void GrRenderTargetContextPriv::stencilPath(const GrHardClip* clip, GrAA doStencilMSAA, const SkMatrix& viewMatrix, sk_sp<const GrPath> path) { @@ -1016,12 +1071,18 @@ void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip, // https://bugs.chromium.org/p/skia/issues/detail?id=5640 is resolved. SkRect bounds = SkRect::MakeIWH(fRenderTargetContext->width(), fRenderTargetContext->height()); - // Setup clip - GrAppliedHardClip appliedClip; - if (!clip.apply(fRenderTargetContext->width(), fRenderTargetContext->height(), &appliedClip, - &bounds)) { + // Setup clip and reject offscreen paths; we do this explicitly instead of relying on addDrawOp + // because GrStencilPathOp is not a draw op as its state depends directly on the choices made + // during this clip application. + GrAppliedHardClip appliedClip(fRenderTargetContext->dimensions(), + fRenderTargetContext->asSurfaceProxy()->backingStoreDimensions()); + + if (clip && !clip->apply(&appliedClip, &bounds)) { return; } + // else see FIXME above; we'd normally want to check path bounds with render target bounds, + // but as it is, we're just using the full render target so intersecting the two bounds would + // do nothing. std::unique_ptr<GrOp> op = GrStencilPathOp::Make(fRenderTargetContext->fContext, viewMatrix, @@ -1038,7 +1099,7 @@ void GrRenderTargetContextPriv::stencilPath(const GrHardClip& clip, fRenderTargetContext->addOp(std::move(op)); } -void GrRenderTargetContext::drawTextureSet(const GrClip& clip, TextureSetEntry set[], +void GrRenderTargetContext::drawTextureSet(const GrClip* clip, TextureSetEntry set[], int cnt, int proxyRunCnt, GrSamplerState::Filter filter, SkBlendMode mode, GrAA aa, SkCanvas::SrcRectConstraint constraint, @@ -1060,7 +1121,7 @@ void GrRenderTargetContext::drawTextureSet(const GrClip& clip, TextureSetEntry s mode, aaType, constraint, viewMatrix, std::move(texXform)); } -void GrRenderTargetContext::drawVertices(const GrClip& clip, +void GrRenderTargetContext::drawVertices(const GrClip* clip, GrPaint&& paint, const SkMatrixProvider& matrixProvider, sk_sp<SkVertices> vertices, @@ -1084,7 +1145,7 @@ void GrRenderTargetContext::drawVertices(const GrClip& clip, /////////////////////////////////////////////////////////////////////////////// -void GrRenderTargetContext::drawAtlas(const GrClip& clip, +void GrRenderTargetContext::drawAtlas(const GrClip* clip, GrPaint&& paint, const SkMatrix& viewMatrix, int spriteCount, @@ -1106,7 +1167,7 @@ void GrRenderTargetContext::drawAtlas(const GrClip& clip, /////////////////////////////////////////////////////////////////////////////// -void GrRenderTargetContext::drawRRect(const GrClip& origClip, +void GrRenderTargetContext::drawRRect(const GrClip* origClip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -1122,8 +1183,7 @@ void GrRenderTargetContext::drawRRect(const GrClip& origClip, return; } - GrNoClip noclip; - const GrClip* clip = &origClip; + const GrClip* clip = origClip; #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK // The Android framework frequently clips rrects to themselves where the clip is non-aa and the // draw is aa. Since our lower level clip code works from op bounds, which are SkRects, it @@ -1132,9 +1192,9 @@ void GrRenderTargetContext::drawRRect(const GrClip& origClip, // can be ignored. We'd prefer to fix this in the framework by removing the clips calls. This // only works for filled rrects since the stroke width outsets beyond the rrect itself. SkRRect devRRect; - if (stroke.getStyle() == SkStrokeRec::kFill_Style && rrect.transform(viewMatrix, &devRRect) && - clip->quickContains(devRRect)) { - clip = &noclip; + if (clip && stroke.getStyle() == SkStrokeRec::kFill_Style && + rrect.transform(viewMatrix, &devRRect) && clip->quickContains(devRRect)) { + clip = nullptr; } #endif SkASSERT(!style.pathEffect()); // this should've been devolved to a path in SkGpuDevice @@ -1163,12 +1223,12 @@ void GrRenderTargetContext::drawRRect(const GrClip& origClip, fContext, std::move(paint), viewMatrix, rrect, stroke, this->caps()->shaderCaps()); } if (op) { - this->addDrawOp(*clip, std::move(op)); + this->addDrawOp(clip, std::move(op)); return; } assert_alive(paint); - this->drawShapeUsingPathRenderer(*clip, std::move(paint), aa, viewMatrix, + this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewMatrix, GrStyledShape(rrect, style)); } @@ -1181,7 +1241,7 @@ static SkPoint3 map(const SkMatrix& m, const SkPoint3& pt) { return result; } -bool GrRenderTargetContext::drawFastShadow(const GrClip& clip, +bool GrRenderTargetContext::drawFastShadow(const GrClip* clip, const SkMatrix& viewMatrix, const SkPath& path, const SkDrawShadowRec& rec) { @@ -1376,7 +1436,7 @@ bool GrRenderTargetContext::drawFastShadow(const GrClip& clip, /////////////////////////////////////////////////////////////////////////////// -bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip, +bool GrRenderTargetContext::drawFilledDRRect(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -1442,18 +1502,17 @@ bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip, const auto& caps = *this->caps()->shaderCaps(); // TODO these need to be a geometry processors - auto innerEffect = GrRRectEffect::Make(innerEdgeType, *inner, caps); - if (!innerEffect) { + auto [success, fp] = GrRRectEffect::Make(/*inputFP=*/nullptr, innerEdgeType, *inner, caps); + if (!success) { return false; } - auto outerEffect = GrRRectEffect::Make(outerEdgeType, *outer, caps); - if (!outerEffect) { + std::tie(success, fp) = GrRRectEffect::Make(std::move(fp), outerEdgeType, *outer, caps); + if (!success) { return false; } - paint.addCoverageFragmentProcessor(std::move(innerEffect)); - paint.addCoverageFragmentProcessor(std::move(outerEffect)); + paint.addCoverageFragmentProcessor(std::move(fp)); SkRect bounds = outer->getBounds(); if (GrAAType::kCoverage == aaType) { @@ -1465,7 +1524,7 @@ bool GrRenderTargetContext::drawFilledDRRect(const GrClip& clip, return true; } -void GrRenderTargetContext::drawDRRect(const GrClip& clip, +void GrRenderTargetContext::drawDRRect(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -1496,7 +1555,7 @@ void GrRenderTargetContext::drawDRRect(const GrClip& clip, /////////////////////////////////////////////////////////////////////////////// -void GrRenderTargetContext::drawRegion(const GrClip& clip, +void GrRenderTargetContext::drawRegion(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -1532,7 +1591,7 @@ void GrRenderTargetContext::drawRegion(const GrClip& clip, this->addDrawOp(clip, std::move(op)); } -void GrRenderTargetContext::drawOval(const GrClip& clip, +void GrRenderTargetContext::drawOval(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -1593,7 +1652,7 @@ void GrRenderTargetContext::drawOval(const GrClip& clip, GrStyledShape(SkRRect::MakeOval(oval), SkPathDirection::kCW, 2, false, style)); } -void GrRenderTargetContext::drawArc(const GrClip& clip, +void GrRenderTargetContext::drawArc(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -1632,7 +1691,7 @@ void GrRenderTargetContext::drawArc(const GrClip& clip, GrStyledShape::MakeArc(oval, startAngle, sweepAngle, useCenter, style)); } -void GrRenderTargetContext::drawImageLattice(const GrClip& clip, +void GrRenderTargetContext::drawImageLattice(const GrClip* clip, GrPaint&& paint, const SkMatrix& viewMatrix, GrSurfaceProxyView view, @@ -1711,7 +1770,8 @@ void GrRenderTargetContext::asyncRescaleAndReadPixels( int x = srcRect.fLeft; int y = srcRect.fTop; if (needsRescale) { - tempRTC = this->rescale(info, srcRect, rescaleGamma, rescaleQuality); + tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma, + rescaleQuality); if (!tempRTC) { callback(context, nullptr); return; @@ -1754,7 +1814,7 @@ void GrRenderTargetContext::asyncRescaleAndReadPixels( callback(context, nullptr); return; } - tempRTC->drawTexture(GrNoClip(), std::move(texProxyView), this->colorInfo().alphaType(), + tempRTC->drawTexture(nullptr, std::move(texProxyView), this->colorInfo().alphaType(), GrSamplerState::Filter::kNearest, SkBlendMode::kSrc, SK_PMColor4fWHITE, srcRectToDraw, SkRect::MakeWH(srcRect.width(), srcRect.height()), GrAA::kNo, @@ -1899,7 +1959,7 @@ void GrRenderTargetContext::asyncReadPixels(const SkIRect& rect, SkColorType col GrFlushInfo flushInfo; flushInfo.fFinishedContext = finishContext; flushInfo.fFinishedProc = finishCallback; - this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo); + this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo, nullptr); } void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvColorSpace, @@ -1941,7 +2001,8 @@ void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvC auto info = SkImageInfo::Make(dstSize, kRGBA_8888_SkColorType, kPremul_SkAlphaType, dstColorSpace); // TODO: Incorporate the YUV conversion into last pass of rescaling. - auto tempRTC = this->rescale(info, srcRect, rescaleGamma, rescaleQuality); + auto tempRTC = this->rescale(info, kTopLeft_GrSurfaceOrigin, srcRect, rescaleGamma, + rescaleQuality); if (!tempRTC) { callback(context, nullptr); return; @@ -1976,7 +2037,7 @@ void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvC callback(context, nullptr); return; } - tempRTC->drawTexture(GrNoClip(), std::move(srcView), this->colorInfo().alphaType(), + tempRTC->drawTexture(nullptr, std::move(srcView), this->colorInfo().alphaType(), GrSamplerState::Filter::kNearest, SkBlendMode::kSrc, SK_PMColor4fWHITE, srcRectToDraw, SkRect::Make(srcRect.size()), GrAA::kNo, GrQuadAAFlags::kNone, SkCanvas::kFast_SrcRectConstraint, @@ -2008,7 +2069,7 @@ void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvC // TODO: Use one transfer buffer for all three planes to reduce map/unmap cost? - auto texMatrix = SkMatrix::MakeTrans(x, y); + auto texMatrix = SkMatrix::Translate(x, y); SkRect dstRectY = SkRect::Make(dstSize); SkRect dstRectUV = SkRect::MakeWH(halfW, halfH); @@ -2021,12 +2082,14 @@ void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvC std::fill_n(yM, 15, 0.f); std::copy_n(baseM + 0, 5, yM + 15); GrPaint yPaint; - yPaint.addColorFragmentProcessor( - GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix)); - auto yFP = GrColorMatrixFragmentProcessor::Make(yM, false, true, false); - yPaint.addColorFragmentProcessor(std::move(yFP)); + auto yTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix); + auto yColFP = GrColorMatrixFragmentProcessor::Make(std::move(yTexFP), yM, + /*unpremulInput=*/false, + /*clampRGBOutput=*/true, + /*premulOutput=*/false); + yPaint.addColorFragmentProcessor(std::move(yColFP)); yPaint.setPorterDuffXPFactory(SkBlendMode::kSrc); - yRTC->fillRectToRect(GrNoClip(), std::move(yPaint), GrAA::kNo, SkMatrix::I(), + yRTC->fillRectToRect(nullptr, std::move(yPaint), GrAA::kNo, SkMatrix::I(), dstRectY, dstRectY); if (!doSynchronousRead) { yTransfer = yRTC->transferPixels(GrColorType::kAlpha_8, @@ -2043,12 +2106,15 @@ void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvC std::fill_n(uM, 15, 0.f); std::copy_n(baseM + 5, 5, uM + 15); GrPaint uPaint; - uPaint.addColorFragmentProcessor(GrTextureEffect::Make( - srcView, this->colorInfo().alphaType(), texMatrix, GrSamplerState::Filter::kBilerp)); - auto uFP = GrColorMatrixFragmentProcessor::Make(uM, false, true, false); - uPaint.addColorFragmentProcessor(std::move(uFP)); + auto uTexFP = GrTextureEffect::Make(srcView, this->colorInfo().alphaType(), texMatrix, + GrSamplerState::Filter::kBilerp); + auto uColFP = GrColorMatrixFragmentProcessor::Make(std::move(uTexFP), uM, + /*unpremulInput=*/false, + /*clampRGBOutput=*/true, + /*premulOutput=*/false); + uPaint.addColorFragmentProcessor(std::move(uColFP)); uPaint.setPorterDuffXPFactory(SkBlendMode::kSrc); - uRTC->fillRectToRect(GrNoClip(), std::move(uPaint), GrAA::kNo, SkMatrix::I(), + uRTC->fillRectToRect(nullptr, std::move(uPaint), GrAA::kNo, SkMatrix::I(), dstRectUV, dstRectUV); if (!doSynchronousRead) { uTransfer = uRTC->transferPixels(GrColorType::kAlpha_8, @@ -2064,13 +2130,15 @@ void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvC std::fill_n(vM, 15, 0.f); std::copy_n(baseM + 10, 5, vM + 15); GrPaint vPaint; - vPaint.addColorFragmentProcessor(GrTextureEffect::Make(std::move(srcView), - this->colorInfo().alphaType(), texMatrix, - GrSamplerState::Filter::kBilerp)); - auto vFP = GrColorMatrixFragmentProcessor::Make(vM, false, true, false); - vPaint.addColorFragmentProcessor(std::move(vFP)); + auto vTexFP = GrTextureEffect::Make(std::move(srcView), this->colorInfo().alphaType(), + texMatrix, GrSamplerState::Filter::kBilerp); + auto vColFP = GrColorMatrixFragmentProcessor::Make(std::move(vTexFP), vM, + /*unpremulInput=*/false, + /*clampRGBOutput=*/true, + /*premulOutput=*/false); + vPaint.addColorFragmentProcessor(std::move(vColFP)); vPaint.setPorterDuffXPFactory(SkBlendMode::kSrc); - vRTC->fillRectToRect(GrNoClip(), std::move(vPaint), GrAA::kNo, SkMatrix::I(), + vRTC->fillRectToRect(nullptr, std::move(vPaint), GrAA::kNo, SkMatrix::I(), dstRectUV, dstRectUV); if (!doSynchronousRead) { vTransfer = vRTC->transferPixels(GrColorType::kAlpha_8, @@ -2150,19 +2218,26 @@ void GrRenderTargetContext::asyncRescaleAndReadPixelsYUV420(SkYUVColorSpace yuvC GrFlushInfo flushInfo; flushInfo.fFinishedContext = finishContext; flushInfo.fFinishedProc = finishCallback; - this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo); + this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, flushInfo, nullptr); } GrSemaphoresSubmitted GrRenderTargetContext::flush(SkSurface::BackendSurfaceAccess access, - const GrFlushInfo& info) { + const GrFlushInfo& info, + const GrBackendSurfaceMutableState* newState) { ASSERT_SINGLE_OWNER if (fContext->priv().abandoned()) { + if (info.fSubmittedProc) { + info.fSubmittedProc(info.fSubmittedContext, false); + } + if (info.fFinishedProc) { + info.fFinishedProc(info.fFinishedContext); + } return GrSemaphoresSubmitted::kNo; } SkDEBUGCODE(this->validate();) GR_CREATE_TRACE_MARKER_CONTEXT("GrRenderTargetContext", "flush", fContext); - return this->drawingManager()->flushSurface(this->asSurfaceProxy(), access, info); + return this->drawingManager()->flushSurface(this->asSurfaceProxy(), access, info, newState); } bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores, @@ -2197,7 +2272,7 @@ bool GrRenderTargetContext::waitOnSemaphores(int numSemaphores, return true; } -void GrRenderTargetContext::drawPath(const GrClip& clip, +void GrRenderTargetContext::drawPath(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -2213,7 +2288,7 @@ void GrRenderTargetContext::drawPath(const GrClip& clip, this->drawShape(clip, std::move(paint), aa, viewMatrix, shape); } -void GrRenderTargetContext::drawShape(const GrClip& clip, +void GrRenderTargetContext::drawShape(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -2271,7 +2346,7 @@ void GrRenderTargetContext::drawShape(const GrClip& clip, /* attempt fallback */ false); } -bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip, +bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip* clip, const GrUserStencilSettings* ss, SkRegion::Op op, bool invert, @@ -2302,8 +2377,7 @@ bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip, GrAAType aaType = fRenderTargetContext->chooseAAType(aa); bool hasUserStencilSettings = !ss->isUnused(); - SkIRect clipConservativeBounds = clip.getConservativeBounds(fRenderTargetContext->width(), - fRenderTargetContext->height()); + SkIRect clipConservativeBounds = get_clip_bounds(fRenderTargetContext, clip); GrPaint paint; paint.setCoverageSetOpXPFactory(op, invert); @@ -2332,7 +2406,7 @@ bool GrRenderTargetContextPriv::drawAndStencilPath(const GrHardClip& clip, std::move(paint), ss, fRenderTargetContext, - &clip, + clip, &clipConservativeBounds, &viewMatrix, &shape, @@ -2354,7 +2428,7 @@ SkBudgeted GrRenderTargetContextPriv::isBudgeted() const { return fRenderTargetContext->asSurfaceProxy()->isBudgeted(); } -void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip, +void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -2376,7 +2450,7 @@ void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip, return; } - SkIRect clipConservativeBounds = clip.getConservativeBounds(this->width(), this->height()); + SkIRect clipConservativeBounds = get_clip_bounds(this, clip); GrStyledShape tempShape; GrAAType aaType = this->chooseAAType(aa); @@ -2441,7 +2515,7 @@ void GrRenderTargetContext::drawShapeUsingPathRenderer(const GrClip& clip, std::move(paint), &GrUserStencilSettings::kUnused, this, - &clip, + clip, &clipConservativeBounds, &viewMatrix, canDrawArgs.fShape, @@ -2477,11 +2551,12 @@ static void op_bounds(SkRect* bounds, const GrOp* op) { } void GrRenderTargetContext::addOp(std::unique_ptr<GrOp> op) { - this->getOpsTask()->addOp( - std::move(op), GrTextureResolveManager(this->drawingManager()), *this->caps()); + GrDrawingManager* drawingMgr = this->drawingManager(); + this->getOpsTask()->addOp(drawingMgr, + std::move(op), GrTextureResolveManager(drawingMgr), *this->caps()); } -void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDrawOp> op, +void GrRenderTargetContext::addDrawOp(const GrClip* clip, std::unique_ptr<GrDrawOp> op, const std::function<WillAddOpFn>& willAddFn) { ASSERT_SINGLE_OWNER if (fContext->priv().abandoned()) { @@ -2495,7 +2570,7 @@ void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDraw // Setup clip SkRect bounds; op_bounds(&bounds, op.get()); - GrAppliedClip appliedClip; + GrAppliedClip appliedClip(this->dimensions(), this->asSurfaceProxy()->backingStoreDimensions()); GrDrawOp::FixedFunctionFlags fixedFunctionFlags = op->fixedFunctionFlags(); bool usesHWAA = fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesHWAA; bool usesUserStencilBits = fixedFunctionFlags & GrDrawOp::FixedFunctionFlags::kUsesStencil; @@ -2504,7 +2579,20 @@ void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDraw this->setNeedsStencil(usesHWAA); } - if (!clip.apply(fContext, this, usesHWAA, usesUserStencilBits, &appliedClip, &bounds)) { + bool skipDraw = false; + if (clip) { + // Have a complex clip, so defer to its early clip culling + if (!clip->apply(fContext, this, usesHWAA, usesUserStencilBits, &appliedClip, &bounds)) { + skipDraw = true; + } + } else { + // No clipping, so just clip the bounds against the logical render target dimensions + if (!bounds.intersect(this->asSurfaceProxy()->getBoundsRect())) { + skipDraw = true; + } + } + + if (skipDraw) { fContext->priv().opMemoryPool()->release(std::move(op)); return; } @@ -2524,24 +2612,26 @@ void GrRenderTargetContext::addDrawOp(const GrClip& clip, std::unique_ptr<GrDraw GrProcessorSet::Analysis analysis = op->finalize( *this->caps(), &appliedClip, hasMixedSampledCoverage, clampType); + // Must be called before setDstProxyView so that it sees the final bounds of the op. + op->setClippedBounds(bounds); + GrXferProcessor::DstProxyView dstProxyView; if (analysis.requiresDstTexture()) { - if (!this->setupDstProxyView(clip, *op, &dstProxyView)) { + if (!this->setupDstProxyView(*op, &dstProxyView)) { fContext->priv().opMemoryPool()->release(std::move(op)); return; } } - op->setClippedBounds(bounds); auto opsTask = this->getOpsTask(); if (willAddFn) { willAddFn(op.get(), opsTask->uniqueID()); } - opsTask->addDrawOp(std::move(op), analysis, std::move(appliedClip), dstProxyView, - GrTextureResolveManager(this->drawingManager()), *this->caps()); + opsTask->addDrawOp(this->drawingManager(), std::move(op), analysis, std::move(appliedClip), + dstProxyView,GrTextureResolveManager(this->drawingManager()), *this->caps()); } -bool GrRenderTargetContext::setupDstProxyView(const GrClip& clip, const GrOp& op, +bool GrRenderTargetContext::setupDstProxyView(const GrOp& op, GrXferProcessor::DstProxyView* dstProxyView) { // If we are wrapping a vulkan secondary command buffer, we can't make a dst copy because we // don't actually have a VkImage to make a copy of. Additionally we don't have the power to @@ -2561,37 +2651,20 @@ bool GrRenderTargetContext::setupDstProxyView(const GrClip& clip, const GrOp& op } } - SkIRect copyRect = SkIRect::MakeSize(this->asSurfaceProxy()->dimensions()); - - SkIRect clippedRect = clip.getConservativeBounds(this->width(), this->height()); - SkRect opBounds = op.bounds(); - // If the op has aa bloating or is a infinitely thin geometry (hairline) outset the bounds by - // 0.5 pixels. - if (op.hasAABloat() || op.hasZeroArea()) { - opBounds.outset(0.5f, 0.5f); - // An antialiased/hairline draw can sometimes bleed outside of the clips bounds. For - // performance we may ignore the clip when the draw is entirely inside the clip is float - // space but will hit pixels just outside the clip when actually rasterizing. - clippedRect.outset(1, 1); - clippedRect.intersect(SkIRect::MakeSize(this->asSurfaceProxy()->dimensions())); - } - SkIRect opIBounds; - opBounds.roundOut(&opIBounds); - if (!clippedRect.intersect(opIBounds)) { -#ifdef SK_DEBUG - GrCapsDebugf(this->caps(), "setupDstTexture: Missed an early reject bailing on draw."); -#endif - return false; - } - GrColorType colorType = this->colorInfo().colorType(); // MSAA consideration: When there is support for reading MSAA samples in the shader we could // have per-sample dst values by making the copy multisampled. GrCaps::DstCopyRestrictions restrictions = this->caps()->getDstCopyRestrictions( this->asRenderTargetProxy(), colorType); + SkIRect copyRect = SkIRect::MakeSize(this->asSurfaceProxy()->backingStoreDimensions()); if (!restrictions.fMustCopyWholeSrc) { - copyRect = clippedRect; + // If we don't need the whole source, restrict to the op's bounds. We add an extra pixel + // of padding to account for AA bloat and the unpredictable rounding of coords near pixel + // centers during rasterization. + SkIRect conservativeDrawBounds = op.bounds().roundOut(); + conservativeDrawBounds.outset(1, 1); + SkAssertResult(copyRect.intersect(conservativeDrawBounds)); } SkIPoint dstOffset; @@ -2633,7 +2706,7 @@ bool GrRenderTargetContext::blitTexture(GrSurfaceProxyView view, const SkIRect& paint.addColorFragmentProcessor(std::move(fp)); this->fillRectToRect( - GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), + nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::MakeXYWH(clippedDstPoint.fX, clippedDstPoint.fY, clippedSrcRect.width(), clippedSrcRect.height()), SkRect::Make(clippedSrcRect)); diff --git a/chromium/third_party/skia/src/gpu/GrRenderTargetContext.h b/chromium/third_party/skia/src/gpu/GrRenderTargetContext.h index ca0ac266de0..350461b081a 100644 --- a/chromium/third_party/skia/src/gpu/GrRenderTargetContext.h +++ b/chromium/third_party/skia/src/gpu/GrRenderTargetContext.h @@ -14,6 +14,7 @@ #include "include/core/SkSurface.h" #include "include/core/SkSurfaceProps.h" #include "include/private/GrTypesPriv.h" +#include "src/core/SkGlyphRunPainter.h" #include "src/gpu/GrOpsTask.h" #include "src/gpu/GrPaint.h" #include "src/gpu/GrRenderTargetProxy.h" @@ -28,7 +29,6 @@ class GrClip; class GrColorSpaceXform; class GrCoverageCountingPathRenderer; class GrDrawOp; -class GrFixedClip; class GrOp; class GrRenderTarget; class GrRenderTargetContextPriv; @@ -118,8 +118,8 @@ public: // Creates a GrRenderTargetContext that wraps the passed in GrBackendTexture. static std::unique_ptr<GrRenderTargetContext> MakeFromBackendTexture( GrRecordingContext*, GrColorType, sk_sp<SkColorSpace>, const GrBackendTexture&, - int sampleCnt, GrSurfaceOrigin, const SkSurfaceProps*, ReleaseProc releaseProc, - ReleaseContext releaseCtx); + int sampleCnt, GrSurfaceOrigin, const SkSurfaceProps*, + sk_sp<GrRefCntedCallback> releaseHelper); static std::unique_ptr<GrRenderTargetContext> MakeFromBackendTextureAsRenderTarget( GrRecordingContext*, GrColorType, sk_sp<SkColorSpace>, const GrBackendTexture&, @@ -140,7 +140,7 @@ public: ~GrRenderTargetContext() override; - virtual void drawGlyphRunList(const GrClip&, const SkMatrixProvider&, const SkGlyphRunList&); + virtual void drawGlyphRunList(const GrClip*, const SkMatrixProvider&, const SkGlyphRunList&); /** * Provides a perfomance hint that the render target's contents are allowed @@ -148,28 +148,23 @@ public: */ void discard(); - enum class CanClearFullscreen : bool { - kNo = false, - kYes = true - }; - /** - * Clear the entire or rect of the render target, ignoring any clips. - * @param rect the rect to clear or the whole thing if rect is NULL. + * Clear the rect of the render target to the given color. + * @param rect the rect to clear to * @param color the color to clear to. - * @param CanClearFullscreen allows partial clears to be converted to fullscreen clears on - * tiling platforms where that is an optimization. */ - void clear(const SkIRect* rect, const SkPMColor4f& color, CanClearFullscreen); - + void clear(const SkIRect& rect, const SkPMColor4f& color) { + this->internalClear(&rect, color); + } + // Clears the entire render target to the color. void clear(const SkPMColor4f& color) { - return this->clear(nullptr, color, CanClearFullscreen::kYes); + this->internalClear(nullptr, color); } /** * Draw everywhere (respecting the clip) with the paint. */ - void drawPaint(const GrClip&, GrPaint&&, const SkMatrix& viewMatrix); + void drawPaint(const GrClip*, GrPaint&&, const SkMatrix& viewMatrix); /** * Draw the rect using a paint. @@ -180,7 +175,7 @@ public: * allowed. * The rects coords are used to access the paint (through texture matrix) */ - void drawRect(const GrClip&, + void drawRect(const GrClip*, GrPaint&& paint, GrAA, const SkMatrix& viewMatrix, @@ -196,7 +191,7 @@ public: * @param rectToDraw the rectangle to draw * @param localRect the rectangle of shader coordinates applied to rectToDraw */ - void fillRectToRect(const GrClip& clip, + void fillRectToRect(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -210,7 +205,7 @@ public: /** * Fills a rect with a paint and a localMatrix. */ - void fillRectWithLocalMatrix(const GrClip& clip, + void fillRectWithLocalMatrix(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -228,7 +223,7 @@ public: * This is a specialized version of fillQuadWithEdgeAA, but is kept separate since knowing * the geometry is a rectangle affords more optimizations. */ - void fillRectWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa, GrQuadAAFlags edgeAA, + void fillRectWithEdgeAA(const GrClip* clip, GrPaint&& paint, GrAA aa, GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix, const SkRect& rect, const SkRect* optionalLocalRect = nullptr) { const SkRect& localRect = optionalLocalRect ? *optionalLocalRect : rect; @@ -248,7 +243,7 @@ public: * The last argument, 'optionalLocalQuad', can be null if no separate local coordinates are * necessary. */ - void fillQuadWithEdgeAA(const GrClip& clip, GrPaint&& paint, GrAA aa, GrQuadAAFlags edgeAA, + void fillQuadWithEdgeAA(const GrClip* clip, GrPaint&& paint, GrAA aa, GrQuadAAFlags edgeAA, const SkMatrix& viewMatrix, const SkPoint points[4], const SkPoint optionalLocalPoints[4]) { const SkPoint* localPoints = optionalLocalPoints ? optionalLocalPoints : points; @@ -266,7 +261,7 @@ public: }; // TODO(michaelludwig) - remove if the bulk API is not useful for SkiaRenderer - void drawQuadSet(const GrClip& clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, + void drawQuadSet(const GrClip* clip, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, const QuadSetEntry[], int cnt); /** @@ -275,7 +270,7 @@ public: * specifies the rectangle to draw in local coords which will be transformed by 'viewMatrix' to * device space. */ - void drawTexture(const GrClip& clip, GrSurfaceProxyView view, SkAlphaType srcAlphaType, + void drawTexture(const GrClip* clip, GrSurfaceProxyView view, SkAlphaType srcAlphaType, GrSamplerState::Filter filter, SkBlendMode mode, const SkPMColor4f& color, const SkRect& srcRect, const SkRect& dstRect, GrAA aa, GrQuadAAFlags edgeAA, SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, @@ -294,7 +289,7 @@ public: * 'subset' is null, it's equivalent to using the fast src rect constraint. If 'subset' is * provided, the strict src rect constraint is applied using 'subset'. */ - void drawTextureQuad(const GrClip& clip, GrSurfaceProxyView view, GrColorType srcColorType, + void drawTextureQuad(const GrClip* clip, GrSurfaceProxyView view, GrColorType srcColorType, SkAlphaType srcAlphaType, GrSamplerState::Filter filter, SkBlendMode mode, const SkPMColor4f& color, const SkPoint srcQuad[4], const SkPoint dstQuad[4], GrAA aa, GrQuadAAFlags edgeAA, @@ -314,7 +309,7 @@ public: SkRect fDstRect; const SkPoint* fDstClipQuad; // Must be null, or point to an array of 4 points const SkMatrix* fPreViewMatrix; // If not null, entry's CTM is 'viewMatrix' * fPreViewMatrix - float fAlpha; + SkPMColor4f fColor; // {a,a,a,a} for rgb textures, {r,g,b,a} for alpha-only textures GrQuadAAFlags fAAFlags; }; /** @@ -328,7 +323,7 @@ public: * can be inferred from the array within this function, but the information is already known * by SkGpuDevice, so no need to incur another iteration over the array. */ - void drawTextureSet(const GrClip&, TextureSetEntry[], int cnt, int proxyRunCnt, + void drawTextureSet(const GrClip*, TextureSetEntry[], int cnt, int proxyRunCnt, GrSamplerState::Filter, SkBlendMode mode, GrAA aa, SkCanvas::SrcRectConstraint, const SkMatrix& viewMatrix, sk_sp<GrColorSpaceXform> texXform); @@ -342,7 +337,7 @@ public: * @param rrect the roundrect to draw * @param style style to apply to the rrect. Currently path effects are not allowed. */ - void drawRRect(const GrClip&, + void drawRRect(const GrClip*, GrPaint&&, GrAA, const SkMatrix& viewMatrix, @@ -357,7 +352,7 @@ public: * @param path the path to shadow * @param rec parameters for shadow rendering */ - bool drawFastShadow(const GrClip&, + bool drawFastShadow(const GrClip*, const SkMatrix& viewMatrix, const SkPath& path, const SkDrawShadowRec& rec); @@ -372,7 +367,7 @@ public: * @param outer the outer roundrect * @param inner the inner roundrect */ - void drawDRRect(const GrClip&, + void drawDRRect(const GrClip*, GrPaint&&, GrAA, const SkMatrix& viewMatrix, @@ -388,7 +383,7 @@ public: * @param path the path to draw * @param style style to apply to the path. */ - void drawPath(const GrClip&, + void drawPath(const GrClip*, GrPaint&&, GrAA, const SkMatrix& viewMatrix, @@ -403,7 +398,7 @@ public: * @param viewMatrix transformation matrix * @param shape the shape to draw */ - void drawShape(const GrClip&, + void drawShape(const GrClip*, GrPaint&&, GrAA, const SkMatrix& viewMatrix, @@ -419,7 +414,7 @@ public: * @param overridePrimType primitive type to draw. If NULL, derive prim type from vertices. * @param effect runtime effect that will handle custom vertex attributes. */ - void drawVertices(const GrClip&, + void drawVertices(const GrClip*, GrPaint&& paint, const SkMatrixProvider& matrixProvider, sk_sp<SkVertices> vertices, @@ -438,7 +433,7 @@ public: * @param colors optional array of per-sprite colors, supercedes * the paint's color field. */ - void drawAtlas(const GrClip&, + void drawAtlas(const GrClip*, GrPaint&& paint, const SkMatrix& viewMatrix, int spriteCount, @@ -455,7 +450,7 @@ public: * @param region the region to be drawn * @param style style to apply to the region */ - void drawRegion(const GrClip&, + void drawRegion(const GrClip*, GrPaint&& paint, GrAA aa, const SkMatrix& viewMatrix, @@ -472,7 +467,7 @@ public: * @param oval the bounding rect of the oval. * @param style style to apply to the oval. Currently path effects are not allowed. */ - void drawOval(const GrClip&, + void drawOval(const GrClip*, GrPaint&& paint, GrAA, const SkMatrix& viewMatrix, @@ -493,7 +488,7 @@ public: * omitted. * @param style style to apply to the oval. */ - void drawArc(const GrClip&, + void drawArc(const GrClip*, GrPaint&& paint, GrAA, const SkMatrix& viewMatrix, @@ -506,7 +501,7 @@ public: /** * Draw the image as a set of rects, specified by |iter|. */ - void drawImageLattice(const GrClip&, + void drawImageLattice(const GrClip*, GrPaint&&, const SkMatrix& viewMatrix, GrSurfaceProxyView, @@ -551,7 +546,8 @@ public: * After this returns any pending surface IO will be issued to the backend 3D API and * if the surface has MSAA it will be resolved. */ - GrSemaphoresSubmitted flush(SkSurface::BackendSurfaceAccess access, const GrFlushInfo&); + GrSemaphoresSubmitted flush(SkSurface::BackendSurfaceAccess access, const GrFlushInfo&, + const GrBackendSurfaceMutableState*); /** * The next time this GrRenderTargetContext is flushed, the gpu will wait on the passed in @@ -594,13 +590,12 @@ private: GrAAType chooseAAType(GrAA); - friend class GrAtlasTextBlob; // for access to add[Mesh]DrawOp friend class GrClipStackClip; // for access to getOpsTask friend class GrOnFlushResourceProvider; // for access to getOpsTask (http://skbug.com/9357) friend class GrRenderTargetContextPriv; - // All the path renderers currently make their own ops + // All the path and text renderers/ops currently make their own ops friend class GrSoftwarePathRenderer; // for access to add[Mesh]DrawOp friend class GrAAConvexPathRenderer; // for access to add[Mesh]DrawOp friend class GrDashLinePathRenderer; // for access to add[Mesh]DrawOp @@ -615,6 +610,7 @@ private: friend class GrFillRectOp; // for access to addDrawOp friend class GrTessellationPathRenderer; // for access to addDrawOp friend class GrTextureOp; // for access to addDrawOp + friend class GrAtlasTextOp; // for access to addDrawOp SkDEBUGCODE(void onValidate() const override;) @@ -622,11 +618,12 @@ private: GrOpsTask::CanDiscardPreviousOps canDiscardPreviousOpsOnFullClear() const; void setNeedsStencil(bool useMixedSamplesIfNotMSAA); - void internalClear(const GrFixedClip&, const SkPMColor4f&, CanClearFullscreen); - void internalStencilClear(const GrFixedClip&, bool insideStencilMask); + void internalClear(const SkIRect* scissor, const SkPMColor4f&, + bool upgradePartialToFull = false); + void internalStencilClear(const SkIRect* scissor, bool insideStencilMask); // Only consumes the GrPaint if successful. - bool drawFilledDRRect(const GrClip& clip, + bool drawFilledDRRect(const GrClip* clip, GrPaint&& paint, GrAA, const SkMatrix& viewMatrix, @@ -642,7 +639,7 @@ private: // // 'stencilSettings' are provided merely for decision making purposes; When non-null, // optimization strategies that submit special ops are avoided. - QuadOptimization attemptQuadOptimization(const GrClip& clip, + QuadOptimization attemptQuadOptimization(const GrClip* clip, const SkPMColor4f* constColor, const GrUserStencilSettings* stencilSettings, GrAA* aa, @@ -652,7 +649,7 @@ private: // can choose between coverage, MSAA as per chooseAAType(). This will always attempt to apply // quad optimizations, so all quad/rect public APIs should rely on this function for consistent // clipping behavior. 'quad' will be modified in place to reflect final rendered geometry. - void drawFilledQuad(const GrClip& clip, + void drawFilledQuad(const GrClip* clip, GrPaint&& paint, GrAA aa, DrawQuad* quad, @@ -660,7 +657,7 @@ private: // Like drawFilledQuad but does not require using a GrPaint or FP for texturing. // 'quad' may be modified in place to reflect final geometry. - void drawTexturedQuad(const GrClip& clip, + void drawTexturedQuad(const GrClip* clip, GrSurfaceProxyView proxyView, SkAlphaType alphaType, sk_sp<GrColorSpaceXform> textureXform, @@ -673,7 +670,7 @@ private: // If 'attemptShapeFallback' is true, and the original shape had been simplfied, this // will re-route through drawShape() to see if we can avoid path rendering one more time. - void drawShapeUsingPathRenderer(const GrClip&, GrPaint&&, GrAA, const SkMatrix&, + void drawShapeUsingPathRenderer(const GrClip*, GrPaint&&, GrAA, const SkMatrix&, const GrStyledShape&, bool attemptShapeFallback = true); void addOp(std::unique_ptr<GrOp>); @@ -684,13 +681,17 @@ private: // op list. Before adding the op to an op list the WillAddOpFn is called. Note that it // will not be called in the event that the op is discarded. Moreover, the op may merge into // another op after the function is called (either before addDrawOp returns or some time later). - void addDrawOp(const GrClip&, std::unique_ptr<GrDrawOp>, + // + // If the clip pointer is null, no clipping will be performed. + void addDrawOp(const GrClip*, std::unique_ptr<GrDrawOp>, const std::function<WillAddOpFn>& = std::function<WillAddOpFn>()); // Makes a copy of the proxy if it is necessary for the draw and places the texture that should // be used by GrXferProcessor to access the destination color in 'result'. If the return // value is false then a texture copy could not be made. - bool SK_WARN_UNUSED_RESULT setupDstProxyView(const GrClip&, const GrOp& op, + // + // The op should have already had setClippedBounds called on it. + bool SK_WARN_UNUSED_RESULT setupDstProxyView(const GrOp& op, GrXferProcessor::DstProxyView* result); class AsyncReadResult; @@ -701,6 +702,8 @@ private: GrOpsTask* getOpsTask(); + SkGlyphRunListPainter* glyphPainter() { return &fGlyphPainter; } + std::unique_ptr<GrTextTarget> fTextTarget; GrSurfaceProxyView fWriteView; @@ -716,7 +719,7 @@ private: #if GR_TEST_UTILS bool fPreserveOpsOnFullClear_TestingOnly = false; #endif - + SkGlyphRunListPainter fGlyphPainter; typedef GrSurfaceContext INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/GrRenderTargetContextPriv.h b/chromium/third_party/skia/src/gpu/GrRenderTargetContextPriv.h index 188d251002d..4e1e227fbc9 100644 --- a/chromium/third_party/skia/src/gpu/GrRenderTargetContextPriv.h +++ b/chromium/third_party/skia/src/gpu/GrRenderTargetContextPriv.h @@ -12,7 +12,6 @@ #include "src/gpu/GrPathRendering.h" #include "src/gpu/GrRenderTargetContext.h" -class GrFixedClip; class GrHardClip; class GrPath; class GrRenderTargetPriv; @@ -43,17 +42,21 @@ public: opsTask->fLastClipNumAnalyticFPs != numClipAnalyticFPs; } - using CanClearFullscreen = GrRenderTargetContext::CanClearFullscreen; - - void clear(const GrFixedClip&, const SkPMColor4f&, CanClearFullscreen); + // Clear at minimum the pixels within 'scissor', but is allowed to clear the full render target + // if that is the more performant option. + void clearAtLeast(const SkIRect& scissor, const SkPMColor4f& color) { + fRenderTargetContext->internalClear(&scissor, color, /* upgrade to full */ true); + } - void clearStencilClip(const GrFixedClip&, bool insideStencilMask); + void clearStencilClip(const SkIRect& scissor, bool insideStencilMask) { + fRenderTargetContext->internalStencilClear(&scissor, insideStencilMask); + } // While this can take a general clip, since GrReducedClip relies on this function, it must take // care to only provide hard clips or we could get stuck in a loop. The general clip is needed // so that path renderers can use this function. void stencilRect( - const GrClip& clip, const GrUserStencilSettings* ss, GrPaint&& paint, + const GrClip* clip, const GrUserStencilSettings* ss, GrPaint&& paint, GrAA doStencilMSAA, const SkMatrix& viewMatrix, const SkRect& rect, const SkMatrix* localMatrix = nullptr) { // Since this provides stencil settings to drawFilledQuad, it performs a different AA type @@ -65,13 +68,13 @@ public: } void stencilPath( - const GrHardClip&, GrAA doStencilMSAA, const SkMatrix& viewMatrix, sk_sp<const GrPath>); + const GrHardClip*, GrAA doStencilMSAA, const SkMatrix& viewMatrix, sk_sp<const GrPath>); /** * Draws a path, either AA or not, and touches the stencil buffer with the user stencil settings * for each color sample written. */ - bool drawAndStencilPath(const GrHardClip&, + bool drawAndStencilPath(const GrHardClip*, const GrUserStencilSettings*, SkRegion::Op op, bool invert, @@ -95,7 +98,7 @@ public: using WillAddOpFn = GrRenderTargetContext::WillAddOpFn; void testingOnly_addDrawOp(std::unique_ptr<GrDrawOp>); - void testingOnly_addDrawOp(const GrClip&, std::unique_ptr<GrDrawOp>, + void testingOnly_addDrawOp(const GrClip*, std::unique_ptr<GrDrawOp>, const std::function<WillAddOpFn>& = std::function<WillAddOpFn>()); bool refsWrappedObjects() const { diff --git a/chromium/third_party/skia/src/gpu/GrRenderTargetProxy.h b/chromium/third_party/skia/src/gpu/GrRenderTargetProxy.h index de21acc23cb..31193ae184b 100644 --- a/chromium/third_party/skia/src/gpu/GrRenderTargetProxy.h +++ b/chromium/third_party/skia/src/gpu/GrRenderTargetProxy.h @@ -60,7 +60,7 @@ public: bool wrapsVkSecondaryCB() const { return fWrapsVkSecondaryCB == WrapsVkSecondaryCB::kYes; } void markMSAADirty(const SkIRect& dirtyRect, GrSurfaceOrigin origin) { - SkASSERT(SkIRect::MakeSize(this->dimensions()).contains(dirtyRect)); + SkASSERT(SkIRect::MakeSize(this->backingStoreDimensions()).contains(dirtyRect)); SkASSERT(this->requiresManualMSAAResolve()); auto nativeRect = GrNativeRect::MakeRelativeTo( origin, this->backingStoreDimensions().height(), dirtyRect); diff --git a/chromium/third_party/skia/src/gpu/GrRenderTask.cpp b/chromium/third_party/skia/src/gpu/GrRenderTask.cpp index 7dc434b8276..fece63f45b2 100644 --- a/chromium/third_party/skia/src/gpu/GrRenderTask.cpp +++ b/chromium/third_party/skia/src/gpu/GrRenderTask.cpp @@ -26,21 +26,24 @@ GrRenderTask::GrRenderTask() , fFlags(0) { } -GrRenderTask::GrRenderTask(GrSurfaceProxyView targetView) - : fTargetView(std::move(targetView)) - , fUniqueID(CreateUniqueID()) - , fFlags(0) { -} +void GrRenderTask::disown(GrDrawingManager* drawingMgr) { + if (this->isSetFlag(kDisowned_Flag)) { + return; + } + this->setFlag(kDisowned_Flag); -GrRenderTask::~GrRenderTask() { - GrSurfaceProxy* proxy = fTargetView.proxy(); - if (proxy && this == proxy->getLastRenderTask()) { - // Ensure the target proxy doesn't keep hold of a dangling back pointer. - proxy->setLastRenderTask(nullptr); + for (const GrSurfaceProxyView& target : fTargets) { + if (this == drawingMgr->getLastRenderTask(target.proxy())) { + drawingMgr->setLastRenderTask(target.proxy(), nullptr); + } } } #ifdef SK_DEBUG +GrRenderTask::~GrRenderTask() { + SkASSERT(this->isSetFlag(kDisowned_Flag)); +} + bool GrRenderTask::deferredProxiesAreInstantiated() const { for (int i = 0; i < fDeferredProxies.count(); ++i) { if (!fDeferredProxies[i]->isInstantiated()) { @@ -59,13 +62,13 @@ void GrRenderTask::makeClosed(const GrCaps& caps) { SkIRect targetUpdateBounds; if (ExpectedOutcome::kTargetDirty == this->onMakeClosed(caps, &targetUpdateBounds)) { - GrSurfaceProxy* proxy = fTargetView.proxy(); + GrSurfaceProxy* proxy = this->target(0).proxy(); if (proxy->requiresManualMSAAResolve()) { - SkASSERT(fTargetView.asRenderTargetProxy()); - fTargetView.asRenderTargetProxy()->markMSAADirty(targetUpdateBounds, - fTargetView.origin()); + SkASSERT(this->target(0).asRenderTargetProxy()); + this->target(0).asRenderTargetProxy()->markMSAADirty(targetUpdateBounds, + this->target(0).origin()); } - GrTextureProxy* textureProxy = fTargetView.asTextureProxy(); + GrTextureProxy* textureProxy = this->target(0).asTextureProxy(); if (textureProxy && GrMipMapped::kYes == textureProxy->mipMapped()) { textureProxy->markMipMapsDirty(); } @@ -111,13 +114,14 @@ void GrRenderTask::addDependenciesFromOtherTask(GrRenderTask* otherTask) { } // Convert from a GrSurface-based dependency to a GrRenderTask one -void GrRenderTask::addDependency(GrSurfaceProxy* dependedOn, GrMipMapped mipMapped, +void GrRenderTask::addDependency(GrDrawingManager* drawingMgr, GrSurfaceProxy* dependedOn, + GrMipMapped mipMapped, GrTextureResolveManager textureResolveManager, const GrCaps& caps) { // If it is still receiving dependencies, this GrRenderTask shouldn't be closed SkASSERT(!this->isClosed()); - GrRenderTask* dependedOnTask = dependedOn->getLastRenderTask(); + GrRenderTask* dependedOnTask = drawingMgr->getLastRenderTask(dependedOn); if (dependedOnTask == this) { // self-read - presumably for dst reads. We don't need to do anything in this case. The @@ -168,11 +172,11 @@ void GrRenderTask::addDependency(GrSurfaceProxy* dependedOn, GrMipMapped mipMapp if (!fTextureResolveTask) { fTextureResolveTask = textureResolveManager.newTextureResolveRenderTask(caps); } - fTextureResolveTask->addProxy(sk_ref_sp(dependedOn), resolveFlags, caps); + fTextureResolveTask->addProxy(drawingMgr, sk_ref_sp(dependedOn), resolveFlags, caps); // addProxy() should have closed the texture proxy's previous task. SkASSERT(!dependedOnTask || dependedOnTask->isClosed()); - SkASSERT(dependedOn->getLastRenderTask() == fTextureResolveTask); + SkASSERT(drawingMgr->getLastRenderTask(dependedOn) == fTextureResolveTask); #ifdef SK_DEBUG // addProxy() should have called addDependency (in this instance, recursively) on @@ -192,7 +196,7 @@ void GrRenderTask::addDependency(GrSurfaceProxy* dependedOn, GrMipMapped mipMapp if (textureProxy) { SkASSERT(!textureProxy->mipMapsAreDirty()); } - SkASSERT(dependedOn->getLastRenderTask() == fTextureResolveTask); + SkASSERT(drawingMgr->getLastRenderTask(dependedOn) == fTextureResolveTask); #endif return; } @@ -250,11 +254,11 @@ void GrRenderTask::closeThoseWhoDependOnMe(const GrCaps& caps) { } bool GrRenderTask::isInstantiated() const { - // Some renderTasks (e.g. GrTransferFromRenderTask) don't have a target. - GrSurfaceProxy* proxy = fTargetView.proxy(); - if (!proxy) { + // Some renderTasks (e.g. GrTransferFromRenderTask) don't have any targets. + if (0 == this->numTargets()) { return true; } + GrSurfaceProxy* proxy = this->target(0).proxy(); if (!proxy->isInstantiated()) { return false; @@ -268,16 +272,29 @@ bool GrRenderTask::isInstantiated() const { return true; } +void GrRenderTask::addTarget(GrDrawingManager* drawingMgr, GrSurfaceProxyView view) { + SkASSERT(view); + drawingMgr->setLastRenderTask(view.proxy(), this); + fTargets.push_back(std::move(view)); +} + #ifdef SK_DEBUG void GrRenderTask::dump(bool printDependencies) const { SkDebugf("--------------------------------------------------------------\n"); - GrSurfaceProxy* proxy = fTargetView.proxy(); - SkDebugf("%s - renderTaskID: %d - proxyID: %d - surfaceID: %d\n", - this->name(), fUniqueID, - proxy ? proxy->uniqueID().asUInt() : -1, - proxy && proxy->peekSurface() - ? proxy->peekSurface()->uniqueID().asUInt() - : -1); + SkDebugf("%s - renderTaskID: %d\n", this->name(), fUniqueID); + + if (!fTargets.empty()) { + SkDebugf("Targets: \n"); + for (int i = 0; i < fTargets.count(); ++i) { + GrSurfaceProxy* proxy = fTargets[i].proxy(); + SkDebugf("[%d]: proxyID: %d - surfaceID: %d\n", + i, + proxy ? proxy->uniqueID().asUInt() : -1, + proxy && proxy->peekSurface() + ? proxy->peekSurface()->uniqueID().asUInt() + : -1); + } + } if (printDependencies) { SkDebugf("I rely On (%d): ", fDependencies.count()); diff --git a/chromium/third_party/skia/src/gpu/GrRenderTask.h b/chromium/third_party/skia/src/gpu/GrRenderTask.h index 83f17d90243..64431a18fea 100644 --- a/chromium/third_party/skia/src/gpu/GrRenderTask.h +++ b/chromium/third_party/skia/src/gpu/GrRenderTask.h @@ -14,6 +14,7 @@ #include "src/gpu/GrSurfaceProxyView.h" #include "src/gpu/GrTextureProxy.h" #include "src/gpu/GrTextureResolveManager.h" +#include "src/gpu/ops/GrOp.h" class GrOpFlushState; class GrOpsTask; @@ -26,8 +27,7 @@ class GrTextureResolveRenderTask; class GrRenderTask : public SkRefCnt { public: GrRenderTask(); - GrRenderTask(GrSurfaceProxyView); - ~GrRenderTask() override; + SkDEBUGCODE(~GrRenderTask() override); void makeClosed(const GrCaps&); @@ -40,15 +40,20 @@ public: // Called when this class will survive a flush and needs to truncate its ops and start over. // TODO: ultimately it should be invalid for an op list to survive a flush. // https://bugs.chromium.org/p/skia/issues/detail?id=7111 - virtual void endFlush() {} + virtual void endFlush(GrDrawingManager*) {} + + // This method "disowns" all the GrSurfaceProxies this RenderTask modifies. In + // practice this just means telling the drawingManager to forget the relevant + // mappings from surface proxy to last modifying rendertask. + virtual void disown(GrDrawingManager*); bool isClosed() const { return this->isSetFlag(kClosed_Flag); } /* * Notify this GrRenderTask that it relies on the contents of 'dependedOn' */ - void addDependency(GrSurfaceProxy* dependedOn, GrMipMapped, GrTextureResolveManager, - const GrCaps& caps); + void addDependency(GrDrawingManager*, GrSurfaceProxy* dependedOn, GrMipMapped, + GrTextureResolveManager, const GrCaps& caps); /* * Notify this GrRenderTask that it relies on the contents of all GrRenderTasks which otherTask @@ -62,6 +67,8 @@ public: bool dependsOn(const GrRenderTask* dependedOn) const; uint32_t uniqueID() const { return fUniqueID; } + int numTargets() const { return fTargets.count(); } + const GrSurfaceProxyView& target(int i) const { return fTargets[i]; } /* * Safely cast this GrRenderTask to a GrOpsTask (if possible). @@ -81,8 +88,8 @@ public: void visitTargetAndSrcProxies_debugOnly(const GrOp::VisitProxyFunc& fn) const { this->visitProxies_debugOnly(fn); - if (fTargetView.proxy()) { - fn(fTargetView.proxy(), GrMipMapped::kNo); + for (int i = 0; i < this->numTargets(); ++i) { + fn(this->target(i).proxy(), GrMipMapped::kNo); } } #endif @@ -94,6 +101,10 @@ protected: SkDEBUGCODE(bool deferredProxiesAreInstantiated() const;) + // Add a target surface proxy to the list of targets for this task. + // This also informs the drawing manager to update the lastRenderTask association. + void addTarget(GrDrawingManager*, GrSurfaceProxyView); + enum class ExpectedOutcome : bool { kTargetUnchanged, kTargetDirty, @@ -106,7 +117,7 @@ protected: // targetUpdateBounds must not extend beyond the proxy bounds. virtual ExpectedOutcome onMakeClosed(const GrCaps&, SkIRect* targetUpdateBounds) = 0; - GrSurfaceProxyView fTargetView; + SkSTArray<1, GrSurfaceProxyView> fTargets; // List of texture proxies whose contents are being prepared on a worker thread // TODO: this list exists so we can fire off the proper upload when an renderTask begins @@ -118,15 +129,19 @@ private: friend class GrDrawingManager; // Drops any pending operations that reference proxies that are not instantiated. - // NOTE: Derived classes don't need to check fTargetView. That is handled when the + // NOTE: Derived classes don't need to check targets. That is handled when the // drawingManager calls isInstantiated. virtual void handleInternalAllocationFailure() = 0; + // Derived classes can override to indicate usage of proxies _other than target proxies_. + // GrRenderTask itself will handle checking the target proxies. virtual bool onIsUsed(GrSurfaceProxy*) const = 0; bool isUsed(GrSurfaceProxy* proxy) const { - if (proxy == fTargetView.proxy()) { - return true; + for (const GrSurfaceProxyView& target : fTargets) { + if (target.proxy() == proxy) { + return true; + } } return this->onIsUsed(proxy); @@ -144,10 +159,11 @@ private: static uint32_t CreateUniqueID(); enum Flags { - kClosed_Flag = 0x01, //!< This GrRenderTask can't accept any more dependencies. + kClosed_Flag = 0x01, //!< This task can't accept any more dependencies. + kDisowned_Flag = 0x02, //!< This task is disowned by its creating GrDrawingManager. - kWasOutput_Flag = 0x02, //!< Flag for topological sorting - kTempMark_Flag = 0x04, //!< Flag for topological sorting + kWasOutput_Flag = 0x04, //!< Flag for topological sorting + kTempMark_Flag = 0x08, //!< Flag for topological sorting }; void setFlag(uint32_t flag) { diff --git a/chromium/third_party/skia/src/gpu/GrResourceCache.cpp b/chromium/third_party/skia/src/gpu/GrResourceCache.cpp index cdc0e21f24b..b3166acf1a6 100644 --- a/chromium/third_party/skia/src/gpu/GrResourceCache.cpp +++ b/chromium/third_party/skia/src/gpu/GrResourceCache.cpp @@ -28,8 +28,7 @@ DECLARE_SKMESSAGEBUS_MESSAGE(GrUniqueKeyInvalidatedMessage); DECLARE_SKMESSAGEBUS_MESSAGE(GrTextureFreedMessage); -#define ASSERT_SINGLE_OWNER \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) +#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fSingleOwner) ////////////////////////////////////////////////////////////////////////////// diff --git a/chromium/third_party/skia/src/gpu/GrResourceCache.h b/chromium/third_party/skia/src/gpu/GrResourceCache.h index 4db77e21867..23639dc3890 100644 --- a/chromium/third_party/skia/src/gpu/GrResourceCache.h +++ b/chromium/third_party/skia/src/gpu/GrResourceCache.h @@ -61,7 +61,7 @@ public: ~GrResourceCache(); // Default maximum number of bytes of gpu memory of budgeted resources in the cache. - static const size_t kDefaultMaxSize = 96 * (1 << 20); + static const size_t kDefaultMaxSize = 256 * (1 << 20); /** Used to access functionality needed by GrGpuResource for lifetime management. */ class ResourceAccess; diff --git a/chromium/third_party/skia/src/gpu/GrResourceProvider.cpp b/chromium/third_party/skia/src/gpu/GrResourceProvider.cpp index f079c7d9df2..2c9d9b145bb 100644 --- a/chromium/third_party/skia/src/gpu/GrResourceProvider.cpp +++ b/chromium/third_party/skia/src/gpu/GrResourceProvider.cpp @@ -31,8 +31,7 @@ const int GrResourceProvider::kMinScratchTextureSize = 16; -#define ASSERT_SINGLE_OWNER \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);) +#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fSingleOwner) GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner) : fCache(cache) diff --git a/chromium/third_party/skia/src/gpu/GrRingBuffer.cpp b/chromium/third_party/skia/src/gpu/GrRingBuffer.cpp new file mode 100644 index 00000000000..145c88a72df --- /dev/null +++ b/chromium/third_party/skia/src/gpu/GrRingBuffer.cpp @@ -0,0 +1,91 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/gpu/GrRingBuffer.h" + +// Get offset into buffer that has enough space for size +// Returns fTotalSize if no space +size_t GrRingBuffer::getAllocationOffset(size_t size) { + // capture current state locally (because fTail could be overwritten by the completion handler) + size_t head, tail; + SkAutoSpinlock lock(fMutex); + head = fHead; + tail = fTail; + + // The head and tail indices increment without bound, wrapping with overflow, + // so we need to mod them down to the actual bounds of the allocation to determine + // which blocks are available. + size_t modHead = head & (fTotalSize - 1); + size_t modTail = tail & (fTotalSize - 1); + + bool full = (head != tail && modHead == modTail); + + if (full) { + return fTotalSize; + } + + // case 1: free space lies at the beginning and/or the end of the buffer + if (modHead >= modTail) { + // check for room at the end + if (fTotalSize - modHead < size) { + // no room at the end, check the beginning + if (modTail < size) { + // no room at the beginning + return fTotalSize; + } + // we are going to allocate from the beginning, adjust head to '0' position + head += fTotalSize - modHead; + modHead = 0; + } + // case 2: free space lies in the middle of the buffer, check for room there + } else if (modTail - modHead < size) { + // no room in the middle + return fTotalSize; + } + + fHead = GrAlignTo(head + size, fAlignment); + return modHead; +} + +GrRingBuffer::Slice GrRingBuffer::suballocate(size_t size) { + size_t offset = this->getAllocationOffset(size); + if (offset < fTotalSize) { + return { fBuffer, offset }; + } + + // Try to grow allocation (old allocation will age out). + fTotalSize *= 2; + fBuffer = this->createBuffer(fTotalSize); + SkASSERT(fBuffer); + { + SkAutoSpinlock lock(fMutex); + fHead = 0; + fTail = 0; + fGenID++; + } + offset = this->getAllocationOffset(size); + SkASSERT(offset < fTotalSize); + return { fBuffer, offset }; +} + +// used when current command buffer/command list is submitted +GrRingBuffer::SubmitData GrRingBuffer::startSubmit() { + SubmitData submitData; + SkAutoSpinlock lock(fMutex); + submitData.fBuffer = fBuffer; + submitData.fLastHead = fHead; + submitData.fGenID = fGenID; + return submitData; +} + +// used when current command buffer/command list is completed +void GrRingBuffer::finishSubmit(const GrRingBuffer::SubmitData& submitData) { + SkAutoSpinlock lock(fMutex); + if (submitData.fGenID == fGenID) { + fTail = submitData.fLastHead; + } +} diff --git a/chromium/third_party/skia/src/gpu/GrRingBuffer.h b/chromium/third_party/skia/src/gpu/GrRingBuffer.h new file mode 100644 index 00000000000..2498c0d9cfb --- /dev/null +++ b/chromium/third_party/skia/src/gpu/GrRingBuffer.h @@ -0,0 +1,72 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrRingBuffer_DEFINED +#define GrRingBuffer_DEFINED + +#include "src/gpu/GrGpuBuffer.h" + +#include "include/private/SkSpinlock.h" + +/** + * A wrapper for a GPU buffer that allocates slices in a continuous ring. + * + * It's assumed that suballocate and startSubmit are always called in the same thread, + * and that finishSubmit could be called in a separate thread. + */ +class GrRingBuffer : public SkRefCnt { +public: + GrRingBuffer(sk_sp<GrGpuBuffer> buffer, size_t size, size_t alignment) + : fBuffer(std::move(buffer)) + , fTotalSize(size) + , fAlignment(alignment) + , fHead(0) + , fTail(0) + , fGenID(0) { + // We increment fHead and fTail without bound and let overflow handle any wrapping. + // Because of this, size needs to be a power of two. + SkASSERT(SkIsPow2(size)); + } + virtual ~GrRingBuffer() = default; + + struct Slice { + sk_sp<GrGpuBuffer> fBuffer; + size_t fOffset; + }; + + Slice suballocate(size_t size); + + class SubmitData { + public: + GrGpuBuffer* buffer() const { return fBuffer.get(); } + private: + friend class GrRingBuffer; + sk_sp<GrGpuBuffer> fBuffer; + size_t fLastHead; + size_t fGenID; + }; + // Backends should call startSubmit() at submit time, and finishSubmit() when the + // command buffer/list finishes. + SubmitData startSubmit(); + void finishSubmit(const SubmitData&); + + size_t size() const { return fTotalSize; } + +private: + virtual sk_sp<GrGpuBuffer> createBuffer(size_t size) = 0; + size_t getAllocationOffset(size_t size); + + sk_sp<GrGpuBuffer> fBuffer; + size_t fTotalSize; + size_t fAlignment; + size_t fHead SK_GUARDED_BY(fMutex); // where we start allocating + size_t fTail SK_GUARDED_BY(fMutex); // where we start deallocating + uint64_t fGenID SK_GUARDED_BY(fMutex); // incremented when createBuffer is called + SkSpinlock fMutex; +}; + +#endif diff --git a/chromium/third_party/skia/src/gpu/GrSWMaskHelper.h b/chromium/third_party/skia/src/gpu/GrSWMaskHelper.h index 5ca23f70d61..5982bcffb35 100644 --- a/chromium/third_party/skia/src/gpu/GrSWMaskHelper.h +++ b/chromium/third_party/skia/src/gpu/GrSWMaskHelper.h @@ -15,6 +15,7 @@ #include "src/core/SkAutoPixmapStorage.h" #include "src/core/SkDraw.h" #include "src/core/SkRasterClip.h" +#include "src/gpu/GrSurfaceProxyView.h" class GrShape; class GrStyledShape; diff --git a/chromium/third_party/skia/src/gpu/GrScissorState.h b/chromium/third_party/skia/src/gpu/GrScissorState.h index dac735b023d..cc1cea25781 100644 --- a/chromium/third_party/skia/src/gpu/GrScissorState.h +++ b/chromium/third_party/skia/src/gpu/GrScissorState.h @@ -10,33 +10,74 @@ #include "include/core/SkRect.h" +/** + * The scissor state is stored as the scissor rectangle and the backing store bounds of the render + * target that the scissor will apply to. If the render target is approximate fit and the padded + * content should not be modified, the clip should apply the render target context's logical bounds + * as part of the scissor (e.g. when stenciling). This puts the onus on the render target context + * to intentionally discard the scissor at its logical bounds when drawing into the padded content + * is acceptable (e.g. color-only updates). + */ class GrScissorState { public: - GrScissorState() : fEnabled(false) {} - GrScissorState(const SkIRect& rect) : fEnabled(true), fRect(rect) {} - void setDisabled() { fEnabled = false; } - void set(const SkIRect& rect) { fRect = rect; fEnabled = true; } + // The disabled scissor state for a render target of the given size. + explicit GrScissorState(const SkISize& rtDims) + : fRTSize(rtDims) + , fRect(SkIRect::MakeSize(rtDims)) {} + + void setDisabled() { fRect = SkIRect::MakeSize(fRTSize); } + bool set(const SkIRect& rect) { + this->setDisabled(); + return this->intersect(rect); + } + bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& rect) { - if (!fEnabled) { - this->set(rect); + if (!fRect.intersect(rect)) { + fRect.setEmpty(); + return false; + } else { return true; } - return fRect.intersect(rect); } + + // If the scissor was configured for the backing store dimensions and it's acceptable to + // draw outside the logical dimensions of the target, this will discard the scissor test if + // the test wouldn't modify the logical dimensions. + bool relaxTest(const SkISize& logicalDimensions) { + SkASSERT(logicalDimensions.fWidth <= fRTSize.fWidth && + logicalDimensions.fHeight <= fRTSize.fHeight); + if (fRect.fLeft == 0 && fRect.fTop == 0 && fRect.fRight >= logicalDimensions.fWidth && + fRect.fBottom >= logicalDimensions.fHeight) { + this->setDisabled(); + return true; + } else { + return false; + } + } + bool operator==(const GrScissorState& other) const { - return fEnabled == other.fEnabled && - (false == fEnabled || fRect == other.fRect); + return fRTSize == other.fRTSize && fRect == other.fRect; } bool operator!=(const GrScissorState& other) const { return !(*this == other); } - bool enabled() const { return fEnabled; } + bool enabled() const { + SkASSERT(fRect.isEmpty() || SkIRect::MakeSize(fRTSize).contains(fRect)); + // This is equivalent to a strict contains check on SkIRect::MakeSize(rtSize) w/o creating + // the render target bounding rectangle. + return fRect.fLeft > 0 || fRect.fTop > 0 || + fRect.fRight < fRTSize.fWidth || fRect.fBottom < fRTSize.fHeight; + } + + // Will always be equal to or contained in the rt bounds, or empty if scissor rectangles were + // added that did not intersect with the render target or prior scissor. const SkIRect& rect() const { - SkASSERT(fEnabled); + SkASSERT(fRect.isEmpty() || SkIRect::MakeSize(fRTSize).contains(fRect)); return fRect; } private: - bool fEnabled; + // The scissor is considered enabled if the rectangle does not cover the render target + SkISize fRTSize; SkIRect fRect; }; diff --git a/chromium/third_party/skia/src/gpu/GrShaderCaps.cpp b/chromium/third_party/skia/src/gpu/GrShaderCaps.cpp index faafc94c79b..a629085a099 100644 --- a/chromium/third_party/skia/src/gpu/GrShaderCaps.cpp +++ b/chromium/third_party/skia/src/gpu/GrShaderCaps.cpp @@ -49,7 +49,6 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) { fPreferFlatInterpolation = false; fNoPerspectiveInterpolationSupport = false; fSampleMaskSupport = false; - fTessellationSupport = false; fExternalTextureSupport = false; fVertexIDSupport = false; fFPManipulationSupport = false; @@ -61,6 +60,7 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) { // GL_ARB_texture_swizzle). fTextureSwizzleAppliedInShader = true; fBuiltinFMASupport = false; + fCanUseDoLoops = true; fVersionDeclString = nullptr; fShaderDerivativeExtensionString = nullptr; @@ -76,6 +76,7 @@ GrShaderCaps::GrShaderCaps(const GrContextOptions& options) { fFBFetchColorName = nullptr; fFBFetchExtensionString = nullptr; fMaxFragmentSamplers = 0; + fMaxTessellationSegments = 0; fAdvBlendEqInteraction = kNotSupported_AdvBlendEqInteraction; } @@ -132,7 +133,6 @@ void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const { writer->appendBool("Prefer flat interpolation", fPreferFlatInterpolation); writer->appendBool("No perspective interpolation support", fNoPerspectiveInterpolationSupport); writer->appendBool("Sample mask support", fSampleMaskSupport); - writer->appendBool("Tessellation Support", fTessellationSupport); writer->appendBool("External texture support", fExternalTextureSupport); writer->appendBool("sk_VertexID support", fVertexIDSupport); writer->appendBool("Floating point manipulation support", fFPManipulationSupport); @@ -142,8 +142,10 @@ void GrShaderCaps::dumpJSON(SkJSONWriter* writer) const { writer->appendBool("Color space math needs float", fColorSpaceMathNeedsFloat); writer->appendBool("Texture swizzle applied in shader", fTextureSwizzleAppliedInShader); writer->appendBool("Builtin fma() support", fBuiltinFMASupport); + writer->appendBool("Can use do-while loops", fCanUseDoLoops); writer->appendS32("Max FS Samplers", fMaxFragmentSamplers); + writer->appendS32("Max Tessellation Segments", fMaxTessellationSegments); writer->appendString("Advanced blend equation interaction", kAdvBlendEqInteractionStr[fAdvBlendEqInteraction]); @@ -183,7 +185,7 @@ void GrShaderCaps::applyOptionsOverrides(const GrContextOptions& options) { fGeometryShaderSupport = false; } if (options.fSuppressTessellationShaders) { - fTessellationSupport = false; + fMaxTessellationSegments = 0; } #endif } diff --git a/chromium/third_party/skia/src/gpu/GrShaderCaps.h b/chromium/third_party/skia/src/gpu/GrShaderCaps.h index b6a3cc023c1..3b3e1bf9b5f 100644 --- a/chromium/third_party/skia/src/gpu/GrShaderCaps.h +++ b/chromium/third_party/skia/src/gpu/GrShaderCaps.h @@ -72,8 +72,6 @@ public: bool sampleMaskSupport() const { return fSampleMaskSupport; } - bool tessellationSupport() const { return fTessellationSupport; } - bool externalTextureSupport() const { return fExternalTextureSupport; } bool vertexIDSupport() const { return fVertexIDSupport; } @@ -175,6 +173,10 @@ public: // http://skbug.com/8921 bool canOnlyUseSampleMaskWithStencil() const { return fCanOnlyUseSampleMaskWithStencil; } + // ANGLE disallows do loops altogether, and we're seeing crashes on Tegra3 with do loops in at + // least some cases. + bool canUseDoLoops() const { return fCanUseDoLoops; } + // Returns the string of an extension that must be enabled in the shader to support // derivatives. If nullptr is returned then no extension needs to be enabled. Before calling // this function, the caller should check that shaderDerivativeSupport exists. @@ -244,6 +246,11 @@ public: int maxFragmentSamplers() const { return fMaxFragmentSamplers; } + // Maximum number of segments a tessellation edge can be divided into. + int maxTessellationSegments() const { return fMaxTessellationSegments; } + + bool tessellationSupport() const { return SkToBool(fMaxTessellationSegments);} + bool textureSwizzleAppliedInShader() const { return fTextureSwizzleAppliedInShader; } GrGLSLGeneration generation() const { return fGLSLGeneration; } @@ -267,7 +274,6 @@ private: bool fPreferFlatInterpolation : 1; bool fNoPerspectiveInterpolationSupport : 1; bool fSampleMaskSupport : 1; - bool fTessellationSupport : 1; bool fExternalTextureSupport : 1; bool fVertexIDSupport : 1; bool fFPManipulationSupport : 1; @@ -301,6 +307,7 @@ private: bool fNoDefaultPrecisionForExternalSamplers : 1; bool fCanOnlyUseSampleMaskWithStencil : 1; bool fColorSpaceMathNeedsFloat : 1; + bool fCanUseDoLoops : 1; const char* fVersionDeclString; @@ -319,6 +326,7 @@ private: const char* fFBFetchExtensionString; int fMaxFragmentSamplers; + int fMaxTessellationSegments; AdvBlendEqInteraction fAdvBlendEqInteraction; diff --git a/chromium/third_party/skia/src/gpu/GrSoftwarePathRenderer.cpp b/chromium/third_party/skia/src/gpu/GrSoftwarePathRenderer.cpp index 6646caeadb9..95ab059800f 100644 --- a/chromium/third_party/skia/src/gpu/GrSoftwarePathRenderer.cpp +++ b/chromium/third_party/skia/src/gpu/GrSoftwarePathRenderer.cpp @@ -68,15 +68,16 @@ static bool get_unclipped_shape_dev_bounds(const GrStyledShape& shape, const SkM // Gets the shape bounds, the clip bounds, and the intersection (if any). Returns false if there // is no intersection. bool GrSoftwarePathRenderer::GetShapeAndClipBounds(GrRenderTargetContext* renderTargetContext, - const GrClip& clip, + const GrClip* clip, const GrStyledShape& shape, const SkMatrix& matrix, SkIRect* unclippedDevShapeBounds, SkIRect* clippedDevShapeBounds, SkIRect* devClipBounds) { // compute bounds as intersection of rt size, clip, and path - *devClipBounds = clip.getConservativeBounds(renderTargetContext->width(), - renderTargetContext->height()); + *devClipBounds = clip ? clip->getConservativeBounds() + : SkIRect::MakeWH(renderTargetContext->width(), + renderTargetContext->height()); if (!get_unclipped_shape_dev_bounds(shape, matrix, unclippedDevShapeBounds)) { *unclippedDevShapeBounds = SkIRect::MakeEmpty(); @@ -95,7 +96,7 @@ bool GrSoftwarePathRenderer::GetShapeAndClipBounds(GrRenderTargetContext* render void GrSoftwarePathRenderer::DrawNonAARect(GrRenderTargetContext* renderTargetContext, GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, - const GrClip& clip, + const GrClip* clip, const SkMatrix& viewMatrix, const SkRect& rect, const SkMatrix& localMatrix) { @@ -106,7 +107,7 @@ void GrSoftwarePathRenderer::DrawNonAARect(GrRenderTargetContext* renderTargetCo void GrSoftwarePathRenderer::DrawAroundInvPath(GrRenderTargetContext* renderTargetContext, GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, - const GrClip& clip, + const GrClip* clip, const SkMatrix& viewMatrix, const SkIRect& devClipBounds, const SkIRect& devPathBounds) { @@ -147,7 +148,7 @@ void GrSoftwarePathRenderer::DrawToTargetWithShapeMask( GrRenderTargetContext* renderTargetContext, GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, - const GrClip& clip, + const GrClip* clip, const SkMatrix& viewMatrix, const SkIPoint& textureOriginInDeviceSpace, const SkIRect& deviceSpaceRectToDraw) { @@ -161,7 +162,7 @@ void GrSoftwarePathRenderer::DrawToTargetWithShapeMask( // We use device coords to compute the texture coordinates. We take the device coords and apply // a translation so that the top-left of the device bounds maps to 0,0, and then a scaling // matrix to normalized coords. - SkMatrix maskMatrix = SkMatrix::MakeTrans(SkIntToScalar(-textureOriginInDeviceSpace.fX), + SkMatrix maskMatrix = SkMatrix::Translate(SkIntToScalar(-textureOriginInDeviceSpace.fX), SkIntToScalar(-textureOriginInDeviceSpace.fY)); maskMatrix.preConcat(viewMatrix); @@ -241,13 +242,13 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) { args.fShape->hasUnstyledKey() && (GrAAType::kCoverage == args.fAAType); if (!GetShapeAndClipBounds(args.fRenderTargetContext, - *args.fClip, *args.fShape, + args.fClip, *args.fShape, *args.fViewMatrix, &unclippedDevShapeBounds, &clippedDevShapeBounds, &devClipBounds)) { if (inverseFilled) { DrawAroundInvPath(args.fRenderTargetContext, std::move(args.fPaint), - *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, + *args.fUserStencilSettings, args.fClip, *args.fViewMatrix, devClipBounds, unclippedDevShapeBounds); } return true; @@ -382,11 +383,11 @@ bool GrSoftwarePathRenderer::onDrawPath(const DrawPathArgs& args) { SkASSERT(view); if (inverseFilled) { DrawAroundInvPath(args.fRenderTargetContext, GrPaint::Clone(args.fPaint), - *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, devClipBounds, + *args.fUserStencilSettings, args.fClip, *args.fViewMatrix, devClipBounds, unclippedDevShapeBounds); } DrawToTargetWithShapeMask(std::move(view), args.fRenderTargetContext, std::move(args.fPaint), - *args.fUserStencilSettings, *args.fClip, *args.fViewMatrix, + *args.fUserStencilSettings, args.fClip, *args.fViewMatrix, SkIPoint{boundsForMask->fLeft, boundsForMask->fTop}, *boundsForMask); return true; diff --git a/chromium/third_party/skia/src/gpu/GrSoftwarePathRenderer.h b/chromium/third_party/skia/src/gpu/GrSoftwarePathRenderer.h index d24d48adbe4..7b931662240 100644 --- a/chromium/third_party/skia/src/gpu/GrSoftwarePathRenderer.h +++ b/chromium/third_party/skia/src/gpu/GrSoftwarePathRenderer.h @@ -27,7 +27,7 @@ public: } static bool GetShapeAndClipBounds(GrRenderTargetContext*, - const GrClip& clip, + const GrClip* clip, const GrStyledShape& shape, const SkMatrix& matrix, SkIRect* unclippedDevShapeBounds, @@ -38,14 +38,14 @@ private: static void DrawNonAARect(GrRenderTargetContext* renderTargetContext, GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, - const GrClip& clip, + const GrClip* clip, const SkMatrix& viewMatrix, const SkRect& rect, const SkMatrix& localMatrix); static void DrawAroundInvPath(GrRenderTargetContext* renderTargetContext, GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, - const GrClip& clip, + const GrClip* clip, const SkMatrix& viewMatrix, const SkIRect& devClipBounds, const SkIRect& devPathBounds); @@ -57,7 +57,7 @@ private: GrRenderTargetContext* renderTargetContext, GrPaint&& paint, const GrUserStencilSettings& userStencilSettings, - const GrClip& clip, + const GrClip* clip, const SkMatrix& viewMatrix, const SkIPoint& textureOriginInDeviceSpace, const SkIRect& deviceSpaceRectToDraw); diff --git a/chromium/third_party/skia/src/gpu/GrStencilClip.h b/chromium/third_party/skia/src/gpu/GrStencilClip.h index 854ba1ce510..4ab8a82e080 100644 --- a/chromium/third_party/skia/src/gpu/GrStencilClip.h +++ b/chromium/third_party/skia/src/gpu/GrStencilClip.h @@ -16,12 +16,14 @@ */ class GrStencilClip final : public GrHardClip { public: - GrStencilClip(uint32_t stencilStackID = SK_InvalidGenID) : fStencilStackID(stencilStackID) {} + explicit GrStencilClip(const SkISize& rtDims, uint32_t stencilStackID = SK_InvalidGenID) + : fFixedClip(rtDims) + , fStencilStackID(stencilStackID) {} - explicit GrStencilClip(const SkIRect& scissorRect, uint32_t stencilStackID = SK_InvalidGenID) - : fFixedClip(scissorRect) - , fStencilStackID(stencilStackID) { - } + GrStencilClip(const SkISize& rtDims, const SkIRect& scissorRect, + uint32_t stencilStackID = SK_InvalidGenID) + : fFixedClip(rtDims, scissorRect) + , fStencilStackID(stencilStackID) {} const GrFixedClip& fixedClip() const { return fFixedClip; } GrFixedClip& fixedClip() { return fFixedClip; } @@ -33,14 +35,14 @@ public: bool quickContains(const SkRect& rect) const override { return !this->hasStencilClip() && fFixedClip.quickContains(rect); } - SkIRect getConservativeBounds(int width, int height) const override { - return fFixedClip.getConservativeBounds(width, height); + SkIRect getConservativeBounds() const override { + return fFixedClip.getConservativeBounds(); } - bool isRRect(const SkRect& rtBounds, SkRRect* rr, GrAA* aa) const override { - return !this->hasStencilClip() && fFixedClip.isRRect(rtBounds, rr, aa); + bool isRRect(SkRRect* rr, GrAA* aa) const override { + return !this->hasStencilClip() && fFixedClip.isRRect(rr, aa); } - bool apply(int rtWidth, int rtHeight, GrAppliedHardClip* out, SkRect* bounds) const override { - if (!fFixedClip.apply(rtWidth, rtHeight, out, bounds)) { + bool apply(GrAppliedHardClip* out, SkRect* bounds) const override { + if (!fFixedClip.apply(out, bounds)) { return false; } if (this->hasStencilClip()) { diff --git a/chromium/third_party/skia/src/gpu/GrStencilMaskHelper.cpp b/chromium/third_party/skia/src/gpu/GrStencilMaskHelper.cpp index f9870f41af1..f261e265e92 100644 --- a/chromium/third_party/skia/src/gpu/GrStencilMaskHelper.cpp +++ b/chromium/third_party/skia/src/gpu/GrStencilMaskHelper.cpp @@ -278,7 +278,7 @@ static void draw_stencil_rect(GrRenderTargetContext* rtc, const GrHardClip& clip const SkRect& rect, GrAA aa) { GrPaint paint; paint.setXPFactory(GrDisableColorXPFactory::Get()); - rtc->priv().stencilRect(clip, ss, std::move(paint), aa, matrix, rect); + rtc->priv().stencilRect(&clip, ss, std::move(paint), aa, matrix, rect); } static void draw_path(GrRecordingContext* context, GrRenderTargetContext* rtc, @@ -334,7 +334,8 @@ bool GrStencilMaskHelper::init(const SkIRect& bounds, uint32_t genID, } fClip.setStencilClip(genID); - fClip.fixedClip().setScissor(bounds); + // Should have caught bounds not intersecting the render target much earlier in clip application + SkAssertResult(fClip.fixedClip().setScissor(bounds)); if (!windowRects.empty()) { fClip.fixedClip().setWindowRectangles( windowRects, GrWindowRectsState::Mode::kExclusive); @@ -462,7 +463,15 @@ bool GrStencilMaskHelper::drawShape(const GrShape& shape, } void GrStencilMaskHelper::clear(bool insideStencil) { - fRTC->priv().clearStencilClip(fClip.fixedClip(), insideStencil); + if (fClip.fixedClip().hasWindowRectangles()) { + // Use a draw to benefit from window rectangles when resetting the stencil buffer; for + // large buffers with MSAA this can be significant. + draw_stencil_rect(fRTC, fClip.fixedClip(), + GrStencilSettings::SetClipBitSettings(insideStencil), SkMatrix::I(), + SkRect::Make(fClip.fixedClip().scissorRect()), GrAA::kNo); + } else { + fRTC->priv().clearStencilClip(fClip.fixedClip().scissorRect(), insideStencil); + } } void GrStencilMaskHelper::finish() { diff --git a/chromium/third_party/skia/src/gpu/GrStencilMaskHelper.h b/chromium/third_party/skia/src/gpu/GrStencilMaskHelper.h index 547bee2d934..f6cd2b90aa2 100644 --- a/chromium/third_party/skia/src/gpu/GrStencilMaskHelper.h +++ b/chromium/third_party/skia/src/gpu/GrStencilMaskHelper.h @@ -39,7 +39,8 @@ public: // of which must outlive the helper. GrStencilMaskHelper(GrRecordingContext* context, GrRenderTargetContext* rtc) : fContext(context) - , fRTC(rtc) {} + , fRTC(rtc) + , fClip(rtc->dimensions()) {} // Returns true if the stencil mask must be redrawn bool init(const SkIRect& maskBounds, uint32_t genID, diff --git a/chromium/third_party/skia/src/gpu/GrSurface.cpp b/chromium/third_party/skia/src/gpu/GrSurface.cpp index 03f46166116..1aa4444482f 100644 --- a/chromium/third_party/skia/src/gpu/GrSurface.cpp +++ b/chromium/third_party/skia/src/gpu/GrSurface.cpp @@ -7,6 +7,7 @@ #include "include/gpu/GrContext.h" #include "src/core/SkCompressedDataUtils.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrRenderTarget.h" #include "src/gpu/GrResourceProvider.h" #include "src/gpu/GrSurface.h" @@ -34,7 +35,7 @@ size_t GrSurface::ComputeSize(const GrCaps& caps, dimensions = GrResourceProvider::MakeApprox(dimensions); } - SkImage::CompressionType compressionType = caps.compressionType(format); + SkImage::CompressionType compressionType = GrBackendFormatToCompressionType(format); if (compressionType != SkImage::CompressionType::kNone) { colorSize = SkCompressedFormatDataSize(compressionType, dimensions, mipMapped == GrMipMapped::kYes); diff --git a/chromium/third_party/skia/src/gpu/GrSurfaceContext.cpp b/chromium/third_party/skia/src/gpu/GrSurfaceContext.cpp index 4e0e5c4b6ba..b7c667f04b9 100644 --- a/chromium/third_party/skia/src/gpu/GrSurfaceContext.cpp +++ b/chromium/third_party/skia/src/gpu/GrSurfaceContext.cpp @@ -10,7 +10,6 @@ #include "include/private/GrRecordingContext.h" #include "src/core/SkAutoPixmapStorage.h" #include "src/gpu/GrAuditTrail.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrDataUtils.h" #include "src/gpu/GrDrawingManager.h" @@ -24,8 +23,7 @@ #include "src/gpu/SkGr.h" #include "src/gpu/effects/GrBicubicEffect.h" -#define ASSERT_SINGLE_OWNER \ - SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(this->singleOwner());) +#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(this->singleOwner()) #define RETURN_FALSE_IF_ABANDONED if (this->fContext->priv().abandoned()) { return false; } std::unique_ptr<GrSurfaceContext> GrSurfaceContext::Make(GrRecordingContext* context, @@ -240,7 +238,7 @@ bool GrSurfaceContext::readPixels(const GrImageInfo& origDstInfo, void* dst, siz paint.addColorFragmentProcessor(std::move(fp)); tempCtx->asRenderTargetContext()->fillRectToRect( - GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), + nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::MakeWH(dstInfo.width(), dstInfo.height()), SkRect::MakeXYWH(pt.fX, pt.fY, dstInfo.width(), dstInfo.height())); @@ -275,7 +273,7 @@ bool GrSurfaceContext::readPixels(const GrImageInfo& origDstInfo, void* dst, siz } direct->priv().flushSurface(srcProxy); - + direct->submit(); if (!direct->priv().getGpu()->readPixels(srcSurface, pt.fX, pt.fY, dstInfo.width(), dstInfo.height(), this->colorInfo().colorType(), supportedRead.fColorType, readDst, readRB)) { @@ -426,7 +424,7 @@ bool GrSurfaceContext::writePixels(const GrImageInfo& origSrcInfo, const void* s paint.setPorterDuffXPFactory(SkBlendMode::kSrc); paint.addColorFragmentProcessor(std::move(fp)); this->asRenderTargetContext()->fillRectToRect( - GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), + nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::MakeXYWH(pt.fX, pt.fY, srcInfo.width(), srcInfo.height()), SkRect::MakeWH(srcInfo.width(), srcInfo.height())); } else { @@ -502,14 +500,11 @@ bool GrSurfaceContext::copy(GrSurfaceProxy* src, const SkIRect& srcRect, const S } std::unique_ptr<GrRenderTargetContext> GrSurfaceContext::rescale( - const SkImageInfo& info, - const SkIRect& srcRect, + const GrImageInfo& info, + GrSurfaceOrigin origin, + SkIRect srcRect, SkSurface::RescaleGamma rescaleGamma, SkFilterQuality rescaleQuality) { - auto direct = fContext->priv().asDirectContext(); - if (!direct) { - return nullptr; - } auto rtProxy = this->asRenderTargetProxy(); if (rtProxy && rtProxy->wrapsVkSecondaryCB()) { return nullptr; @@ -524,12 +519,7 @@ std::unique_ptr<GrRenderTargetContext> GrSurfaceContext::rescale( return nullptr; } - int srcW = srcRect.width(); - int srcH = srcRect.height(); - int srcX = srcRect.fLeft; - int srcY = srcRect.fTop; GrSurfaceProxyView texView = this->readSurfaceView(); - SkCanvas::SrcRectConstraint constraint = SkCanvas::kStrict_SrcRectConstraint; SkAlphaType srcAlphaType = this->colorInfo().alphaType(); if (!texView.asTextureProxy()) { texView = GrSurfaceProxyView::Copy(fContext, std::move(texView), GrMipMapped::kNo, srcRect, @@ -538,25 +528,8 @@ std::unique_ptr<GrRenderTargetContext> GrSurfaceContext::rescale( return nullptr; } SkASSERT(texView.asTextureProxy()); - srcX = 0; - srcY = 0; - constraint = SkCanvas::kFast_SrcRectConstraint; - } - - float sx = (float)info.width() / srcW; - float sy = (float)info.height() / srcH; - - // How many bilerp/bicubic steps to do in X and Y. + means upscaling, - means downscaling. - int stepsX; - int stepsY; - if (rescaleQuality > kNone_SkFilterQuality) { - stepsX = static_cast<int>((sx > 1.f) ? ceil(log2f(sx)) : floor(log2f(sx))); - stepsY = static_cast<int>((sy > 1.f) ? ceil(log2f(sy)) : floor(log2f(sy))); - } else { - stepsX = sx != 1.f; - stepsY = sy != 1.f; + srcRect = SkIRect::MakeSize(srcRect.size()); } - SkASSERT(stepsX || stepsY); // Within a rescaling pass A is the input (if not null) and B is the output. At the end of the // pass B is moved to A. If 'this' is the input on the first pass then tempA is null. @@ -572,100 +545,95 @@ std::unique_ptr<GrRenderTargetContext> GrSurfaceContext::rescale( kPremul_SkAlphaType); // We'll fall back to kRGBA_8888 if half float not supported. auto linearRTC = GrRenderTargetContext::MakeWithFallback( - fContext, GrColorType::kRGBA_F16, cs, SkBackingFit::kExact, {srcW, srcH}, 1, - GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin); + fContext, GrColorType::kRGBA_F16, cs, SkBackingFit::kApprox, srcRect.size(), 1, + GrMipMapped::kNo, GrProtected::kNo, origin); if (!linearRTC) { return nullptr; } - linearRTC->drawTexture(GrNoClip(), std::move(texView), srcAlphaType, + // 1-to-1 draw can always be kFast. + linearRTC->drawTexture(nullptr, std::move(texView), srcAlphaType, GrSamplerState::Filter::kNearest, SkBlendMode::kSrc, - SK_PMColor4fWHITE, SkRect::Make(srcRect), SkRect::MakeWH(srcW, srcH), - GrAA::kNo, GrQuadAAFlags::kNone, constraint, SkMatrix::I(), - std::move(xform)); + SK_PMColor4fWHITE, SkRect::Make(srcRect), + SkRect::Make(srcRect.size()), GrAA::kNo, GrQuadAAFlags::kNone, + SkCanvas::kFast_SrcRectConstraint, SkMatrix::I(), std::move(xform)); texView = linearRTC->readSurfaceView(); SkASSERT(texView.asTextureProxy()); tempA = std::move(linearRTC); - srcX = 0; - srcY = 0; - constraint = SkCanvas::kFast_SrcRectConstraint; - } - while (stepsX || stepsY) { - int nextW = info.width(); - int nextH = info.height(); - if (stepsX < 0) { - nextW = info.width() << (-stepsX - 1); - stepsX++; - } else if (stepsX != 0) { - if (stepsX > 1) { - nextW = srcW * 2; + srcRect = SkIRect::MakeSize(srcRect.size()); + } + + while (srcRect.size() != info.dimensions()) { + SkISize nextDims = info.dimensions(); + if (rescaleQuality != kNone_SkFilterQuality) { + if (srcRect.width() > info.width()) { + nextDims.fWidth = std::max((srcRect.width() + 1)/2, info.width()); + } else if (srcRect.width() < info.width()) { + nextDims.fWidth = std::min(srcRect.width()*2, info.width()); } - --stepsX; - } - if (stepsY < 0) { - nextH = info.height() << (-stepsY - 1); - stepsY++; - } else if (stepsY != 0) { - if (stepsY > 1) { - nextH = srcH * 2; + if (srcRect.height() > info.height()) { + nextDims.fHeight = std::max((srcRect.height() + 1)/2, info.height()); + } else if (srcRect.height() < info.height()) { + nextDims.fHeight = std::min(srcRect.height()*2, info.height()); } - --stepsY; } auto input = tempA ? tempA.get() : this; GrColorType colorType = input->colorInfo().colorType(); auto cs = input->colorInfo().refColorSpace(); sk_sp<GrColorSpaceXform> xform; auto prevAlphaType = input->colorInfo().alphaType(); - if (!stepsX && !stepsY) { + if (nextDims == info.dimensions()) { // Might as well fold conversion to final info in the last step. cs = info.refColorSpace(); - colorType = SkColorTypeToGrColorType(info.colorType()); xform = GrColorSpaceXform::Make(input->colorInfo().colorSpace(), input->colorInfo().alphaType(), cs.get(), info.alphaType()); } - tempB = GrRenderTargetContext::MakeWithFallback( - fContext, colorType, std::move(cs), SkBackingFit::kExact, {nextW, nextH}, 1, - GrMipMapped::kNo, GrProtected::kNo, kTopLeft_GrSurfaceOrigin); + tempB = GrRenderTargetContext::MakeWithFallback(fContext, colorType, std::move(cs), + SkBackingFit::kApprox, nextDims, 1, + GrMipMapped::kNo, GrProtected::kNo, origin); if (!tempB) { return nullptr; } - auto dstRect = SkRect::MakeWH(nextW, nextH); + auto dstRect = SkRect::Make(nextDims); if (rescaleQuality == kHigh_SkFilterQuality) { SkMatrix matrix; - matrix.setScaleTranslate((float)srcW / nextW, (float)srcH / nextH, srcX, srcY); + matrix.setScaleTranslate((float)srcRect.width()/nextDims.width(), + (float)srcRect.height()/nextDims.height(), + srcRect.x(), + srcRect.y()); std::unique_ptr<GrFragmentProcessor> fp; auto dir = GrBicubicEffect::Direction::kXY; - if (nextW == srcW) { + if (nextDims.width() == srcRect.width()) { dir = GrBicubicEffect::Direction::kY; - } else if (nextH == srcH) { + } else if (nextDims.height() == srcRect.height()) { dir = GrBicubicEffect::Direction::kX; } static constexpr GrSamplerState::WrapMode kWM = GrSamplerState::WrapMode::kClamp; - auto subset = SkRect::MakeXYWH(srcX, srcY, srcW, srcH); fp = GrBicubicEffect::MakeSubset(std::move(texView), prevAlphaType, matrix, kWM, kWM, - subset, dir, *this->caps()); + SkRect::Make(srcRect), dir, *this->caps()); if (xform) { fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(xform)); } GrPaint paint; paint.addColorFragmentProcessor(std::move(fp)); paint.setPorterDuffXPFactory(SkBlendMode::kSrc); - tempB->fillRectToRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect, + tempB->fillRectToRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), dstRect, dstRect); } else { auto filter = rescaleQuality == kNone_SkFilterQuality ? GrSamplerState::Filter::kNearest : GrSamplerState::Filter::kBilerp; - auto srcSubset = SkRect::MakeXYWH(srcX, srcY, srcW, srcH); - tempB->drawTexture(GrNoClip(), std::move(texView), srcAlphaType, filter, - SkBlendMode::kSrc, SK_PMColor4fWHITE, srcSubset, dstRect, GrAA::kNo, + // Minimizing draw with integer coord src and dev rects can always be kFast. + auto constraint = SkCanvas::SrcRectConstraint::kStrict_SrcRectConstraint; + if (nextDims.width() <= srcRect.width() && nextDims.height() <= srcRect.height()) { + constraint = SkCanvas::SrcRectConstraint::kFast_SrcRectConstraint; + } + tempB->drawTexture(nullptr, std::move(texView), srcAlphaType, filter, SkBlendMode::kSrc, + SK_PMColor4fWHITE, SkRect::Make(srcRect), dstRect, GrAA::kNo, GrQuadAAFlags::kNone, constraint, SkMatrix::I(), std::move(xform)); } texView = tempB->readSurfaceView(); tempA = std::move(tempB); - srcX = srcY = 0; - srcW = nextW; - srcH = nextH; - constraint = SkCanvas::kFast_SrcRectConstraint; + srcRect = SkIRect::MakeSize(nextDims); } SkASSERT(tempA); return tempA; @@ -744,4 +712,3 @@ void GrSurfaceContext::validate() const { this->onValidate(); } #endif - diff --git a/chromium/third_party/skia/src/gpu/GrSurfaceContext.h b/chromium/third_party/skia/src/gpu/GrSurfaceContext.h index 028cc52a94d..8e3394ce1a0 100644 --- a/chromium/third_party/skia/src/gpu/GrSurfaceContext.h +++ b/chromium/third_party/skia/src/gpu/GrSurfaceContext.h @@ -114,6 +114,19 @@ public: virtual GrRenderTargetContext* asRenderTargetContext() { return nullptr; } + /** + * Rescales the contents of srcRect. The gamma in which the rescaling occurs is controlled by + * RescaleGamma. It is always in the original gamut. The result is converted to the color type + * and color space of info after rescaling. Note: this currently requires that the info have a + * different size than srcRect. Though, it could be relaxed to allow non-scaling color + * conversions. + */ + std::unique_ptr<GrRenderTargetContext> rescale(const GrImageInfo& info, + GrSurfaceOrigin, + SkIRect srcRect, + SkSurface::RescaleGamma, + SkFilterQuality); + GrAuditTrail* auditTrail(); // Provides access to functions that aren't part of the public API. @@ -144,11 +157,6 @@ protected: GrSurfaceProxyView fReadView; - // The rescaling step of asyncRescaleAndReadPixels[YUV420](). - std::unique_ptr<GrRenderTargetContext> rescale(const SkImageInfo& info, const SkIRect& srcRect, - SkSurface::RescaleGamma rescaleGamma, - SkFilterQuality rescaleQuality); - // Inserts a transfer, part of the implementation of asyncReadPixels and // asyncRescaleAndReadPixelsYUV420(). struct PixelTransferResult { diff --git a/chromium/third_party/skia/src/gpu/GrSurfaceProxy.cpp b/chromium/third_party/skia/src/gpu/GrSurfaceProxy.cpp index 4df6c3302db..23580b2a5e4 100644 --- a/chromium/third_party/skia/src/gpu/GrSurfaceProxy.cpp +++ b/chromium/third_party/skia/src/gpu/GrSurfaceProxy.cpp @@ -106,9 +106,6 @@ GrSurfaceProxy::GrSurfaceProxy(sk_sp<GrSurface> surface, } GrSurfaceProxy::~GrSurfaceProxy() { - // For this to be deleted the opsTask that held a ref on it (if there was one) must have been - // deleted. Which would have cleared out this back pointer. - SkASSERT(!fLastRenderTask); } sk_sp<GrSurface> GrSurfaceProxy::createSurfaceImpl(GrResourceProvider* resourceProvider, @@ -219,21 +216,6 @@ void GrSurfaceProxy::computeScratchKey(const GrCaps& caps, GrScratchKey* key) co renderable, sampleCount, mipMapped, fIsProtected, key); } -void GrSurfaceProxy::setLastRenderTask(GrRenderTask* renderTask) { -#ifdef SK_DEBUG - if (fLastRenderTask) { - SkASSERT(fLastRenderTask->isClosed()); - } -#endif - - // Un-reffed - fLastRenderTask = renderTask; -} - -GrOpsTask* GrSurfaceProxy::getLastOpsTask() { - return fLastRenderTask ? fLastRenderTask->asOpsTask() : nullptr; -} - SkISize GrSurfaceProxy::backingStoreDimensions() const { SkASSERT(!this->isFullyLazy()); if (fTarget) { @@ -259,7 +241,7 @@ bool GrSurfaceProxy::isFormatCompressed(const GrCaps* caps) const { #ifdef SK_DEBUG void GrSurfaceProxy::validate(GrContext_Base* context) const { if (fTarget) { - SkASSERT(fTarget->getContext() == context); + SkASSERT(fTarget->getContext()->priv().matches(context)); } } #endif diff --git a/chromium/third_party/skia/src/gpu/GrSurfaceProxy.h b/chromium/third_party/skia/src/gpu/GrSurfaceProxy.h index 0bbd936127b..f30e21d10d4 100644 --- a/chromium/third_party/skia/src/gpu/GrSurfaceProxy.h +++ b/chromium/third_party/skia/src/gpu/GrSurfaceProxy.h @@ -268,11 +268,6 @@ public: return fSurfaceFlags & GrInternalSurfaceFlags::kRequiresManualMSAAResolve; } - void setLastRenderTask(GrRenderTask*); - GrRenderTask* getLastRenderTask() { return fLastRenderTask; } - - GrOpsTask* getLastOpsTask(); - /** * Retrieves the amount of GPU memory that will be or currently is used by this resource * in bytes. It is approximate since we aren't aware of additional padding or copies made @@ -436,15 +431,6 @@ private: // If the proxy computes its own answer that answer is checked (in debug mode) in // the instantiation method. mutable size_t fGpuMemorySize; - - // The last GrRenderTask that wrote to or is currently going to write to this surface - // The GrRenderTask can be closed (e.g., no surface context is currently bound - // to this proxy). - // This back-pointer is required so that we can add a dependancy between - // the GrRenderTask used to create the current contents of this surface - // and the GrRenderTask of a destination surface to which this one is being drawn or copied. - // This pointer is unreffed. GrRenderTasks own a ref on their surface proxies. - GrRenderTask* fLastRenderTask = nullptr; }; GR_MAKE_BITFIELD_CLASS_OPS(GrSurfaceProxy::ResolveFlags) diff --git a/chromium/third_party/skia/src/gpu/GrTextureProxy.cpp b/chromium/third_party/skia/src/gpu/GrTextureProxy.cpp index fa7e064fa9a..d955712d209 100644 --- a/chromium/third_party/skia/src/gpu/GrTextureProxy.cpp +++ b/chromium/third_party/skia/src/gpu/GrTextureProxy.cpp @@ -24,10 +24,13 @@ GrTextureProxy::GrTextureProxy(const GrBackendFormat& format, SkBudgeted budgeted, GrProtected isProtected, GrInternalSurfaceFlags surfaceFlags, - UseAllocator useAllocator) + UseAllocator useAllocator, + GrDDLProvider creatingProvider) : INHERITED(format, dimensions, fit, budgeted, isProtected, surfaceFlags, useAllocator) , fMipMapped(mipMapped) - , fMipMapsStatus(mipMapsStatus) SkDEBUGCODE(, fInitialMipMapsStatus(fMipMapsStatus)) + , fMipMapsStatus(mipMapsStatus) + SkDEBUGCODE(, fInitialMipMapsStatus(fMipMapsStatus)) + , fCreatingProvider(creatingProvider) , fProxyProvider(nullptr) , fDeferredUploader(nullptr) { SkASSERT(!(fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly)); @@ -43,22 +46,28 @@ GrTextureProxy::GrTextureProxy(LazyInstantiateCallback&& callback, SkBudgeted budgeted, GrProtected isProtected, GrInternalSurfaceFlags surfaceFlags, - UseAllocator useAllocator) + UseAllocator useAllocator, + GrDDLProvider creatingProvider) : INHERITED(std::move(callback), format, dimensions, fit, budgeted, isProtected, surfaceFlags, useAllocator) , fMipMapped(mipMapped) - , fMipMapsStatus(mipMapsStatus) SkDEBUGCODE(, fInitialMipMapsStatus(fMipMapsStatus)) + , fMipMapsStatus(mipMapsStatus) + SkDEBUGCODE(, fInitialMipMapsStatus(fMipMapsStatus)) + , fCreatingProvider(creatingProvider) , fProxyProvider(nullptr) , fDeferredUploader(nullptr) { SkASSERT(!(fSurfaceFlags & GrInternalSurfaceFlags::kFramebufferOnly)); } // Wrapped version -GrTextureProxy::GrTextureProxy(sk_sp<GrSurface> surf, UseAllocator useAllocator) +GrTextureProxy::GrTextureProxy(sk_sp<GrSurface> surf, + UseAllocator useAllocator, + GrDDLProvider creatingProvider) : INHERITED(std::move(surf), SkBackingFit::kExact, useAllocator) , fMipMapped(fTarget->asTexture()->texturePriv().mipMapped()) , fMipMapsStatus(fTarget->asTexture()->texturePriv().mipMapsStatus()) - SkDEBUGCODE(, fInitialMipMapsStatus(fMipMapsStatus)) + SkDEBUGCODE(, fInitialMipMapsStatus(fMipMapsStatus)) + , fCreatingProvider(creatingProvider) , fProxyProvider(nullptr) , fDeferredUploader(nullptr) { if (fTarget->getUniqueKey().isValid()) { diff --git a/chromium/third_party/skia/src/gpu/GrTextureProxy.h b/chromium/third_party/skia/src/gpu/GrTextureProxy.h index 06afa9a08ce..7781cc2309f 100644 --- a/chromium/third_party/skia/src/gpu/GrTextureProxy.h +++ b/chromium/third_party/skia/src/gpu/GrTextureProxy.h @@ -73,7 +73,8 @@ public: */ const GrUniqueKey& getUniqueKey() const { #ifdef SK_DEBUG - if (this->isInstantiated() && fUniqueKey.isValid() && fSyncTargetKey) { + if (this->isInstantiated() && fUniqueKey.isValid() && fSyncTargetKey && + fCreatingProvider == GrDDLProvider::kNo) { GrSurface* surface = this->peekSurface(); SkASSERT(surface); @@ -100,6 +101,8 @@ public: GrTextureProxyPriv texPriv(); const GrTextureProxyPriv texPriv() const; + SkDEBUGCODE(GrDDLProvider creatingProvider() const { return fCreatingProvider; }) + protected: // DDL TODO: rm the GrSurfaceProxy friending friend class GrSurfaceProxy; // for ctors @@ -116,7 +119,8 @@ protected: SkBudgeted, GrProtected, GrInternalSurfaceFlags, - UseAllocator); + UseAllocator, + GrDDLProvider creatingProvider); // Lazy-callback version // There are two main use cases for lazily-instantiated proxies: @@ -137,15 +141,19 @@ protected: SkBudgeted, GrProtected, GrInternalSurfaceFlags, - UseAllocator); + UseAllocator, + GrDDLProvider creatingProvider); // Wrapped version - GrTextureProxy(sk_sp<GrSurface>, UseAllocator); + GrTextureProxy(sk_sp<GrSurface>, UseAllocator, GrDDLProvider creatingProvider); ~GrTextureProxy() override; sk_sp<GrSurface> createSurface(GrResourceProvider*) const override; + // By default uniqueKeys are propagated from a textureProxy to its backing GrTexture. + // Setting syncTargetKey to false disables this behavior and only keeps the unique key + // on the proxy. void setTargetKeySync(bool sync) { fSyncTargetKey = sync; } private: @@ -173,6 +181,12 @@ private: bool fSyncTargetKey = true; // Should target's unique key be sync'ed with ours. + // For GrTextureProxies created in a DDL recording thread it is possible for the uniqueKey + // to be cleared on the backing GrTexture while the uniqueKey remains on the proxy. + // A fCreatingProvider of DDLProvider::kYes loosens up asserts that the key of an instantiated + // uniquely-keyed textureProxy is also always set on the backing GrTexture. + GrDDLProvider fCreatingProvider = GrDDLProvider::kNo; + GrUniqueKey fUniqueKey; GrProxyProvider* fProxyProvider; // only set when fUniqueKey is valid diff --git a/chromium/third_party/skia/src/gpu/GrTextureRenderTargetProxy.cpp b/chromium/third_party/skia/src/gpu/GrTextureRenderTargetProxy.cpp index e7b6e186691..7dbd304e7dd 100644 --- a/chromium/third_party/skia/src/gpu/GrTextureRenderTargetProxy.cpp +++ b/chromium/third_party/skia/src/gpu/GrTextureRenderTargetProxy.cpp @@ -30,13 +30,14 @@ GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps, SkBudgeted budgeted, GrProtected isProtected, GrInternalSurfaceFlags surfaceFlags, - UseAllocator useAllocator) + UseAllocator useAllocator, + GrDDLProvider creatingProvider) : GrSurfaceProxy(format, dimensions, fit, budgeted, isProtected, surfaceFlags, useAllocator) // for now textures w/ data are always wrapped , GrRenderTargetProxy(caps, format, dimensions, sampleCnt, fit, budgeted, isProtected, surfaceFlags, useAllocator) , GrTextureProxy(format, dimensions, mipMapped, mipMapsStatus, fit, budgeted, isProtected, - surfaceFlags, useAllocator) { + surfaceFlags, useAllocator, creatingProvider) { this->initSurfaceFlags(caps); } @@ -52,7 +53,8 @@ GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps, SkBudgeted budgeted, GrProtected isProtected, GrInternalSurfaceFlags surfaceFlags, - UseAllocator useAllocator) + UseAllocator useAllocator, + GrDDLProvider creatingProvider) : GrSurfaceProxy(std::move(callback), format, dimensions, fit, budgeted, isProtected, surfaceFlags, useAllocator) // Since we have virtual inheritance, we initialize GrSurfaceProxy directly. Send null @@ -61,7 +63,8 @@ GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps, budgeted, isProtected, surfaceFlags, useAllocator, WrapsVkSecondaryCB::kNo) , GrTextureProxy(LazyInstantiateCallback(), format, dimensions, mipMapped, mipMapsStatus, - fit, budgeted, isProtected, surfaceFlags, useAllocator) { + fit, budgeted, isProtected, surfaceFlags, useAllocator, + creatingProvider) { this->initSurfaceFlags(caps); } @@ -69,10 +72,11 @@ GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(const GrCaps& caps, // This class is virtually derived from GrSurfaceProxy (via both GrTextureProxy and // GrRenderTargetProxy) so its constructor must be explicitly called. GrTextureRenderTargetProxy::GrTextureRenderTargetProxy(sk_sp<GrSurface> surf, - UseAllocator useAllocator) + UseAllocator useAllocator, + GrDDLProvider creatingProvider) : GrSurfaceProxy(surf, SkBackingFit::kExact, useAllocator) , GrRenderTargetProxy(surf, useAllocator) - , GrTextureProxy(surf, useAllocator) { + , GrTextureProxy(surf, useAllocator, creatingProvider) { SkASSERT(surf->asTexture()); SkASSERT(surf->asRenderTarget()); SkASSERT(fSurfaceFlags == fTarget->surfacePriv().flags()); diff --git a/chromium/third_party/skia/src/gpu/GrTextureRenderTargetProxy.h b/chromium/third_party/skia/src/gpu/GrTextureRenderTargetProxy.h index 585f60c63d9..4eb81f25f89 100644 --- a/chromium/third_party/skia/src/gpu/GrTextureRenderTargetProxy.h +++ b/chromium/third_party/skia/src/gpu/GrTextureRenderTargetProxy.h @@ -38,7 +38,8 @@ private: SkBudgeted, GrProtected, GrInternalSurfaceFlags, - UseAllocator); + UseAllocator, + GrDDLProvider creatingProvider); // Lazy-callback version GrTextureRenderTargetProxy(const GrCaps&, @@ -52,11 +53,13 @@ private: SkBudgeted, GrProtected, GrInternalSurfaceFlags, - UseAllocator); + UseAllocator, + GrDDLProvider creatingProvider); // Wrapped version GrTextureRenderTargetProxy(sk_sp<GrSurface>, - UseAllocator); + UseAllocator, + GrDDLProvider creatingProvider); void initSurfaceFlags(const GrCaps&); diff --git a/chromium/third_party/skia/src/gpu/GrTextureResolveRenderTask.cpp b/chromium/third_party/skia/src/gpu/GrTextureResolveRenderTask.cpp index 8d67c035321..1a915bad9db 100644 --- a/chromium/third_party/skia/src/gpu/GrTextureResolveRenderTask.cpp +++ b/chromium/third_party/skia/src/gpu/GrTextureResolveRenderTask.cpp @@ -14,28 +14,24 @@ #include "src/gpu/GrResourceAllocator.h" #include "src/gpu/GrTexturePriv.h" -GrTextureResolveRenderTask::~GrTextureResolveRenderTask() { - for (const auto& resolve : fResolves) { - // Ensure the proxy doesn't keep hold of a dangling back pointer. - resolve.fProxy->setLastRenderTask(nullptr); - } -} - -void GrTextureResolveRenderTask::addProxy( - sk_sp<GrSurfaceProxy> proxyRef, GrSurfaceProxy::ResolveFlags flags, const GrCaps& caps) { - fResolves.emplace_back(std::move(proxyRef), flags); - GrSurfaceProxy* proxy = fResolves.back().fProxy.get(); +void GrTextureResolveRenderTask::addProxy(GrDrawingManager* drawingMgr, + sk_sp<GrSurfaceProxy> proxyRef, + GrSurfaceProxy::ResolveFlags flags, + const GrCaps& caps) { + Resolve& resolve = fResolves.emplace_back(flags); + GrSurfaceProxy* proxy = proxyRef.get(); // Ensure the last render task that operated on the proxy is closed. That's where msaa and // mipmaps should have been marked dirty. - SkASSERT(!proxy->getLastRenderTask() || proxy->getLastRenderTask()->isClosed()); + SkASSERT(!drawingMgr->getLastRenderTask(proxy) + || drawingMgr->getLastRenderTask(proxy)->isClosed()); SkASSERT(GrSurfaceProxy::ResolveFlags::kNone != flags); if (GrSurfaceProxy::ResolveFlags::kMSAA & flags) { GrRenderTargetProxy* renderTargetProxy = proxy->asRenderTargetProxy(); SkASSERT(renderTargetProxy); SkASSERT(renderTargetProxy->isMSAADirty()); - fResolves.back().fMSAAResolveRect = renderTargetProxy->msaaDirtyRect(); + resolve.fMSAAResolveRect = renderTargetProxy->msaaDirtyRect(); renderTargetProxy->markMSAAResolved(); } @@ -48,8 +44,9 @@ void GrTextureResolveRenderTask::addProxy( // Add the proxy as a dependency: We will read the existing contents of this texture while // generating mipmap levels and/or resolving MSAA. - this->addDependency(proxy, GrMipMapped::kNo, GrTextureResolveManager(nullptr), caps); - proxy->setLastRenderTask(this); + this->addDependency(drawingMgr, proxy, GrMipMapped::kNo, + GrTextureResolveManager(nullptr), caps); + this->addTarget(drawingMgr, GrSurfaceProxyView(std::move(proxyRef))); } void GrTextureResolveRenderTask::gatherProxyIntervals(GrResourceAllocator* alloc) const { @@ -57,8 +54,9 @@ void GrTextureResolveRenderTask::gatherProxyIntervals(GrResourceAllocator* alloc // fEndOfOpsTaskOpIndices will remain in sync. We create fake op#'s to capture the fact that we // manipulate the resolve proxies. auto fakeOp = alloc->curOp(); - for (const auto& resolve : fResolves) { - alloc->addInterval(resolve.fProxy.get(), fakeOp, fakeOp, + SkASSERT(fResolves.count() == this->numTargets()); + for (const GrSurfaceProxyView& target : fTargets) { + alloc->addInterval(target.proxy(), fakeOp, fakeOp, GrResourceAllocator::ActualUse::kYes); } alloc->incOps(); @@ -66,9 +64,11 @@ void GrTextureResolveRenderTask::gatherProxyIntervals(GrResourceAllocator* alloc bool GrTextureResolveRenderTask::onExecute(GrOpFlushState* flushState) { // Resolve all msaa back-to-back, before regenerating mipmaps. - for (const auto& resolve : fResolves) { + SkASSERT(fResolves.count() == this->numTargets()); + for (int i = 0; i < fResolves.count(); ++i) { + const Resolve& resolve = fResolves[i]; if (GrSurfaceProxy::ResolveFlags::kMSAA & resolve.fFlags) { - GrSurfaceProxy* proxy = resolve.fProxy.get(); + GrSurfaceProxy* proxy = this->target(i).proxy(); // peekRenderTarget might be null if there was an instantiation error. if (GrRenderTarget* renderTarget = proxy->peekRenderTarget()) { flushState->gpu()->resolveRenderTarget(renderTarget, resolve.fMSAAResolveRect, @@ -77,10 +77,11 @@ bool GrTextureResolveRenderTask::onExecute(GrOpFlushState* flushState) { } } // Regenerate all mipmaps back-to-back. - for (const auto& resolve : fResolves) { + for (int i = 0; i < fResolves.count(); ++i) { + const Resolve& resolve = fResolves[i]; if (GrSurfaceProxy::ResolveFlags::kMipMaps & resolve.fFlags) { // peekTexture might be null if there was an instantiation error. - GrTexture* texture = resolve.fProxy->peekTexture(); + GrTexture* texture = this->target(i).proxy()->peekTexture(); if (texture && texture->texturePriv().mipMapsAreDirty()) { flushState->gpu()->regenerateMipMapLevels(texture); SkASSERT(!texture->texturePriv().mipMapsAreDirty()); @@ -92,9 +93,5 @@ bool GrTextureResolveRenderTask::onExecute(GrOpFlushState* flushState) { } #ifdef SK_DEBUG -void GrTextureResolveRenderTask::visitProxies_debugOnly(const GrOp::VisitProxyFunc& fn) const { - for (const auto& resolve : fResolves) { - fn(resolve.fProxy.get(), GrMipMapped::kNo); - } -} +void GrTextureResolveRenderTask::visitProxies_debugOnly(const GrOp::VisitProxyFunc& fn) const {} #endif diff --git a/chromium/third_party/skia/src/gpu/GrTextureResolveRenderTask.h b/chromium/third_party/skia/src/gpu/GrTextureResolveRenderTask.h index e9ce954ca5c..379aa4b3453 100644 --- a/chromium/third_party/skia/src/gpu/GrTextureResolveRenderTask.h +++ b/chromium/third_party/skia/src/gpu/GrTextureResolveRenderTask.h @@ -13,14 +13,12 @@ class GrTextureResolveRenderTask final : public GrRenderTask { public: GrTextureResolveRenderTask() : GrRenderTask() {} - ~GrTextureResolveRenderTask() override; - void addProxy(sk_sp<GrSurfaceProxy> proxy, GrSurfaceProxy::ResolveFlags, const GrCaps&); + void addProxy(GrDrawingManager*, sk_sp<GrSurfaceProxy> proxy, + GrSurfaceProxy::ResolveFlags, const GrCaps&); private: bool onIsUsed(GrSurfaceProxy* proxy) const override { - // This case should be handled by GrRenderTask. - SkASSERT(proxy != fTargetView.proxy()); return false; } void handleInternalAllocationFailure() override { @@ -40,9 +38,7 @@ private: #endif struct Resolve { - Resolve(sk_sp<GrSurfaceProxy> proxy, GrSurfaceProxy::ResolveFlags flags) - : fProxy(std::move(proxy)), fFlags(flags) {} - sk_sp<GrSurfaceProxy> fProxy; + Resolve(GrSurfaceProxy::ResolveFlags flags) : fFlags(flags) {} GrSurfaceProxy::ResolveFlags fFlags; SkIRect fMSAAResolveRect; }; diff --git a/chromium/third_party/skia/src/gpu/GrTransferFromRenderTask.h b/chromium/third_party/skia/src/gpu/GrTransferFromRenderTask.h index 2126ae81a86..93a0f7aad31 100644 --- a/chromium/third_party/skia/src/gpu/GrTransferFromRenderTask.h +++ b/chromium/third_party/skia/src/gpu/GrTransferFromRenderTask.h @@ -28,7 +28,7 @@ public: private: bool onIsUsed(GrSurfaceProxy* proxy) const override { - SkASSERT(!fTargetView.proxy()); + SkASSERT(0 == this->numTargets()); return proxy == fSrcProxy.get(); } // If fSrcProxy is uninstantiated at flush time we simply will skip doing the transfer. diff --git a/chromium/third_party/skia/src/gpu/GrTriangulator.cpp b/chromium/third_party/skia/src/gpu/GrTriangulator.cpp index b2b2af31add..f695d6ee2dc 100644 --- a/chromium/third_party/skia/src/gpu/GrTriangulator.cpp +++ b/chromium/third_party/skia/src/gpu/GrTriangulator.cpp @@ -2400,13 +2400,13 @@ int get_contour_count(const SkPath& path, SkScalar tolerance) { if (!first) { ++contourCnt; } - // fallthru. + [[fallthrough]]; case SkPath::kLine_Verb: case SkPath::kConic_Verb: case SkPath::kQuad_Verb: case SkPath::kCubic_Verb: hasPoints = true; - // fallthru to break. + break; default: break; } diff --git a/chromium/third_party/skia/src/gpu/GrUniformDataManager.cpp b/chromium/third_party/skia/src/gpu/GrUniformDataManager.cpp new file mode 100644 index 00000000000..549057a3d5a --- /dev/null +++ b/chromium/third_party/skia/src/gpu/GrUniformDataManager.cpp @@ -0,0 +1,319 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/gpu/GrUniformDataManager.h" + +#include "src/gpu/GrShaderVar.h" + +GrUniformDataManager::GrUniformDataManager(uint32_t uniformCount, uint32_t uniformSize) + : fUniformSize(uniformSize) + , fUniformsDirty(false) { + fUniformData.reset(uniformSize); + fUniforms.push_back_n(uniformCount); + // subclasses fill in the uniforms in their constructor +} + +void* GrUniformDataManager::getBufferPtrAndMarkDirty(const Uniform& uni) const { + fUniformsDirty = true; + return static_cast<char*>(fUniformData.get())+uni.fOffset; +} + +void GrUniformDataManager::set1i(UniformHandle u, int32_t i) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + void* buffer = this->getBufferPtrAndMarkDirty(uni); + memcpy(buffer, &i, sizeof(int32_t)); +} + +void GrUniformDataManager::set1iv(UniformHandle u, + int arrayCount, + const int32_t v[]) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType); + SkASSERT(arrayCount > 0); + SkASSERT(arrayCount <= uni.fArrayCount || + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); + + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(int32_t) == 4); + for (int i = 0; i < arrayCount; ++i) { + const int32_t* curVec = &v[i]; + memcpy(buffer, curVec, sizeof(int32_t)); + buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t); + } +} + +void GrUniformDataManager::set1f(UniformHandle u, float v0) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(float) == 4); + memcpy(buffer, &v0, sizeof(float)); +} + +void GrUniformDataManager::set1fv(UniformHandle u, + int arrayCount, + const float v[]) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType); + SkASSERT(arrayCount > 0); + SkASSERT(arrayCount <= uni.fArrayCount || + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); + + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(float) == 4); + for (int i = 0; i < arrayCount; ++i) { + const float* curVec = &v[i]; + memcpy(buffer, curVec, sizeof(float)); + buffer = static_cast<char*>(buffer) + 4*sizeof(float); + } +} + +void GrUniformDataManager::set2i(UniformHandle u, int32_t i0, int32_t i1) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + void* buffer = this->getBufferPtrAndMarkDirty(uni); + int32_t v[2] = { i0, i1 }; + memcpy(buffer, v, 2 * sizeof(int32_t)); +} + +void GrUniformDataManager::set2iv(UniformHandle u, + int arrayCount, + const int32_t v[]) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType); + SkASSERT(arrayCount > 0); + SkASSERT(arrayCount <= uni.fArrayCount || + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); + + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(int32_t) == 4); + for (int i = 0; i < arrayCount; ++i) { + const int32_t* curVec = &v[2 * i]; + memcpy(buffer, curVec, 2 * sizeof(int32_t)); + buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t); + } +} + +void GrUniformDataManager::set2f(UniformHandle u, float v0, float v1) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(float) == 4); + float v[2] = { v0, v1 }; + memcpy(buffer, v, 2 * sizeof(float)); +} + +void GrUniformDataManager::set2fv(UniformHandle u, + int arrayCount, + const float v[]) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType); + SkASSERT(arrayCount > 0); + SkASSERT(arrayCount <= uni.fArrayCount || + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); + + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(float) == 4); + for (int i = 0; i < arrayCount; ++i) { + const float* curVec = &v[2 * i]; + memcpy(buffer, curVec, 2 * sizeof(float)); + buffer = static_cast<char*>(buffer) + 4*sizeof(float); + } +} + +void GrUniformDataManager::set3i(UniformHandle u, + int32_t i0, + int32_t i1, + int32_t i2) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + void* buffer = this->getBufferPtrAndMarkDirty(uni); + int32_t v[3] = { i0, i1, i2 }; + memcpy(buffer, v, 3 * sizeof(int32_t)); +} + +void GrUniformDataManager::set3iv(UniformHandle u, + int arrayCount, + const int32_t v[]) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType); + SkASSERT(arrayCount > 0); + SkASSERT(arrayCount <= uni.fArrayCount || + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); + + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(int32_t) == 4); + for (int i = 0; i < arrayCount; ++i) { + const int32_t* curVec = &v[3 * i]; + memcpy(buffer, curVec, 3 * sizeof(int32_t)); + buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t); + } +} + +void GrUniformDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(float) == 4); + float v[3] = { v0, v1, v2 }; + memcpy(buffer, v, 3 * sizeof(float)); +} + +void GrUniformDataManager::set3fv(UniformHandle u, + int arrayCount, + const float v[]) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType); + SkASSERT(arrayCount > 0); + SkASSERT(arrayCount <= uni.fArrayCount || + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); + + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(float) == 4); + for (int i = 0; i < arrayCount; ++i) { + const float* curVec = &v[3 * i]; + memcpy(buffer, curVec, 3 * sizeof(float)); + buffer = static_cast<char*>(buffer) + 4*sizeof(float); + } +} + +void GrUniformDataManager::set4i(UniformHandle u, + int32_t i0, + int32_t i1, + int32_t i2, + int32_t i3) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + void* buffer = this->getBufferPtrAndMarkDirty(uni); + int32_t v[4] = { i0, i1, i2, i3 }; + memcpy(buffer, v, 4 * sizeof(int32_t)); +} + +void GrUniformDataManager::set4iv(UniformHandle u, + int arrayCount, + const int32_t v[]) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType); + SkASSERT(arrayCount > 0); + SkASSERT(arrayCount <= uni.fArrayCount || + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); + + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(int32_t) == 4); + for (int i = 0; i < arrayCount; ++i) { + const int32_t* curVec = &v[4 * i]; + memcpy(buffer, curVec, 4 * sizeof(int32_t)); + buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t); + } +} + +void GrUniformDataManager::set4f(UniformHandle u, + float v0, + float v1, + float v2, + float v3) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType); + SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(float) == 4); + float v[4] = { v0, v1, v2, v3 }; + memcpy(buffer, v, 4 * sizeof(float)); +} + +void GrUniformDataManager::set4fv(UniformHandle u, + int arrayCount, + const float v[]) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType); + SkASSERT(arrayCount > 0); + SkASSERT(arrayCount <= uni.fArrayCount || + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); + + void* buffer = this->getBufferPtrAndMarkDirty(uni); + SkASSERT(sizeof(float) == 4); + memcpy(buffer, v, arrayCount * 4 * sizeof(float)); +} + +void GrUniformDataManager::setMatrix2f(UniformHandle u, const float matrix[]) const { + this->setMatrices<2>(u, 1, matrix); +} + +void GrUniformDataManager::setMatrix2fv(UniformHandle u, + int arrayCount, + const float m[]) const { + this->setMatrices<2>(u, arrayCount, m); +} + +void GrUniformDataManager::setMatrix3f(UniformHandle u, const float matrix[]) const { + this->setMatrices<3>(u, 1, matrix); +} + +void GrUniformDataManager::setMatrix3fv(UniformHandle u, + int arrayCount, + const float m[]) const { + this->setMatrices<3>(u, arrayCount, m); +} + +void GrUniformDataManager::setMatrix4f(UniformHandle u, const float matrix[]) const { + this->setMatrices<4>(u, 1, matrix); +} + +void GrUniformDataManager::setMatrix4fv(UniformHandle u, + int arrayCount, + const float m[]) const { + this->setMatrices<4>(u, arrayCount, m); +} + +template<int N> struct set_uniform_matrix; + +template<int N> inline void GrUniformDataManager::setMatrices(UniformHandle u, + int arrayCount, + const float matrices[]) const { + const Uniform& uni = fUniforms[u.toIndex()]; + SkASSERT(uni.fType == kFloat2x2_GrSLType + (N - 2) || + uni.fType == kHalf2x2_GrSLType + (N - 2)); + SkASSERT(arrayCount > 0); + SkASSERT(arrayCount <= uni.fArrayCount || + (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); + + void* buffer = fUniformData.get(); + fUniformsDirty = true; + + set_uniform_matrix<N>::set(buffer, uni.fOffset, arrayCount, matrices); +} + +template<int N> struct set_uniform_matrix { + inline static void set(void* buffer, int uniformOffset, int count, const float matrices[]) { + static_assert(sizeof(float) == 4); + buffer = static_cast<char*>(buffer) + uniformOffset; + for (int i = 0; i < count; ++i) { + const float* matrix = &matrices[N * N * i]; + for (int j = 0; j < N; ++j) { + memcpy(buffer, &matrix[j * N], N * sizeof(float)); + buffer = static_cast<char*>(buffer) + 4 * sizeof(float); + } + } + } +}; + +template<> struct set_uniform_matrix<4> { + inline static void set(void* buffer, int uniformOffset, int count, const float matrices[]) { + static_assert(sizeof(float) == 4); + buffer = static_cast<char*>(buffer) + uniformOffset; + memcpy(buffer, matrices, count * 16 * sizeof(float)); + } +}; + diff --git a/chromium/third_party/skia/src/gpu/GrUniformDataManager.h b/chromium/third_party/skia/src/gpu/GrUniformDataManager.h new file mode 100644 index 00000000000..dc08bcf0d2b --- /dev/null +++ b/chromium/third_party/skia/src/gpu/GrUniformDataManager.h @@ -0,0 +1,77 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrUniformDataManager_DEFINED +#define GrUniformDataManager_DEFINED + +#include "src/gpu/glsl/GrGLSLProgramDataManager.h" + +#include "include/private/GrTypesPriv.h" +#include "include/private/SkTArray.h" +#include "src/core/SkAutoMalloc.h" + +class GrUniformDataManager : public GrGLSLProgramDataManager { +public: + GrUniformDataManager(uint32_t uniformCount, uint32_t uniformSize); + + void set1i(UniformHandle, int32_t) const override; + void set1iv(UniformHandle, int arrayCount, const int32_t v[]) const override; + void set1f(UniformHandle, float v0) const override; + void set1fv(UniformHandle, int arrayCount, const float v[]) const override; + void set2i(UniformHandle, int32_t, int32_t) const override; + void set2iv(UniformHandle, int arrayCount, const int32_t v[]) const override; + void set2f(UniformHandle, float, float) const override; + void set2fv(UniformHandle, int arrayCount, const float v[]) const override; + void set3i(UniformHandle, int32_t, int32_t, int32_t) const override; + void set3iv(UniformHandle, int arrayCount, const int32_t v[]) const override; + void set3f(UniformHandle, float, float, float) const override; + void set3fv(UniformHandle, int arrayCount, const float v[]) const override; + void set4i(UniformHandle, int32_t, int32_t, int32_t, int32_t) const override; + void set4iv(UniformHandle, int arrayCount, const int32_t v[]) const override; + void set4f(UniformHandle, float, float, float, float) const override; + void set4fv(UniformHandle, int arrayCount, const float v[]) const override; + // matrices are column-major, the first two upload a single matrix, the latter two upload + // arrayCount matrices into a uniform array. + void setMatrix2f(UniformHandle, const float matrix[]) const override; + void setMatrix3f(UniformHandle, const float matrix[]) const override; + void setMatrix4f(UniformHandle, const float matrix[]) const override; + void setMatrix2fv(UniformHandle, int arrayCount, const float matrices[]) const override; + void setMatrix3fv(UniformHandle, int arrayCount, const float matrices[]) const override; + void setMatrix4fv(UniformHandle, int arrayCount, const float matrices[]) const override; + + // for nvpr only + void setPathFragmentInputTransform(VaryingHandle u, int components, + const SkMatrix& matrix) const override { + SK_ABORT("Only supported in NVPR, which is only available in GL"); + } + + // For the uniform data to be dirty so that we will reupload on the next use. + void markDirty() { fUniformsDirty = true; } + +protected: + struct Uniform { + uint32_t fOffset; + SkDEBUGCODE( + GrSLType fType; + int fArrayCount; + ); + }; + + template<int N> inline void setMatrices(UniformHandle, int arrayCount, + const float matrices[]) const; + + void* getBufferPtrAndMarkDirty(const Uniform& uni) const; + + uint32_t fUniformSize; + + SkTArray<Uniform, true> fUniforms; + + mutable SkAutoMalloc fUniformData; + mutable bool fUniformsDirty; +}; + +#endif diff --git a/chromium/third_party/skia/src/gpu/GrWaitRenderTask.cpp b/chromium/third_party/skia/src/gpu/GrWaitRenderTask.cpp index d7b2a7cc081..d9740301760 100644 --- a/chromium/third_party/skia/src/gpu/GrWaitRenderTask.cpp +++ b/chromium/third_party/skia/src/gpu/GrWaitRenderTask.cpp @@ -14,15 +14,22 @@ void GrWaitRenderTask::gatherProxyIntervals(GrResourceAllocator* alloc) const { // This renderTask doesn't have "normal" ops. In this case we still need to add an interval (so // fEndOfOpsTaskOpIndices will remain in sync), so we create a fake op# to capture the fact that - // we manipulate fTargetView's proxy. - alloc->addInterval(fTargetView.proxy(), alloc->curOp(), alloc->curOp(), + // we manipulate our target's proxy. + SkASSERT(0 == this->numTargets()); + auto fakeOp = alloc->curOp(); + alloc->addInterval(fWaitedOn.proxy(), fakeOp, fakeOp, GrResourceAllocator::ActualUse::kYes); alloc->incOps(); } bool GrWaitRenderTask::onExecute(GrOpFlushState* flushState) { for (int i = 0; i < fNumSemaphores; ++i) { - flushState->gpu()->waitSemaphore(fSemaphores[i].get()); + // If we don't have a semaphore here it means we failed to wrap it. That happens if the + // client didn't give us a valid semaphore to begin with. Therefore, it is fine to not wait + // on it. + if (fSemaphores[i].get()) { + flushState->gpu()->waitSemaphore(fSemaphores[i].get()); + } } return true; } diff --git a/chromium/third_party/skia/src/gpu/GrWaitRenderTask.h b/chromium/third_party/skia/src/gpu/GrWaitRenderTask.h index 18e715755c8..4681f76209f 100644 --- a/chromium/third_party/skia/src/gpu/GrWaitRenderTask.h +++ b/chromium/third_party/skia/src/gpu/GrWaitRenderTask.h @@ -16,15 +16,14 @@ public: GrWaitRenderTask(GrSurfaceProxyView surfaceView, std::unique_ptr<std::unique_ptr<GrSemaphore>[]> semaphores, int numSemaphores) - : GrRenderTask(std::move(surfaceView)) + : GrRenderTask() , fSemaphores(std::move(semaphores)) - , fNumSemaphores(numSemaphores) {} + , fNumSemaphores(numSemaphores) + , fWaitedOn(std::move(surfaceView)) {} private: bool onIsUsed(GrSurfaceProxy* proxy) const override { - // This case should be handled by GrRenderTask. - SkASSERT(proxy != fTargetView.proxy()); - return false; + return proxy == fWaitedOn.proxy(); } void handleInternalAllocationFailure() override {} void gatherProxyIntervals(GrResourceAllocator*) const override; @@ -42,6 +41,11 @@ private: #endif std::unique_ptr<std::unique_ptr<GrSemaphore>[]> fSemaphores; int fNumSemaphores; + + // This field is separate from the main "targets" field on GrRenderTask because this task + // does not actually write to the surface and so should not participate in the normal + // lastRenderTask tracking that written-to targets do. + GrSurfaceProxyView fWaitedOn; }; #endif diff --git a/chromium/third_party/skia/src/gpu/GrYUVProvider.cpp b/chromium/third_party/skia/src/gpu/GrYUVProvider.cpp index 6a25a79562b..3d5668c6f30 100644 --- a/chromium/third_party/skia/src/gpu/GrYUVProvider.cpp +++ b/chromium/third_party/skia/src/gpu/GrYUVProvider.cpp @@ -16,7 +16,6 @@ #include "src/core/SkYUVPlanesCache.h" #include "src/gpu/GrBitmapTextureMaker.h" #include "src/gpu/GrCaps.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrColorSpaceXform.h" #include "src/gpu/GrProxyProvider.h" #include "src/gpu/GrRecordingContextPriv.h" @@ -191,7 +190,7 @@ GrSurfaceProxyView GrYUVProvider::refAsTextureProxyView(GrRecordingContext* ctx, yuvSizeInfo.fSizes[0].fHeight); SkMatrix m = SkEncodedOriginToMatrix(yuvSizeInfo.fOrigin, r.width(), r.height()); - renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, m, r); + renderTargetContext->drawRect(nullptr, std::move(paint), GrAA::kNo, m, r); SkASSERT(renderTargetContext->asTextureProxy()); return renderTargetContext->readSurfaceView(); diff --git a/chromium/third_party/skia/src/gpu/SkGpuDevice.cpp b/chromium/third_party/skia/src/gpu/SkGpuDevice.cpp index fcd15fa7aad..aa949a3acc3 100644 --- a/chromium/third_party/skia/src/gpu/SkGpuDevice.cpp +++ b/chromium/third_party/skia/src/gpu/SkGpuDevice.cpp @@ -48,8 +48,7 @@ #include "src/image/SkSurface_Gpu.h" #include "src/utils/SkUTF.h" -#define ASSERT_SINGLE_OWNER \ -SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->priv().singleOwner());) +#define ASSERT_SINGLE_OWNER GR_ASSERT_SINGLE_OWNER(fContext->priv().singleOwner()) /////////////////////////////////////////////////////////////////////////////// @@ -125,7 +124,8 @@ SkGpuDevice::SkGpuDevice(GrContext* context, : INHERITED(make_info(renderTargetContext.get(), SkToBool(flags & kIsOpaque_Flag)), renderTargetContext->surfaceProps()) , fContext(SkRef(context)) - , fRenderTargetContext(std::move(renderTargetContext)) { + , fRenderTargetContext(std::move(renderTargetContext)) + , fClip(fRenderTargetContext->dimensions(), &this->cs(), &this->asMatrixProvider()) { if (flags & kNeedClear_Flag) { this->clearAll(); } @@ -209,8 +209,7 @@ void SkGpuDevice::clearAll() { GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "clearAll", fContext.get()); SkIRect rect = SkIRect::MakeWH(this->width(), this->height()); - fRenderTargetContext->clear(&rect, SK_PMColor4fTRANSPARENT, - GrRenderTargetContext::CanClearFullscreen::kYes); + fRenderTargetContext->priv().clearAtLeast(rect, SK_PMColor4fTRANSPARENT); } void SkGpuDevice::replaceRenderTargetContext(std::unique_ptr<GrRenderTargetContext> rtc, @@ -325,13 +324,12 @@ void SkGpuDevice::drawPoints(SkCanvas::PointMode mode, const SkMatrixProvider* matrixProvider = this; #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK - SkTLazy<SkPostConcatMatrixProvider> postConcatMatrixProvider; + SkTLazy<SkPostTranslateMatrixProvider> postTranslateMatrixProvider; // This offsetting in device space matches the expectations of the Android framework for non-AA // points and lines. if (GrIsPrimTypeLines(primitiveType) || GrPrimitiveType::kPoints == primitiveType) { static const SkScalar kOffset = 0.063f; // Just greater than 1/16. - matrixProvider = postConcatMatrixProvider.init(*matrixProvider, - SkMatrix::MakeTrans(kOffset, kOffset)); + matrixProvider = postTranslateMatrixProvider.init(*matrixProvider, kOffset, kOffset); } #endif @@ -630,8 +628,7 @@ void SkGpuDevice::drawPath(const SkPath& origSrcPath, const SkPaint& paint, bool paint, this->asMatrixProvider(), shape); } -void SkGpuDevice::drawSpecial(SkSpecialImage* special, int left, int top, const SkPaint& paint, - SkImage* clipImage, const SkMatrix& clipMatrix) { +void SkGpuDevice::drawSpecial(SkSpecialImage* special, int left, int top, const SkPaint& paint) { SkASSERT(!paint.getMaskFilter()); ASSERT_SINGLE_OWNER @@ -687,55 +684,7 @@ void SkGpuDevice::drawSpecial(SkSpecialImage* special, int left, int top, const const SkIRect& subset = result->subset(); SkRect dstRect = SkRect::Make(SkIRect::MakeXYWH(left, top, subset.width(), subset.height())); SkRect srcRect = SkRect::Make(subset); - if (clipImage) { - // Add the image as a simple texture effect applied to coverage. Accessing content outside - // of the clip image should behave as if it were a decal (i.e. zero coverage). However, to - // limit pixels touched and hardware checks, we draw the clip image geometry to get the - // decal effect. - auto filter = paint.getFilterQuality() > kNone_SkFilterQuality - ? GrSamplerState::Filter::kBilerp - : GrSamplerState::Filter::kNearest; - GrSurfaceProxyView clipView = as_IB(clipImage)->refView(this->context(), GrMipMapped::kNo); - // Fold clip matrix into ctm - ctm.preConcat(clipMatrix); - SkMatrix inverseClipMatrix; - - std::unique_ptr<GrFragmentProcessor> cfp; - if (clipView && ctm.invert(&inverseClipMatrix)) { - GrColorType srcColorType = SkColorTypeToGrColorType(clipImage->colorType()); - - cfp = GrTextureEffect::Make(std::move(clipView), clipImage->alphaType(), - inverseClipMatrix, filter); - if (srcColorType != GrColorType::kAlpha_8) { - cfp = GrFragmentProcessor::SwizzleOutput(std::move(cfp), GrSwizzle::AAAA()); - } - } - if (cfp) { - // If the grPaint already has coverage, this adds an additional stage that multiples - // the image's alpha channel with the prior coverage. - grPaint.addCoverageFragmentProcessor(std::move(cfp)); - - // Undo the offset that was needed for shader coord transforms to get the transform for - // the actual drawn geometry. - ctm.postTranslate(SkIntToScalar(left), SkIntToScalar(top)); - inverseClipMatrix.preTranslate(-SkIntToScalar(left), -SkIntToScalar(top)); - SkRect clipGeometry = SkRect::MakeWH(clipImage->width(), clipImage->height()); - if (!clipGeometry.contains(inverseClipMatrix.mapRect(dstRect))) { - // Draw the clip geometry since it is smaller, using dstRect as an extra scissor - SkClipStack clip(this->cs()); - clip.clipDevRect(SkIRect::MakeXYWH(left, top, subset.width(), subset.height()), - SkClipOp::kIntersect); - SkMatrix local = SkMatrix::Concat(SkMatrix::MakeRectToRect( - dstRect, srcRect, SkMatrix::kFill_ScaleToFit), ctm); - fRenderTargetContext->fillRectWithLocalMatrix(GrClipStackClip(&clip), - std::move(grPaint), GrAA(paint.isAntiAlias()), ctm, clipGeometry, local); - return; - } - // Else fall through and draw the subset since that is contained in the clip geometry - } - // Else some issue configuring the coverage FP, so just draw without the clip mask image - } // Draw directly in screen space, possibly with an extra coverage processor fRenderTargetContext->fillRectToRect(this->clip(), std::move(grPaint), GrAA(paint.isAntiAlias()), SkMatrix::I(), dstRect, srcRect); @@ -844,7 +793,7 @@ void SkGpuDevice::drawDevice(SkBaseDevice* device, return; } - this->drawSpecial(srcImg.get(), left, top, paint, nullptr, SkMatrix::I()); + this->drawSpecial(srcImg.get(), left, top, paint); } void SkGpuDevice::drawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst, @@ -941,12 +890,11 @@ static bool init_vertices_paint(GrContext* context, const SkPaint& skPaint, const SkMatrixProvider& matrixProvider, SkBlendMode bmode, - bool hasTexs, bool hasColors, GrPaint* grPaint) { - if (hasTexs && skPaint.getShader()) { + if (skPaint.getShader()) { if (hasColors) { - // When there are texs and colors the shader and colors are combined using bmode. + // When there are colors and a shader, the shader and colors are combined using bmode. return SkPaintToGrPaintWithXfermode(context, colorInfo, skPaint, matrixProvider, bmode, grPaint); } else { @@ -955,12 +903,11 @@ static bool init_vertices_paint(GrContext* context, } } else { if (hasColors) { - // We have colors, but either have no shader or no texture coords (which implies that - // we should ignore the shader). + // We have colors, but no shader. return SkPaintToGrPaintWithPrimitiveColor(context, colorInfo, skPaint, matrixProvider, grPaint); } else { - // No colors and no shaders. Just draw with the paint color. + // No colors and no shader. Just draw with the paint color. return SkPaintToGrPaintNoShader(context, colorInfo, skPaint, matrixProvider, grPaint); } } @@ -976,13 +923,9 @@ void SkGpuDevice::drawVertices(const SkVertices* vertices, SkBlendMode mode, con const SkRuntimeEffect* effect = paint.getShader() ? as_SB(paint.getShader())->asRuntimeEffect() : nullptr; - // Pretend that we have tex coords when using custom per-vertex data. The shader is going to - // use those (rather than local coords), but our paint conversion remains the same. GrPaint grPaint; - bool hasColors = info.hasColors(); - bool hasTexs = info.hasTexCoords() || info.hasCustomData(); if (!init_vertices_paint(fContext.get(), fRenderTargetContext->colorInfo(), paint, - this->asMatrixProvider(), mode, hasTexs, hasColors, &grPaint)) { + this->asMatrixProvider(), mode, info.hasColors(), &grPaint)) { return; } fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->asMatrixProvider(), @@ -1067,14 +1010,16 @@ void SkGpuDevice::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix, SkC /////////////////////////////////////////////////////////////////////////////// void SkGpuDevice::flush() { - this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo()); + this->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo(), nullptr); + this->context()->submit(); } GrSemaphoresSubmitted SkGpuDevice::flush(SkSurface::BackendSurfaceAccess access, - const GrFlushInfo& info) { + const GrFlushInfo& info, + const GrBackendSurfaceMutableState* newState) { ASSERT_SINGLE_OWNER - return fRenderTargetContext->flush(access, info); + return fRenderTargetContext->flush(access, info, newState); } bool SkGpuDevice::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) { @@ -1143,7 +1088,6 @@ bool SkGpuDevice::android_utils_clipWithStencil() { } GrPaint grPaint; grPaint.setXPFactory(GrDisableColorXPFactory::Get()); - GrNoClip noClip; static constexpr GrUserStencilSettings kDrawToStencil( GrUserStencilSettings::StaticInit< 0x1, @@ -1153,7 +1097,7 @@ bool SkGpuDevice::android_utils_clipWithStencil() { GrUserStencilOp::kReplace, 0x1>() ); - rtc->drawRegion(noClip, std::move(grPaint), GrAA::kNo, SkMatrix::I(), clipRegion, + rtc->drawRegion(nullptr, std::move(grPaint), GrAA::kNo, SkMatrix::I(), clipRegion, GrStyle::SimpleFill(), &kDrawToStencil); return true; } diff --git a/chromium/third_party/skia/src/gpu/SkGpuDevice.h b/chromium/third_party/skia/src/gpu/SkGpuDevice.h index 664aaf0b5c9..75aa82db57b 100644 --- a/chromium/third_party/skia/src/gpu/SkGpuDevice.h +++ b/chromium/third_party/skia/src/gpu/SkGpuDevice.h @@ -101,8 +101,7 @@ public: void drawDevice(SkBaseDevice*, int x, int y, const SkPaint&) override; - void drawSpecial(SkSpecialImage*, int left, int top, const SkPaint& paint, - SkImage*, const SkMatrix&) override; + void drawSpecial(SkSpecialImage*, int left, int top, const SkPaint&) override; void drawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color, SkBlendMode mode) override; @@ -114,7 +113,8 @@ public: sk_sp<SkSpecialImage> snapSpecial(const SkIRect&, bool = false) override; void flush() override; - GrSemaphoresSubmitted flush(SkSurface::BackendSurfaceAccess access, const GrFlushInfo&); + GrSemaphoresSubmitted flush(SkSurface::BackendSurfaceAccess access, const GrFlushInfo&, + const GrBackendSurfaceMutableState*); bool wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores); bool onAccessPixels(SkPixmap*) override; @@ -129,6 +129,7 @@ private: // We want these unreffed in RenderTargetContext, GrContext order. sk_sp<GrContext> fContext; std::unique_ptr<GrRenderTargetContext> fRenderTargetContext; + GrClipStackClip fClip; enum Flags { kNeedClear_Flag = 1 << 0, //!< Surface requires an initial clear @@ -148,7 +149,7 @@ private: bool forceConservativeRasterClip() const override { return true; } - GrClipStackClip clip() const { return GrClipStackClip(&this->cs()); } + const GrClip* clip() const { return &fClip; } sk_sp<SkSpecialImage> filterTexture(SkSpecialImage*, int left, int top, diff --git a/chromium/third_party/skia/src/gpu/SkGpuDevice_drawTexture.cpp b/chromium/third_party/skia/src/gpu/SkGpuDevice_drawTexture.cpp index 3534b6cd844..4ef4d653950 100644 --- a/chromium/third_party/skia/src/gpu/SkGpuDevice_drawTexture.cpp +++ b/chromium/third_party/skia/src/gpu/SkGpuDevice_drawTexture.cpp @@ -125,12 +125,13 @@ static int determine_tile_size(const SkIRect& src, int maxTileSize) { // Given a bitmap, an optional src rect, and a context with a clip and matrix determine what // pixels from the bitmap are necessary. static SkIRect determine_clipped_src_rect(int width, int height, - const GrClip& clip, + const GrClip* clip, const SkMatrix& viewMatrix, const SkMatrix& srcToDstRect, const SkISize& imageDimensions, const SkRect* srcRectPtr) { - SkIRect clippedSrcIRect = clip.getConservativeBounds(width, height); + SkIRect clippedSrcIRect = clip ? clip->getConservativeBounds() + : SkIRect::MakeWH(width, height); SkMatrix inv = SkMatrix::Concat(viewMatrix, srcToDstRect); if (!inv.invert(&inv)) { return SkIRect::MakeEmpty(); @@ -154,7 +155,7 @@ static SkIRect determine_clipped_src_rect(int width, int height, // tileSize and clippedSubset are valid if true is returned static bool should_tile_image_id(GrContext* context, SkISize rtSize, - const GrClip& clip, + const GrClip* clip, uint32_t imageID, const SkISize& imageSize, const SkMatrix& ctm, @@ -318,8 +319,19 @@ static bool can_use_draw_texture(const SkPaint& paint) { !paint.getImageFilter() && paint.getFilterQuality() < kMedium_SkFilterQuality); } +static SkPMColor4f texture_color(SkColor4f paintColor, float entryAlpha, GrColorType srcColorType, + const GrColorInfo& dstColorInfo) { + paintColor.fA *= entryAlpha; + if (GrColorTypeIsAlphaOnly(srcColorType)) { + return SkColor4fPrepForDst(paintColor, dstColorInfo).premul(); + } else { + float paintAlpha = SkTPin(paintColor.fA, 0.f, 1.f); + return { paintAlpha, paintAlpha, paintAlpha, paintAlpha }; + } +} + // Assumes srcRect and dstRect have already been optimized to fit the proxy -static void draw_texture(GrRenderTargetContext* rtc, const GrClip& clip, const SkMatrix& ctm, +static void draw_texture(GrRenderTargetContext* rtc, const GrClip* clip, const SkMatrix& ctm, const SkPaint& paint, const SkRect& srcRect, const SkRect& dstRect, const SkPoint dstClip[4], GrAA aa, GrQuadAAFlags aaFlags, SkCanvas::SrcRectConstraint constraint, GrSurfaceProxyView view, @@ -354,14 +366,8 @@ static void draw_texture(GrRenderTargetContext* rtc, const GrClip& clip, const S constraint = SkCanvas::kStrict_SrcRectConstraint; } } - SkPMColor4f color; - if (GrColorTypeIsAlphaOnly(srcColorInfo.colorType())) { - color = SkColor4fPrepForDst(paint.getColor4f(), dstInfo).premul(); - } else { - float paintAlpha = paint.getColor4f().fA; - color = { paintAlpha, paintAlpha, paintAlpha, paintAlpha }; - } + SkPMColor4f color = texture_color(paint.getColor4f(), 1.f, srcColorInfo.colorType(), dstInfo); if (dstClip) { // Get source coords corresponding to dstClip SkPoint srcQuad[4]; @@ -382,7 +388,7 @@ static void draw_texture(GrRenderTargetContext* rtc, const GrClip& clip, const S // Assumes srcRect and dstRect have already been optimized to fit the proxy. static void draw_texture_producer(GrContext* context, GrRenderTargetContext* rtc, - const GrClip& clip, + const GrClip* clip, const SkMatrixProvider& matrixProvider, const SkPaint& paint, GrTextureProducer* producer, @@ -510,7 +516,7 @@ static void draw_texture_producer(GrContext* context, void draw_tiled_bitmap(GrContext* context, GrRenderTargetContext* rtc, - const GrClip& clip, + const GrClip* clip, const SkBitmap& bitmap, int tileSize, const SkMatrixProvider& matrixProvider, @@ -844,7 +850,9 @@ void SkGpuDevice::drawEdgeAAImageSet(const SkCanvas::ImageSetEntry set[], int co textures[i].fDstClipQuad = clip; textures[i].fPreViewMatrix = set[i].fMatrixIndex < 0 ? nullptr : preViewMatrices + set[i].fMatrixIndex; - textures[i].fAlpha = set[i].fAlpha * paint.getAlphaf(); + textures[i].fColor = texture_color(paint.getColor4f(), set[i].fAlpha, + SkColorTypeToGrColorType(image->colorType()), + fRenderTargetContext->colorInfo()); textures[i].fAAFlags = SkToGrQuadAAFlags(set[i].fAAFlags); if (n > 0 && diff --git a/chromium/third_party/skia/src/gpu/SkGr.cpp b/chromium/third_party/skia/src/gpu/SkGr.cpp index 9c66d396ce7..9b77a281fc5 100644 --- a/chromium/third_party/skia/src/gpu/SkGr.cpp +++ b/chromium/third_party/skia/src/gpu/SkGr.cpp @@ -20,6 +20,7 @@ #include "include/private/SkTemplates.h" #include "src/core/SkAutoMalloc.h" #include "src/core/SkBlendModePriv.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkColorSpacePriv.h" #include "src/core/SkImagePriv.h" #include "src/core/SkMaskFilterBase.h" @@ -48,38 +49,39 @@ #include "src/shaders/SkShaderBase.h" GR_FP_SRC_STRING SKSL_DITHER_SRC = R"( -// This controls the range of values added to color channels -in int rangeType; +// This controls the range of values added to color channels and is based on the destination color +// type; as such it doesn't really affect our program cache to have a variant per-range. +in half range; -void main(float2 p, inout half4 color) { +void main(inout half4 color) { half value; - half range; - @switch (rangeType) { - case 0: - range = 1.0 / 255.0; - break; - case 1: - range = 1.0 / 63.0; - break; - default: - // Experimentally this looks better than the expected value of 1/15. - range = 1.0 / 15.0; - break; - } - @if (sk_Caps.integerSupport) { + @if (sk_Caps.integerSupport) + { // This ordered-dither code is lifted from the cpu backend. - uint x = uint(p.x); - uint y = uint(p.y); + uint x = uint(sk_FragCoord.x); + uint y = uint(sk_FragCoord.y) ^ x; uint m = (y & 1) << 5 | (x & 1) << 4 | (y & 2) << 2 | (x & 2) << 1 | (y & 4) >> 1 | (x & 4) >> 2; value = half(m) * 1.0 / 64.0 - 63.0 / 128.0; } else { - // Simulate the integer effect used above using step/mod. For speed, simulates a 4x4 - // dither pattern rather than an 8x8 one. - half4 modValues = mod(half4(half(p.x), half(p.y), half(p.x), half(p.y)), half4(2.0, 2.0, 4.0, 4.0)); - half4 stepValues = step(modValues, half4(1.0, 1.0, 2.0, 2.0)); - value = dot(stepValues, half4(8.0 / 16.0, 4.0 / 16.0, 2.0 / 16.0, 1.0 / 16.0)) - 15.0 / 32.0; + // Simulate the integer effect used above using step/mod/abs. For speed, simulates a 4x4 + // dither pattern rather than an 8x8 one. Since it's 4x4, this is effectively computing: + // uint m = (y & 1) << 3 | (x & 1) << 2 | + // (y & 2) << 0 | (x & 2) >> 1; + // where 'y' has already been XOR'ed with 'x' as in the integer-supported case. + + // To get the low bit of p.x and p.y, we compute mod 2.0; for the high bit, we mod 4.0 + half4 bits = mod(half4(sk_FragCoord.yxyx), half4(2.0, 2.0, 4.0, 4.0)); + // Use step to convert the 0-3 value in bits.zw into a 0|1 value. bits.xy is already 0|1. + bits.zw = step(2.0, bits.zw); + // bits was constructed such that the p.x bits were already in the right place for + // interleaving (in bits.yw). We just need to update the other bits from p.y to (p.x ^ p.y). + // These are in bits.xz. Since the values are 0|1, we can simulate ^ as abs(y - x). + bits.xz = abs(bits.xz - bits.yw); + + // Manual binary sum, divide by N^2, and offset + value = dot(bits, half4(8.0 / 16.0, 4.0 / 16.0, 2.0 / 16.0, 1.0 / 16.0)) - 15.0 / 32.0; } // For each color channel, add the random offset to the channel value and then clamp // between 0 and alpha to keep the color premultiplied. @@ -198,39 +200,50 @@ static inline bool blend_requires_shader(const SkBlendMode mode) { } #ifndef SK_IGNORE_GPU_DITHER -static inline int32_t dither_range_type_for_config(GrColorType dstColorType) { +static inline float dither_range_for_config(GrColorType dstColorType) { + // We use 1 / (2^bitdepth-1) as the range since each channel can hold 2^bitdepth values switch (dstColorType) { + // 4 bit + case GrColorType::kABGR_4444: + return 1 / 15.f; + // 6 bit + case GrColorType::kBGR_565: + return 1 / 63.f; + // 8 bit case GrColorType::kUnknown: + case GrColorType::kAlpha_8: + case GrColorType::kAlpha_8xxx: case GrColorType::kGray_8: - case GrColorType::kRGBA_8888: - case GrColorType::kRGB_888x: + case GrColorType::kGray_8xxx: + case GrColorType::kR_8: case GrColorType::kRG_88: - case GrColorType::kBGRA_8888: - case GrColorType::kRG_1616: - case GrColorType::kRGBA_16161616: - case GrColorType::kRG_F16: + case GrColorType::kRGB_888: + case GrColorType::kRGB_888x: + case GrColorType::kRGBA_8888: case GrColorType::kRGBA_8888_SRGB: + case GrColorType::kBGRA_8888: + return 1 / 255.f; + // 10 bit case GrColorType::kRGBA_1010102: case GrColorType::kBGRA_1010102: + return 1 / 1023.f; + // 16 bit + case GrColorType::kAlpha_16: + case GrColorType::kR_16: + case GrColorType::kRG_1616: + case GrColorType::kRGBA_16161616: + return 1 / 32767.f; + // Half case GrColorType::kAlpha_F16: - case GrColorType::kRGBA_F32: + case GrColorType::kGray_F16: + case GrColorType::kR_F16: + case GrColorType::kRG_F16: case GrColorType::kRGBA_F16: case GrColorType::kRGBA_F16_Clamped: - case GrColorType::kAlpha_8: - case GrColorType::kAlpha_8xxx: - case GrColorType::kAlpha_16: + // Float case GrColorType::kAlpha_F32xxx: - case GrColorType::kGray_8xxx: - case GrColorType::kRGB_888: - case GrColorType::kR_8: - case GrColorType::kR_16: - case GrColorType::kR_F16: - case GrColorType::kGray_F16: - return 0; - case GrColorType::kBGR_565: - return 1; - case GrColorType::kABGR_4444: - return 2; + case GrColorType::kRGBA_F32: + return 0.f; // no dithering } SkUNREACHABLE; } @@ -250,15 +263,17 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context, // Setup the initial color considering the shader, the SkPaint color, and the presence or not // of per-vertex colors. - std::unique_ptr<GrFragmentProcessor> shaderFP; + std::unique_ptr<GrFragmentProcessor> paintFP; if (!primColorMode || blend_requires_shader(*primColorMode)) { fpArgs.fInputColorIsOpaque = origColor.isOpaque(); if (shaderProcessor) { - shaderFP = std::move(*shaderProcessor); - } else if (const auto* shader = as_SB(skPaint.getShader())) { - shaderFP = shader->asFragmentProcessor(fpArgs); - if (!shaderFP) { - return false; + paintFP = std::move(*shaderProcessor); + } else { + if (const SkShaderBase* shader = as_SB(skPaint.getShader())) { + paintFP = shader->asFragmentProcessor(fpArgs); + if (paintFP == nullptr) { + return false; + } } } } @@ -267,7 +282,7 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context, // a known constant value. In that case we can simply apply a color filter during this // conversion without converting the color filter to a GrFragmentProcessor. bool applyColorFilterToPaintColor = false; - if (shaderFP) { + if (paintFP) { if (primColorMode) { // There is a blend between the primitive color and the shader color. The shader sees // the opaque paint color. The shader's output is blended using the provided mode by @@ -277,43 +292,33 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context, // the GrPaint color will be ignored. SkPMColor4f shaderInput = origColor.makeOpaque().premul(); - shaderFP = GrFragmentProcessor::OverrideInput(std::move(shaderFP), shaderInput); - shaderFP = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(shaderFP), - *primColorMode); - - // The above may return null if compose results in a pass through of the prim color. - if (shaderFP) { - grPaint->addColorFragmentProcessor(std::move(shaderFP)); - } + paintFP = GrFragmentProcessor::OverrideInput(std::move(paintFP), shaderInput); + paintFP = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(paintFP), + *primColorMode); // We can ignore origColor here - alpha is unchanged by gamma float paintAlpha = skPaint.getColor4f().fA; if (1.0f != paintAlpha) { // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all // color channels. It's value should be treated as the same in ANY color space. - grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make( - { paintAlpha, paintAlpha, paintAlpha, paintAlpha }, - GrConstColorProcessor::InputMode::kModulateRGBA)); + paintFP = GrConstColorProcessor::Make( + std::move(paintFP), { paintAlpha, paintAlpha, paintAlpha, paintAlpha }, + GrConstColorProcessor::InputMode::kModulateRGBA); } } else { // The shader's FP sees the paint *unpremul* color SkPMColor4f origColorAsPM = { origColor.fR, origColor.fG, origColor.fB, origColor.fA }; grPaint->setColor4f(origColorAsPM); - grPaint->addColorFragmentProcessor(std::move(shaderFP)); } } else { if (primColorMode) { // There is a blend between the primitive color and the paint color. The blend considers // the opaque paint color. The paint's alpha is applied to the post-blended color. SkPMColor4f opaqueColor = origColor.makeOpaque().premul(); - auto processor = GrConstColorProcessor::Make(opaqueColor, - GrConstColorProcessor::InputMode::kIgnore); - processor = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(processor), - *primColorMode); - if (processor) { - grPaint->addColorFragmentProcessor(std::move(processor)); - } - + paintFP = GrConstColorProcessor::Make(/*inputFP=*/nullptr, opaqueColor, + GrConstColorProcessor::InputMode::kIgnore); + paintFP = GrXfermodeFragmentProcessor::MakeFromSrcProcessor(std::move(paintFP), + *primColorMode); grPaint->setColor4f(opaqueColor); // We can ignore origColor here - alpha is unchanged by gamma @@ -321,9 +326,9 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context, if (1.0f != paintAlpha) { // No gamut conversion - paintAlpha is a (linear) alpha value, splatted to all // color channels. It's value should be treated as the same in ANY color space. - grPaint->addColorFragmentProcessor(GrConstColorProcessor::Make( - { paintAlpha, paintAlpha, paintAlpha, paintAlpha }, - GrConstColorProcessor::InputMode::kModulateRGBA)); + paintFP = GrConstColorProcessor::Make( + std::move(paintFP), { paintAlpha, paintAlpha, paintAlpha, paintAlpha }, + GrConstColorProcessor::InputMode::kModulateRGBA); } } else { // No shader, no primitive color. @@ -332,13 +337,17 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context, } } + if (paintFP) { + grPaint->addColorFragmentProcessor(std::move(paintFP)); + } + SkColorFilter* colorFilter = skPaint.getColorFilter(); if (colorFilter) { if (applyColorFilterToPaintColor) { SkColorSpace* dstCS = dstColorInfo.colorSpace(); grPaint->setColor4f(colorFilter->filterColor4f(origColor, dstCS, dstCS).premul()); } else { - auto cfFP = colorFilter->asFragmentProcessor(context, dstColorInfo); + auto cfFP = as_CFB(colorFilter)->asFragmentProcessor(context, dstColorInfo); if (cfFP) { grPaint->addColorFragmentProcessor(std::move(cfFP)); } else { @@ -367,12 +376,15 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context, GrColorType ct = dstColorInfo.colorType(); if (SkPaintPriv::ShouldDither(skPaint, GrColorTypeToSkColorType(ct)) && grPaint->numColorFragmentProcessors() > 0) { - int32_t ditherRange = dither_range_type_for_config(ct); - if (ditherRange >= 0) { + float ditherRange = dither_range_for_config(ct); + if (ditherRange > 0.f) { static auto effect = std::get<0>(SkRuntimeEffect::Make(SkString(SKSL_DITHER_SRC))); auto ditherFP = GrSkSLFP::Make(context, effect, "Dither", SkData::MakeWithCopy(&ditherRange, sizeof(ditherRange))); if (ditherFP) { + // The dither shader doesn't actually use input coordinates, but if we don't set + // this flag, the generated shader includes an extra local coord varying. + ditherFP->temporary_SetExplicitlySampled(); grPaint->addColorFragmentProcessor(std::move(ditherFP)); } } @@ -380,7 +392,8 @@ static inline bool skpaint_to_grpaint_impl(GrRecordingContext* context, #endif if (GrColorTypeClampType(dstColorInfo.colorType()) == GrClampType::kManual) { if (grPaint->numColorFragmentProcessors()) { - grPaint->addColorFragmentProcessor(GrClampFragmentProcessor::Make(false)); + grPaint->addColorFragmentProcessor( + GrClampFragmentProcessor::Make(/*inputFP=*/nullptr, /*clampToPremul=*/false)); } else { auto color = grPaint->getColor4f(); grPaint->setColor4f({SkTPin(color.fR, 0.f, 1.f), diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCCAtlas.cpp b/chromium/third_party/skia/src/gpu/ccpr/GrCCAtlas.cpp index a980f688841..8cf105e6740 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCCAtlas.cpp +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCCAtlas.cpp @@ -7,6 +7,7 @@ #include "src/gpu/ccpr/GrCCAtlas.h" +#include "src/core/SkIPoint16.h" #include "src/gpu/GrOnFlushResourceProvider.h" #include "src/gpu/ccpr/GrCCPathCache.h" @@ -84,13 +85,16 @@ sk_sp<GrCCCachedAtlas> GrCCAtlas::refOrMakeCachedAtlas(GrOnFlushResourceProvider GrCCAtlas* GrCCAtlasStack::addRect(const SkIRect& devIBounds, SkIVector* devToAtlasOffset) { GrCCAtlas* retiredAtlas = nullptr; - if (fAtlases.empty() || !fAtlases.back().addRect(devIBounds, devToAtlasOffset)) { + SkIPoint16 location; + if (fAtlases.empty() || + !fAtlases.back().addRect(devIBounds.width(), devIBounds.height(), &location)) { // The retired atlas is out of room and can't grow any bigger. retiredAtlas = !fAtlases.empty() ? &fAtlases.back() : nullptr; fAtlases.emplace_back(fCoverageType, fSpecs, *fCaps); SkASSERT(devIBounds.width() <= fSpecs.fMinWidth); SkASSERT(devIBounds.height() <= fSpecs.fMinHeight); - SkAssertResult(fAtlases.back().addRect(devIBounds, devToAtlasOffset)); + SkAssertResult(fAtlases.back().addRect(devIBounds.width(), devIBounds.height(), &location)); } + devToAtlasOffset->set(location.x() - devIBounds.left(), location.y() - devIBounds.top()); return retiredAtlas; } diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCCClipPath.cpp b/chromium/third_party/skia/src/gpu/ccpr/GrCCClipPath.cpp index b2a2c07f833..36ba5f8383e 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCCClipPath.cpp +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCCClipPath.cpp @@ -21,23 +21,19 @@ void GrCCClipPath::init( fAtlasLazyProxy = GrCCAtlas::MakeLazyAtlasProxy( [this](GrResourceProvider* resourceProvider, const GrCCAtlas::LazyAtlasDesc& desc) { SkASSERT(fHasAtlas); - SkASSERT(!fHasAtlasTransform); + SkASSERT(!fHasAtlasTranslate); GrTextureProxy* textureProxy = fAtlas ? fAtlas->textureProxy() : nullptr; if (!textureProxy || !textureProxy->instantiate(resourceProvider)) { - fAtlasScale = fAtlasTranslate = {0, 0}; - SkDEBUGCODE(fHasAtlasTransform = true); + SkDEBUGCODE(fHasAtlasTranslate = true); return GrSurfaceProxy::LazyCallbackResult(); } sk_sp<GrTexture> texture = sk_ref_sp(textureProxy->peekTexture()); SkASSERT(texture); - fAtlasScale = {1.f / texture->width(), 1.f / texture->height()}; - fAtlasTranslate.set(fDevToAtlasOffset.fX * fAtlasScale.x(), - fDevToAtlasOffset.fY * fAtlasScale.y()); - SkDEBUGCODE(fHasAtlasTransform = true); + SkDEBUGCODE(fHasAtlasTranslate = true); // We use LazyInstantiationKeyMode::kUnsynced here because CCPR clip masks are never // cached, and the clip FP proxies need to ignore any unique keys that atlas diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCCClipPath.h b/chromium/third_party/skia/src/gpu/ccpr/GrCCClipPath.h index 0f3fef20583..c0ec06c47b1 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCCClipPath.h +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCCClipPath.h @@ -62,8 +62,10 @@ public: void accountForOwnPath(GrCCPerFlushResourceSpecs*) const; void renderPathInAtlas(GrCCPerFlushResources*, GrOnFlushResourceProvider*); - const SkVector& atlasScale() const { SkASSERT(fHasAtlasTransform); return fAtlasScale; } - const SkVector& atlasTranslate() const { SkASSERT(fHasAtlasTransform); return fAtlasTranslate; } + const SkIVector& atlasTranslate() const { + SkASSERT(fHasAtlasTranslate); + return fDevToAtlasOffset; + } private: sk_sp<GrTextureProxy> fAtlasLazyProxy; @@ -74,10 +76,7 @@ private: const GrCCAtlas* fAtlas = nullptr; SkIVector fDevToAtlasOffset; // Translation from device space to location in atlas. SkDEBUGCODE(bool fHasAtlas = false;) - - SkVector fAtlasScale; - SkVector fAtlasTranslate; - SkDEBUGCODE(bool fHasAtlasTransform = false;) + SkDEBUGCODE(bool fHasAtlasTranslate = false;) }; #endif diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCCClipProcessor.cpp b/chromium/third_party/skia/src/gpu/ccpr/GrCCClipProcessor.cpp index 9eed783219f..718985ac5fb 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCCClipProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCCClipProcessor.cpp @@ -7,9 +7,8 @@ #include "src/gpu/ccpr/GrCCClipProcessor.h" -#include "src/gpu/GrTexture.h" -#include "src/gpu/GrTextureProxy.h" #include "src/gpu/ccpr/GrCCClipPath.h" +#include "src/gpu/effects/GrTextureEffect.h" #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" @@ -20,30 +19,34 @@ static GrSurfaceProxyView make_view(const GrCaps& caps, GrSurfaceProxy* proxy, return { sk_ref_sp(proxy), GrCCAtlas::kTextureOrigin, swizzle }; } -GrCCClipProcessor::GrCCClipProcessor(GrSurfaceProxyView view, const GrCCClipPath* clipPath, +GrCCClipProcessor::GrCCClipProcessor(std::unique_ptr<GrFragmentProcessor> inputFP, + const GrCaps& caps, + const GrCCClipPath* clipPath, IsCoverageCount isCoverageCount, MustCheckBounds mustCheckBounds) : INHERITED(kGrCCClipProcessor_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag) , fClipPath(clipPath) , fIsCoverageCount(IsCoverageCount::kYes == isCoverageCount) - , fMustCheckBounds(MustCheckBounds::kYes == mustCheckBounds) - , fAtlasAccess(std::move(view)) { - SkASSERT(fAtlasAccess.view()); - this->setTextureSamplerCnt(1); + , fMustCheckBounds(MustCheckBounds::kYes == mustCheckBounds) { + auto view = make_view(caps, clipPath->atlasLazyProxy(), fIsCoverageCount); + auto texEffect = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType); + this->registerExplicitlySampledChild(std::move(texEffect)); + + if (inputFP != nullptr) { + this->registerChild(std::move(inputFP)); + } } -GrCCClipProcessor::GrCCClipProcessor(const GrCaps& caps, const GrCCClipPath* clipPath, - IsCoverageCount isCoverageCount, - MustCheckBounds mustCheckBounds) - : GrCCClipProcessor(make_view(caps, clipPath->atlasLazyProxy(), - IsCoverageCount::kYes == isCoverageCount), - clipPath, isCoverageCount, mustCheckBounds) { +GrCCClipProcessor::GrCCClipProcessor(const GrCCClipProcessor& that) + : INHERITED(kGrCCClipProcessor_ClassID, that.optimizationFlags()) + , fClipPath(that.fClipPath) + , fIsCoverageCount(that.fIsCoverageCount) + , fMustCheckBounds(that.fMustCheckBounds) { + this->cloneAndRegisterAllChildProcessors(that); } std::unique_ptr<GrFragmentProcessor> GrCCClipProcessor::clone() const { - return std::make_unique<GrCCClipProcessor>( - fAtlasAccess.view(), fClipPath, IsCoverageCount(fIsCoverageCount), - MustCheckBounds(fMustCheckBounds)); + return std::unique_ptr<GrFragmentProcessor>(new GrCCClipProcessor(*this)); } void GrCCClipProcessor::onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const { @@ -56,15 +59,19 @@ void GrCCClipProcessor::onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKe bool GrCCClipProcessor::onIsEqual(const GrFragmentProcessor& fp) const { const GrCCClipProcessor& that = fp.cast<GrCCClipProcessor>(); - // Each ClipPath path has a unique atlas proxy, so hasSameSamplersAndAccesses should have - // already weeded out FPs with different ClipPaths. - SkASSERT(that.fClipPath->deviceSpacePath().getGenerationID() == - fClipPath->deviceSpacePath().getGenerationID()); - return that.fClipPath->deviceSpacePath().getFillType() == + return that.fClipPath->deviceSpacePath().getGenerationID() == + fClipPath->deviceSpacePath().getGenerationID() && + that.fClipPath->deviceSpacePath().getFillType() == fClipPath->deviceSpacePath().getFillType() && that.fIsCoverageCount == fIsCoverageCount && that.fMustCheckBounds == fMustCheckBounds; } +bool GrCCClipProcessor::hasInputFP() const { + // We always have a `texEffect`, and this accounts for one child. + // The second child will be the input FP, if we have one. + return this->numChildProcessors() > 1; +} + class GrCCClipProcessor::Impl : public GrGLSLFragmentProcessor { public: void emitCode(EmitArgs& args) override { @@ -72,7 +79,7 @@ public: GrGLSLUniformHandler* uniHandler = args.fUniformHandler; GrGLSLFPFragmentBuilder* f = args.fFragBuilder; - f->codeAppend ("half coverage;"); + f->codeAppend("half coverage;"); if (proc.fMustCheckBounds) { const char* pathIBounds; @@ -84,39 +91,43 @@ public: pathIBounds, pathIBounds); } - const char* atlasTransform; - fAtlasTransformUniform = uniHandler->addUniform(&proc, kFragment_GrShaderFlag, - kFloat4_GrSLType, "atlas_transform", - &atlasTransform); - f->codeAppendf("float2 texcoord = sk_FragCoord.xy * %s.xy + %s.zw;", - atlasTransform, atlasTransform); - - f->codeAppend ("coverage = "); - f->appendTextureLookup(args.fTexSamplers[0], "texcoord"); - f->codeAppend (".a;"); + const char* atlasTranslate; + fAtlasTranslateUniform = uniHandler->addUniform(&proc, kFragment_GrShaderFlag, + kFloat2_GrSLType, "atlas_translate", + &atlasTranslate); + SkString coord; + coord.printf("sk_FragCoord.xy + %s.xy", atlasTranslate); + constexpr int kTexEffectFPIndex = 0; + SkString sample = this->invokeChild(kTexEffectFPIndex, args, coord.c_str()); + f->codeAppendf("coverage = %s.a;", sample.c_str()); if (proc.fIsCoverageCount) { auto fillRule = GrFillRuleForSkPath(proc.fClipPath->deviceSpacePath()); if (GrFillRule::kEvenOdd == fillRule) { - f->codeAppend ("half t = mod(abs(coverage), 2);"); - f->codeAppend ("coverage = 1 - abs(t - 1);"); + f->codeAppend("half t = mod(abs(coverage), 2);"); + f->codeAppend("coverage = 1 - abs(t - 1);"); } else { SkASSERT(GrFillRule::kNonzero == fillRule); - f->codeAppend ("coverage = min(abs(coverage), 1);"); + f->codeAppend("coverage = min(abs(coverage), 1);"); } } if (proc.fMustCheckBounds) { - f->codeAppend ("} else {"); - f->codeAppend ( "coverage = 0;"); - f->codeAppend ("}"); + f->codeAppend("} else {"); + f->codeAppend( "coverage = 0;"); + f->codeAppend("}"); } if (proc.fClipPath->deviceSpacePath().isInverseFillType()) { - f->codeAppend ("coverage = 1 - coverage;"); + f->codeAppend("coverage = 1 - coverage;"); } - f->codeAppendf("%s = %s * coverage;", args.fOutputColor, args.fInputColor); + constexpr int kInputFPIndex = 1; + SkString inputColor = proc.hasInputFP() + ? this->invokeChild(kInputFPIndex, args.fInputColor, args) + : SkString(args.fInputColor); + + f->codeAppendf("%s = %s * coverage;", args.fOutputColor, inputColor.c_str()); } void onSetData(const GrGLSLProgramDataManager& pdman, @@ -127,14 +138,13 @@ public: pdman.set4f(fPathIBoundsUniform, pathIBounds.left(), pathIBounds.top(), pathIBounds.right(), pathIBounds.bottom()); } - const SkVector& scale = proc.fClipPath->atlasScale(); - const SkVector& trans = proc.fClipPath->atlasTranslate(); - pdman.set4f(fAtlasTransformUniform, scale.x(), scale.y(), trans.x(), trans.y()); + const SkIVector& trans = proc.fClipPath->atlasTranslate(); + pdman.set2f(fAtlasTranslateUniform, trans.x(), trans.y()); } private: UniformHandle fPathIBoundsUniform; - UniformHandle fAtlasTransformUniform; + UniformHandle fAtlasTranslateUniform; }; GrGLSLFragmentProcessor* GrCCClipProcessor::onCreateGLSLInstance() const { diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCCClipProcessor.h b/chromium/third_party/skia/src/gpu/ccpr/GrCCClipProcessor.h index d7eae5e5bc1..536bb8ed214 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCCClipProcessor.h +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCCClipProcessor.h @@ -24,21 +24,22 @@ public: kYes = true }; - GrCCClipProcessor(GrSurfaceProxyView, const GrCCClipPath*, IsCoverageCount, MustCheckBounds); - GrCCClipProcessor(const GrCaps&, const GrCCClipPath*, IsCoverageCount, MustCheckBounds); + GrCCClipProcessor(std::unique_ptr<GrFragmentProcessor>, const GrCaps&, const GrCCClipPath*, + IsCoverageCount, MustCheckBounds); const char* name() const override { return "GrCCClipProcessor"; } std::unique_ptr<GrFragmentProcessor> clone() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; - const TextureSampler& onTextureSampler(int) const override { return fAtlasAccess; } + bool hasInputFP() const; private: + explicit GrCCClipProcessor(const GrCCClipProcessor&); + const GrCCClipPath* const fClipPath; const bool fIsCoverageCount; const bool fMustCheckBounds; - const TextureSampler fAtlasAccess; class Impl; diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCCFiller.cpp b/chromium/third_party/skia/src/gpu/ccpr/GrCCFiller.cpp index ee9520f83be..9b30a708cd5 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCCFiller.cpp +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCCFiller.cpp @@ -433,7 +433,7 @@ bool GrCCFiller::prepareToDraw(GrOnFlushResourceProvider* onFlushRP) { SkASSERT(!currFan.empty()); currFan.pop_back(); } - // fallthru. + [[fallthrough]]; case Verb::kEndOpenContour: // endPt != startPt. SkASSERT(!currFanIsTessellated || currFan.empty()); if (!currFanIsTessellated && currFan.count() >= 3) { diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCCPathProcessor.cpp b/chromium/third_party/skia/src/gpu/ccpr/GrCCPathProcessor.cpp index d4c1d8be466..e5c99c01a78 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCCPathProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCCPathProcessor.cpp @@ -103,6 +103,10 @@ class GrCCPathProcessor::Impl : public GrGLSLGeometryProcessor { public: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override; + static void GenKey(const GrCCPathProcessor& cc, GrProcessorKeyBuilder* b) { + b->add32(AddMatrixKeys((uint32_t) cc.fCoverageMode, SkMatrix::I(), cc.fLocalMatrix)); + } + private: void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc, const CoordTransformRange& transformRange) override { @@ -110,14 +114,21 @@ private: pdman.set2f(fAtlasAdjustUniform, 1.0f / proc.fAtlasDimensions.fWidth, 1.0f / proc.fAtlasDimensions.fHeight); - this->setTransformDataHelper(proc.fLocalMatrix, pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); + this->setTransform(pdman, fLocalMatrixUni, proc.fLocalMatrix, &fLocalMatrix); } GrGLSLUniformHandler::UniformHandle fAtlasAdjustUniform; + GrGLSLUniformHandler::UniformHandle fLocalMatrixUni; + SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix(); typedef GrGLSLGeometryProcessor INHERITED; }; +void GrCCPathProcessor::getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const { + GrCCPathProcessor::Impl::GenKey(*this, b); +} + GrGLSLPrimitiveProcessor* GrCCPathProcessor::createGLSLInstance(const GrShaderCaps&) const { return new Impl(); } @@ -218,8 +229,8 @@ void GrCCPathProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { } gpArgs->fPositionVar.set(kFloat2_GrSLType, "octocoord"); - this->emitTransforms(v, varyingHandler, uniHandler, gpArgs->fPositionVar, proc.fLocalMatrix, - args.fFPCoordTransformHandler); + this->writeLocalCoord(v, args.fUniformHandler, gpArgs, gpArgs->fPositionVar, proc.fLocalMatrix, + &fLocalMatrixUni); // Fragment shader. GrGLSLFPFragmentBuilder* f = args.fFragBuilder; diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCCPathProcessor.h b/chromium/third_party/skia/src/gpu/ccpr/GrCCPathProcessor.h index cb5f22770ef..789ac2e3ff6 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCCPathProcessor.h +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCCPathProcessor.h @@ -64,9 +64,8 @@ public: const SkMatrix& viewMatrixIfUsingLocalCoords = SkMatrix::I()); const char* name() const override { return "GrCCPathProcessor"; } - void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { - b->add32((uint32_t)fCoverageMode); - } + void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; void drawPaths(GrOpFlushState*, const GrPipeline&, const GrSurfaceProxy& atlasProxy, diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCCPerFlushResources.cpp b/chromium/third_party/skia/src/gpu/ccpr/GrCCPerFlushResources.cpp index 9101b1d84c4..d13a52a28f6 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCCPerFlushResources.cpp +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCCPerFlushResources.cpp @@ -8,7 +8,6 @@ #include "src/gpu/ccpr/GrCCPerFlushResources.h" #include "include/private/GrRecordingContext.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrMemoryPool.h" #include "src/gpu/GrOnFlushResourceProvider.h" #include "src/gpu/GrRecordingContextPriv.h" @@ -97,8 +96,10 @@ public: GrCCPathProcessor pathProc(coverageMode, fSrcProxy->peekTexture(), swizzle, GrCCAtlas::kTextureOrigin); - GrPipeline pipeline(GrScissorTest::kDisabled, SkBlendMode::kSrc, - flushState->drawOpArgs().writeSwizzle()); + bool hasScissor = flushState->appliedClip() && + flushState->appliedClip()->scissorState().enabled(); + GrPipeline pipeline(hasScissor ? GrScissorTest::kEnabled : GrScissorTest::kDisabled, + SkBlendMode::kSrc, flushState->drawOpArgs().writeSwizzle()); pathProc.drawPaths(flushState, pipeline, *fSrcProxy, *fResources, fBaseInstance, fEndInstance, this->bounds()); @@ -541,7 +542,7 @@ bool GrCCPerFlushResources::finalize(GrOnFlushResourceProvider* onFlushRP) { auto op = CopyAtlasOp::Make( rtc->surfPriv().getContext(), sk_ref_sp(this), copyRange.fSrcProxy, baseCopyInstance, endCopyInstance, atlas.drawBounds()); - rtc->addDrawOp(GrNoClip(), std::move(op)); + rtc->addDrawOp(nullptr, std::move(op)); } baseCopyInstance = endCopyInstance; } @@ -580,7 +581,7 @@ bool GrCCPerFlushResources::finalize(GrOnFlushResourceProvider* onFlushRP) { rtc->surfPriv().getContext(), sk_ref_sp(this), atlas.getFillBatchID(), atlas.getStrokeBatchID(), atlas.drawBounds()); } - rtc->addDrawOp(GrNoClip(), std::move(op)); + rtc->addDrawOp(nullptr, std::move(op)); if (rtc->asSurfaceProxy()->requiresManualMSAAResolve()) { onFlushRP->addTextureResolveTask(sk_ref_sp(rtc->asTextureProxy()), GrSurfaceProxy::ResolveFlags::kMSAA); diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCCStroker.cpp b/chromium/third_party/skia/src/gpu/ccpr/GrCCStroker.cpp index 44f3db3362f..bb09fe4c612 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCCStroker.cpp +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCCStroker.cpp @@ -103,7 +103,6 @@ private: void LinearStrokeProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; - GrGLSLUniformHandler* uniHandler = args.fUniformHandler; varyingHandler->emitAttributes(args.fGP.cast<LinearStrokeProcessor>()); @@ -137,8 +136,7 @@ void LinearStrokeProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { edgeDistances.vsOut(), edgeDistances.vsOut(), edgeDistances.vsOut()); gpArgs->fPositionVar.set(kFloat2_GrSLType, "position"); - this->emitTransforms(v, varyingHandler, uniHandler, GrShaderVar("position", kFloat2_GrSLType), - SkMatrix::I(), args.fFPCoordTransformHandler); + // Leave fLocalCoordVar uninitialized; this GP is not combined with frag processors // Use the 4 edge distances to calculate coverage in the fragment shader. GrGLSLFPFragmentBuilder* f = args.fFragBuilder; @@ -194,7 +192,6 @@ private: void CubicStrokeProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; - GrGLSLUniformHandler* uniHandler = args.fUniformHandler; varyingHandler->emitAttributes(args.fGP.cast<CubicStrokeProcessor>()); @@ -259,8 +256,7 @@ void CubicStrokeProcessor::Impl::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { coverages.vsOut()); gpArgs->fPositionVar.set(kFloat2_GrSLType, "position"); - this->emitTransforms(v, varyingHandler, uniHandler, GrShaderVar("position", kFloat2_GrSLType), - SkMatrix::I(), args.fFPCoordTransformHandler); + // Leave fLocalCoordVar uninitialized; this GP is not combined with frag processors // Use the 2 edge distances and interpolated butt cap AA to calculate fragment coverage. GrGLSLFPFragmentBuilder* f = args.fFragBuilder; @@ -649,10 +645,10 @@ bool GrCCStroker::prepareToDraw(GrOnFlushResourceProvider* onFlushRP) { case Verb::kRoundJoin: case Verb::kInternalRoundJoin: conicWeight = params[paramsIdx++].fConicWeight; - // fallthru + [[fallthrough]]; case Verb::kMiterJoin: miterCapHeightOverWidth = params[paramsIdx++].fMiterCapHeightOverWidth; - // fallthru + [[fallthrough]]; case Verb::kBevelJoin: case Verb::kInternalBevelJoin: builder.appendJoin(verb, pts[ptsIdx], normals[normalsIdx], normals[normalsIdx + 1], diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp b/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp index bc56c5de6e4..5f66c6e442e 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer.cpp @@ -9,8 +9,8 @@ #include "include/pathops/SkPathOps.h" #include "src/gpu/GrCaps.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrProxyProvider.h" +#include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/ccpr/GrCCClipProcessor.h" #include "src/gpu/ccpr/GrCCDrawPathsOp.h" #include "src/gpu/ccpr/GrCCPathCache.h" @@ -136,7 +136,7 @@ GrPathRenderer::CanDrawPath GrCoverageCountingPathRenderer::onCanDrawPath( // defined relative to device space. return CanDrawPath::kNo; } - // fallthru + [[fallthrough]]; case SkStrokeRec::kHairline_Style: { if (CoverageType::kFP16_CoverageCount != fCoverageType) { // Stroking is not yet supported in MSAA atlas mode. @@ -167,11 +167,8 @@ GrPathRenderer::CanDrawPath GrCoverageCountingPathRenderer::onCanDrawPath( bool GrCoverageCountingPathRenderer::onDrawPath(const DrawPathArgs& args) { SkASSERT(!fFlushing); - GrRenderTargetContext* rtc = args.fRenderTargetContext; - SkIRect clipIBounds = args.fClip->getConservativeBounds(rtc->width(), rtc->height()); - - auto op = GrCCDrawPathsOp::Make(args.fContext, clipIBounds, *args.fViewMatrix, *args.fShape, - std::move(args.fPaint)); + auto op = GrCCDrawPathsOp::Make(args.fContext, *args.fClipConservativeBounds, *args.fViewMatrix, + *args.fShape, std::move(args.fPaint)); this->recordOp(std::move(op), args); return true; } @@ -183,14 +180,14 @@ void GrCoverageCountingPathRenderer::recordOp(std::unique_ptr<GrCCDrawPathsOp> o op->cast<GrCCDrawPathsOp>()->addToOwningPerOpsTaskPaths( sk_ref_sp(this->lookupPendingPaths(opsTaskID))); }; - args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op), + args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op), addToOwningPerOpsTaskPaths); } } std::unique_ptr<GrFragmentProcessor> GrCoverageCountingPathRenderer::makeClipProcessor( - uint32_t opsTaskID, const SkPath& deviceSpacePath, const SkIRect& accessRect, - const GrCaps& caps) { + std::unique_ptr<GrFragmentProcessor> inputFP, uint32_t opsTaskID, + const SkPath& deviceSpacePath, const SkIRect& accessRect, const GrCaps& caps) { SkASSERT(!fFlushing); uint32_t key = deviceSpacePath.getGenerationID(); @@ -221,7 +218,8 @@ std::unique_ptr<GrFragmentProcessor> GrCoverageCountingPathRenderer::makeClipPro CoverageType::kFP16_CoverageCount == fCoverageType); auto mustCheckBounds = GrCCClipProcessor::MustCheckBounds( !clipPath.pathDevIBounds().contains(accessRect)); - return std::make_unique<GrCCClipProcessor>(caps, &clipPath, isCoverageCount, mustCheckBounds); + return std::make_unique<GrCCClipProcessor>( + std::move(inputFP), caps, &clipPath, isCoverageCount, mustCheckBounds); } void GrCoverageCountingPathRenderer::preFlush( diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer.h b/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer.h index a3107057b44..e5e09472f00 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer.h +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer.h @@ -63,8 +63,8 @@ public: } std::unique_ptr<GrFragmentProcessor> makeClipProcessor( - uint32_t oplistID, const SkPath& deviceSpacePath, const SkIRect& accessRect, - const GrCaps&); + std::unique_ptr<GrFragmentProcessor> inputFP, uint32_t opsTaskID, + const SkPath& deviceSpacePath, const SkIRect& accessRect, const GrCaps& caps); // GrOnFlushCallbackObject overrides. void preFlush(GrOnFlushResourceProvider*, const uint32_t* opsTaskIDs, diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer_none.cpp b/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer_none.cpp index 1b2a55e0e70..72d443c6949 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer_none.cpp +++ b/chromium/third_party/skia/src/gpu/ccpr/GrCoverageCountingPathRenderer_none.cpp @@ -17,7 +17,7 @@ sk_sp<GrCoverageCountingPathRenderer> GrCoverageCountingPathRenderer::CreateIfSu } std::unique_ptr<GrFragmentProcessor> GrCoverageCountingPathRenderer::makeClipProcessor( - uint32_t opsTaskID, const SkPath& deviceSpacePath, const SkIRect& accessRect, - const GrCaps& caps) { + std::unique_ptr<GrFragmentProcessor> inputFP, uint32_t opsTaskID, + const SkPath& deviceSpacePath, const SkIRect& accessRect, const GrCaps& caps) { return nullptr; } diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrGSCoverageProcessor.cpp b/chromium/third_party/skia/src/gpu/ccpr/GrGSCoverageProcessor.cpp index feaac1a1439..44e2def7264 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrGSCoverageProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/ccpr/GrGSCoverageProcessor.cpp @@ -25,7 +25,7 @@ protected: void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&, const CoordTransformRange& transformRange) final { - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); } void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) final { diff --git a/chromium/third_party/skia/src/gpu/ccpr/GrVSCoverageProcessor.cpp b/chromium/third_party/skia/src/gpu/ccpr/GrVSCoverageProcessor.cpp index ee3ce647edb..0270cbf89af 100644 --- a/chromium/third_party/skia/src/gpu/ccpr/GrVSCoverageProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/ccpr/GrVSCoverageProcessor.cpp @@ -20,7 +20,7 @@ public: private: void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&, const CoordTransformRange& transformRange) final { - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); } void onEmitCode(EmitArgs&, GrGPArgs*) override; diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DAttachmentViewManager.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DAttachmentViewManager.cpp deleted file mode 100644 index 7536f590918..00000000000 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DAttachmentViewManager.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2020 Google LLC - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "src/gpu/d3d/GrD3DAttachmentViewManager.h" - -#include "src/gpu/d3d/GrD3DGpu.h" - -GrD3DAttachmentViewManager::GrD3DAttachmentViewManager(GrD3DGpu* gpu) - : fRTVDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_RTV) - , fDSVDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_DSV) {} - -D3D12_CPU_DESCRIPTOR_HANDLE GrD3DAttachmentViewManager::createRenderTargetView( - GrD3DGpu* gpu, ID3D12Resource* textureResource) { - D3D12_CPU_DESCRIPTOR_HANDLE descriptor = fRTVDescriptorPool.allocateHandle(gpu); - gpu->device()->CreateRenderTargetView(textureResource, nullptr, descriptor); - return descriptor; -} - -void GrD3DAttachmentViewManager::recycleRenderTargetView( - D3D12_CPU_DESCRIPTOR_HANDLE* rtvDescriptor) { - fRTVDescriptorPool.releaseHandle(rtvDescriptor); -} - -D3D12_CPU_DESCRIPTOR_HANDLE GrD3DAttachmentViewManager::createDepthStencilView( - GrD3DGpu* gpu, ID3D12Resource* textureResource) { - D3D12_CPU_DESCRIPTOR_HANDLE descriptor = fDSVDescriptorPool.allocateHandle(gpu); - gpu->device()->CreateDepthStencilView(textureResource, nullptr, descriptor); - return descriptor; -} - -void GrD3DAttachmentViewManager::recycleDepthStencilView( - D3D12_CPU_DESCRIPTOR_HANDLE* dsvDescriptor) { - fDSVDescriptorPool.releaseHandle(dsvDescriptor); -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -std::unique_ptr<GrD3DAttachmentViewManager::Heap> GrD3DAttachmentViewManager::Heap::Make( - GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE type, unsigned int numDescriptors) { - std::unique_ptr<GrD3DDescriptorHeap> heap = - GrD3DDescriptorHeap::Make(gpu, type, numDescriptors, D3D12_DESCRIPTOR_HEAP_FLAG_NONE); - if (!heap) { - return nullptr; - } - - return std::unique_ptr<Heap>(new Heap(heap, numDescriptors)); - -} - -D3D12_CPU_DESCRIPTOR_HANDLE GrD3DAttachmentViewManager::Heap::allocateCPUHandle() { - SkBitSet::OptionalIndex freeBlock = fFreeBlocks.findFirst(); - SkASSERT(freeBlock); - fFreeBlocks.reset(*freeBlock); - --fFreeCount; - return fHeap->getCPUHandle(*freeBlock); -} - -bool GrD3DAttachmentViewManager::Heap::freeCPUHandle(D3D12_CPU_DESCRIPTOR_HANDLE* handle) { - size_t index; - if (!fHeap->getIndex(*handle, &index)) { - return false; - } - fFreeBlocks.set(index); - ++fFreeCount; - handle->ptr = 0; - return true; -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -GrD3DAttachmentViewManager::HeapPool::HeapPool(GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE heapType) - : fMaxAvailableDescriptors(32) - , fHeapType(heapType) { - std::unique_ptr<GrD3DAttachmentViewManager::Heap> heap = - GrD3DAttachmentViewManager::Heap::Make(gpu, fHeapType, fMaxAvailableDescriptors); - fDescriptorHeaps.push_back(std::move(heap)); -} - -D3D12_CPU_DESCRIPTOR_HANDLE GrD3DAttachmentViewManager::HeapPool::allocateHandle(GrD3DGpu* gpu) { - for (unsigned int i = 0; i < fDescriptorHeaps.size(); ++i) { - if (fDescriptorHeaps[i]->canAllocate()) { - D3D12_CPU_DESCRIPTOR_HANDLE handle = fDescriptorHeaps[i]->allocateCPUHandle(); - return handle; - } - } - - // need to allocate more space - std::unique_ptr<GrD3DAttachmentViewManager::Heap> heap = - GrD3DAttachmentViewManager::Heap::Make(gpu, fHeapType, fMaxAvailableDescriptors); - - fDescriptorHeaps.push_back(std::move(heap)); - fMaxAvailableDescriptors *= 2; - D3D12_CPU_DESCRIPTOR_HANDLE handle = - fDescriptorHeaps[fDescriptorHeaps.size() - 1]->allocateCPUHandle(); - return handle; -} - -void GrD3DAttachmentViewManager::HeapPool::releaseHandle( - D3D12_CPU_DESCRIPTOR_HANDLE* dsvDescriptor) { - for (unsigned int i = 0; i < fDescriptorHeaps.size(); ++i) { - if (fDescriptorHeaps[i]->freeCPUHandle(dsvDescriptor)) { - return; - } - } - SkASSERT(false); -} diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DAttachmentViewManager.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DAttachmentViewManager.h deleted file mode 100644 index 3424ba39f94..00000000000 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DAttachmentViewManager.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2020 Google LLC - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrD3DAttachmentViewManager_DEFINED -#define GrD3DAttachmentViewManager_DEFINED - -#include "src/gpu/d3d/GrD3DDescriptorHeap.h" - -class GrD3DGpu; - -class GrD3DAttachmentViewManager { -public: - GrD3DAttachmentViewManager(GrD3DGpu*); - - D3D12_CPU_DESCRIPTOR_HANDLE createRenderTargetView(GrD3DGpu*, ID3D12Resource* textureResource); - void recycleRenderTargetView(D3D12_CPU_DESCRIPTOR_HANDLE*); - - D3D12_CPU_DESCRIPTOR_HANDLE createDepthStencilView(GrD3DGpu*, ID3D12Resource* textureResource); - void recycleDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE*); - -private: - class Heap { - public: - static std::unique_ptr<Heap> Make(GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE type, - unsigned int numDescriptors); - - D3D12_CPU_DESCRIPTOR_HANDLE allocateCPUHandle(); - bool freeCPUHandle(D3D12_CPU_DESCRIPTOR_HANDLE*); - - bool canAllocate() { return fFreeCount > 0; } - - private: - Heap(std::unique_ptr<GrD3DDescriptorHeap>& heap, unsigned int numDescriptors) - : fHeap(std::move(heap)) - , fFreeBlocks(numDescriptors) - , fFreeCount(numDescriptors) { - for (unsigned int i = 0; i < numDescriptors; ++i) { - fFreeBlocks.set(i); - } - } - - std::unique_ptr<GrD3DDescriptorHeap> fHeap; - SkBitSet fFreeBlocks; - unsigned int fFreeCount; - }; - - class HeapPool { - public: - HeapPool(GrD3DGpu*, D3D12_DESCRIPTOR_HEAP_TYPE); - - D3D12_CPU_DESCRIPTOR_HANDLE allocateHandle(GrD3DGpu*); - void releaseHandle(D3D12_CPU_DESCRIPTOR_HANDLE*); - - private: - std::vector<std::unique_ptr<Heap>> fDescriptorHeaps; - int fMaxAvailableDescriptors; - D3D12_DESCRIPTOR_HEAP_TYPE fHeapType; - }; - - HeapPool fRTVDescriptorPool; - HeapPool fDSVDescriptorPool; -}; - -#endif diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DBuffer.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DBuffer.cpp index 7462feb392d..108e9d11571 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DBuffer.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DBuffer.cpp @@ -24,8 +24,8 @@ sk_sp<GrD3DBuffer::Resource> GrD3DBuffer::Resource::Make(GrD3DGpu* gpu, size_t s SkASSERT(intendedType != GrGpuBufferType::kXferCpuToGpu && intendedType != GrGpuBufferType::kXferGpuToCpu); heapType = D3D12_HEAP_TYPE_DEFAULT; - // Can be transitioned to different states - *resourceState = D3D12_RESOURCE_STATE_COMMON; + // Needs to be transitioned to appropriate state to be read in shader + *resourceState = D3D12_RESOURCE_STATE_COPY_DEST; } else { if (intendedType == GrGpuBufferType::kXferGpuToCpu) { heapType = D3D12_HEAP_TYPE_READBACK; @@ -101,6 +101,26 @@ GrD3DBuffer::GrD3DBuffer(GrD3DGpu* gpu, size_t size, GrGpuBufferType intendedTyp VALIDATE(); } +void GrD3DBuffer::setResourceState(const GrD3DGpu* gpu, + D3D12_RESOURCE_STATES newResourceState) { + if (newResourceState == fResourceState || + // GENERIC_READ encapsulates a lot of different read states + (fResourceState == D3D12_RESOURCE_STATE_GENERIC_READ && + SkToBool(newResourceState | fResourceState))) { + return; + } + + D3D12_RESOURCE_TRANSITION_BARRIER barrier = {}; + barrier.pResource = this->d3dResource(); + barrier.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.StateBefore = fResourceState; + barrier.StateAfter = newResourceState; + + gpu->addResourceBarriers(this->resource(), 1, &barrier); + + fResourceState = newResourceState; +} + void GrD3DBuffer::onRelease() { if (!this->wasDestroyed()) { VALIDATE(); @@ -169,10 +189,6 @@ void GrD3DBuffer::internalMap(size_t size) { VALIDATE(); if (this->accessPattern() == kStatic_GrAccessPattern) { -#ifdef SK_BUILD_FOR_MAC - // Mac requires 4-byte alignment for copies so we pad this out - sizeInBytes = SkAlign4(sizeInBytes); -#endif // TODO: should use a slice of a previously allocated UPLOAD buffer D3D12_RESOURCE_STATES resourceState; // not used, just to pass to make fMappedResource = Resource::Make(this->getD3DGpu(), size, GrGpuBufferType::kXferCpuToGpu, @@ -215,15 +231,10 @@ void GrD3DBuffer::internalUnmap(size_t size) { range.Begin = 0; range.End = size; fMappedResource->fD3DResource->Unmap(0, &range); - // TODO - // let the D3DGpu make this decision? - //if (size == this->size()) { - // this->getD3DGpu()->copyResource(this->d3dResource(), fMappedResource->fD3DResource); - - //} else { - // this->getD3DGpu()->copyBufferRegion(this->d3dResource(), 0, - // fMappedResource->fD3DResource, 0, size); - //} + this->setResourceState(this->getD3DGpu(), D3D12_RESOURCE_STATE_COPY_DEST); + this->getD3DGpu()->currentCommandList()->copyBufferToBuffer( + fResource, fResource->fD3DResource.get(), 0, + fMappedResource, fMappedResource->fD3DResource.get(), 0, size); } else { D3D12_RANGE range; range.Begin = 0; diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DBuffer.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DBuffer.h index e2d1efc55de..00611728fc6 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DBuffer.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DBuffer.h @@ -37,6 +37,8 @@ public: return fResource; } + void setResourceState(const GrD3DGpu* gpu, D3D12_RESOURCE_STATES newResourceState); + protected: GrD3DBuffer(GrD3DGpu*, size_t size, GrGpuBufferType, GrAccessPattern, const sk_sp<Resource>&, D3D12_RESOURCE_STATES); diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DCaps.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DCaps.cpp index df17463d607..e6b00dc73b5 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DCaps.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DCaps.cpp @@ -10,6 +10,7 @@ #include "include/gpu/d3d/GrD3DTypes.h" #include "src/core/SkCompressedDataUtils.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrProgramDesc.h" #include "src/gpu/GrProgramInfo.h" #include "src/gpu/GrShaderCaps.h" @@ -773,20 +774,6 @@ bool GrD3DCaps::isFormatSRGB(const GrBackendFormat& format) const { } } -SkImage::CompressionType GrD3DCaps::compressionType(const GrBackendFormat& format) const { - DXGI_FORMAT dxgiFormat; - if (!format.asDxgiFormat(&dxgiFormat)) { - return SkImage::CompressionType::kNone; - } - - switch (dxgiFormat) { - case DXGI_FORMAT_BC1_UNORM: return SkImage::CompressionType::kBC1_RGBA8_UNORM; - default: return SkImage::CompressionType::kNone; - } - - SkUNREACHABLE; -} - bool GrD3DCaps::isFormatTexturable(const GrBackendFormat& format) const { DXGI_FORMAT dxgiFormat; if (!format.asDxgiFormat(&dxgiFormat)) { @@ -944,12 +931,6 @@ bool GrD3DCaps::onAreColorTypeAndFormatCompatible(GrColorType ct, return false; } - SkImage::CompressionType compression = GrDxgiFormatToCompressionType(dxgiFormat); - if (compression != SkImage::CompressionType::kNone) { - return ct == (SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x - : GrColorType::kRGBA_8888); - } - const auto& info = this->getFormatInfo(dxgiFormat); for (int i = 0; i < info.fColorTypeInfoCount; ++i) { if (info.fColorTypeInfos[i].fColorType == ct) { @@ -982,7 +963,7 @@ GrBackendFormat GrD3DCaps::getBackendFormatFromCompressionType( SkUNREACHABLE; } -GrSwizzle GrD3DCaps::getReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const { +GrSwizzle GrD3DCaps::onGetReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const { DXGI_FORMAT dxgiFormat; SkAssertResult(format.asDxgiFormat(&dxgiFormat)); const auto& info = this->getFormatInfo(dxgiFormat); @@ -1025,7 +1006,7 @@ GrCaps::SupportedRead GrD3DCaps::onSupportedReadPixelsColorType( return { GrColorType::kUnknown, 0 }; } - SkImage::CompressionType compression = GrDxgiFormatToCompressionType(dxgiFormat); + SkImage::CompressionType compression = GrBackendFormatToCompressionType(srcBackendFormat); if (compression != SkImage::CompressionType::kNone) { return { SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x : GrColorType::kRGBA_8888, 0 }; diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DCaps.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DCaps.h index 1c4fefb52db..2e05f117b52 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DCaps.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DCaps.h @@ -29,7 +29,6 @@ public: GrD3DCaps(const GrContextOptions& contextOptions, IDXGIAdapter1*, ID3D12Device*); bool isFormatSRGB(const GrBackendFormat&) const override; - SkImage::CompressionType compressionType(const GrBackendFormat&) const override; bool isFormatTexturable(const GrBackendFormat&) const override; bool isFormatTexturable(DXGI_FORMAT) const; @@ -93,7 +92,6 @@ public: return fColorTypeToFormatTable[idx]; } - GrSwizzle getReadSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getWriteSwizzle(const GrBackendFormat&, GrColorType) const override; uint64_t computeFormatKey(const GrBackendFormat&) const override; @@ -139,6 +137,8 @@ private: SupportedRead onSupportedReadPixelsColorType(GrColorType, const GrBackendFormat&, GrColorType) const override; + GrSwizzle onGetReadSwizzle(const GrBackendFormat&, GrColorType) const override; + // ColorTypeInfo for a specific format struct ColorTypeInfo { GrColorType fColorType = GrColorType::kUnknown; diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DCommandList.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DCommandList.cpp index 1216b93f17b..a422622116d 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DCommandList.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DCommandList.cpp @@ -7,10 +7,13 @@ #include "src/gpu/d3d/GrD3DCommandList.h" +#include "src/gpu/GrScissorState.h" #include "src/gpu/d3d/GrD3DBuffer.h" #include "src/gpu/d3d/GrD3DGpu.h" #include "src/gpu/d3d/GrD3DPipelineState.h" #include "src/gpu/d3d/GrD3DRenderTarget.h" +#include "src/gpu/d3d/GrD3DStencilAttachment.h" +#include "src/gpu/d3d/GrD3DTexture.h" #include "src/gpu/d3d/GrD3DTextureResource.h" GrD3DCommandList::GrD3DCommandList(gr_cp<ID3D12CommandAllocator> allocator, @@ -30,6 +33,7 @@ bool GrD3DCommandList::close() { GrD3DCommandList::SubmitResult GrD3DCommandList::submit(ID3D12CommandQueue* queue) { SkASSERT(fIsActive); if (!this->hasWork()) { + this->callFinishedCallbacks(); return SubmitResult::kNoWork; } @@ -49,6 +53,7 @@ void GrD3DCommandList::reset() { SkASSERT(SUCCEEDED(hr)); SkDEBUGCODE(hr = ) fCommandList->Reset(fAllocator.get(), nullptr); SkASSERT(SUCCEEDED(hr)); + this->onReset(); this->releaseResources(); @@ -73,6 +78,12 @@ void GrD3DCommandList::releaseResources() { fTrackedResources.reset(); fTrackedRecycledResources.reset(); + + this->callFinishedCallbacks(); +} + +void GrD3DCommandList::addFinishedCallback(sk_sp<GrRefCntedCallback> callback) { + fFinishedCallbacks.push_back(std::move(callback)); } //////////////////////////////////////////////////////////////////////////////// @@ -81,7 +92,7 @@ void GrD3DCommandList::releaseResources() { void GrD3DCommandList::resourceBarrier(sk_sp<GrManagedResource> resource, int numBarriers, - D3D12_RESOURCE_TRANSITION_BARRIER* barriers) { + const D3D12_RESOURCE_TRANSITION_BARRIER* barriers) { SkASSERT(fIsActive); SkASSERT(barriers); for (int i = 0; i < numBarriers; ++i) { @@ -108,8 +119,8 @@ void GrD3DCommandList::submitResourceBarriers() { SkASSERT(!fResourceBarriers.count()); } -void GrD3DCommandList::copyBufferToTexture(GrD3DBuffer* srcBuffer, - GrD3DTextureResource* dstTexture, +void GrD3DCommandList::copyBufferToTexture(const GrD3DBuffer* srcBuffer, + const GrD3DTextureResource* dstTexture, uint32_t subresourceCount, D3D12_PLACED_SUBRESOURCE_FOOTPRINT* bufferFootprints, int left, int top) { @@ -148,14 +159,23 @@ void GrD3DCommandList::copyTextureRegion(sk_sp<GrManagedResource> dst, fCommandList->CopyTextureRegion(dstLocation, dstX, dstY, 0, srcLocation, srcBox); } -void GrD3DCommandList::clearRenderTargetView(GrD3DRenderTarget* renderTarget, - const SkPMColor4f& color, - const GrFixedClip& clip) { +void GrD3DCommandList::copyBufferToBuffer(sk_sp<GrManagedResource> dst, + ID3D12Resource* dstBuffer, uint64_t dstOffset, + sk_sp<GrManagedResource> src, + ID3D12Resource* srcBuffer, uint64_t srcOffset, + uint64_t numBytes) { + SkASSERT(fIsActive); + this->addingWork(); - this->addResource(renderTarget->resource()); - fCommandList->ClearRenderTargetView(renderTarget->colorRenderTargetView(), - color.vec(), - 0, NULL); // no cliprects for now + this->addResource(dst); + this->addResource(src); + uint64_t dstSize = dstBuffer->GetDesc().Width; + uint64_t srcSize = srcBuffer->GetDesc().Width; + if (dstSize == srcSize && srcSize == numBytes) { + fCommandList->CopyResource(dstBuffer, srcBuffer); + } else { + fCommandList->CopyBufferRegion(dstBuffer, dstOffset, srcBuffer, srcOffset, numBytes); + } } void GrD3DCommandList::addingWork() { @@ -183,7 +203,31 @@ std::unique_ptr<GrD3DDirectCommandList> GrD3DDirectCommandList::Make(ID3D12Devic GrD3DDirectCommandList::GrD3DDirectCommandList(gr_cp<ID3D12CommandAllocator> allocator, gr_cp<ID3D12GraphicsCommandList> commandList) - : GrD3DCommandList(std::move(allocator), std::move(commandList)) { + : GrD3DCommandList(std::move(allocator), std::move(commandList)) + , fCurrentRootSignature(nullptr) + , fCurrentVertexBuffer(nullptr) + , fCurrentVertexStride(0) + , fCurrentInstanceBuffer(nullptr) + , fCurrentInstanceStride(0) + , fCurrentIndexBuffer(nullptr) + , fCurrentConstantRingBuffer(nullptr) + , fCurrentSRVCRVDescriptorHeap(nullptr) + , fCurrentSamplerDescriptorHeap(nullptr) { +} + +void GrD3DDirectCommandList::onReset() { + fCurrentRootSignature = nullptr; + fCurrentVertexBuffer = nullptr; + fCurrentVertexStride = 0; + fCurrentInstanceBuffer = nullptr; + fCurrentInstanceStride = 0; + fCurrentIndexBuffer = nullptr; + if (fCurrentConstantRingBuffer) { + fCurrentConstantRingBuffer->finishSubmit(fConstantRingBufferSubmitData); + fCurrentConstantRingBuffer = nullptr; + } + fCurrentSRVCRVDescriptorHeap = nullptr; + fCurrentSamplerDescriptorHeap = nullptr; } void GrD3DDirectCommandList::setPipelineState(sk_sp<GrD3DPipelineState> pipelineState) { @@ -192,6 +236,16 @@ void GrD3DDirectCommandList::setPipelineState(sk_sp<GrD3DPipelineState> pipeline this->addResource(std::move(pipelineState)); } +void GrD3DDirectCommandList::setCurrentConstantBuffer( + const sk_sp<GrD3DConstantRingBuffer>& constantBuffer) { + fCurrentConstantRingBuffer = constantBuffer.get(); + if (fCurrentConstantRingBuffer) { + fConstantRingBufferSubmitData = constantBuffer->startSubmit(); + this->addResource( + static_cast<GrD3DBuffer*>(fConstantRingBufferSubmitData.buffer())->resource()); + } +} + void GrD3DDirectCommandList::setStencilRef(unsigned int stencilRef) { SkASSERT(fIsActive); fCommandList->OMSetStencilRef(stencilRef); @@ -218,6 +272,150 @@ void GrD3DDirectCommandList::setViewports(unsigned int numViewports, fCommandList->RSSetViewports(numViewports, viewports); } +void GrD3DDirectCommandList::setGraphicsRootSignature(const sk_sp<GrD3DRootSignature>& rootSig) { + SkASSERT(fIsActive); + if (fCurrentRootSignature != rootSig.get()) { + fCommandList->SetGraphicsRootSignature(rootSig->rootSignature()); + this->addResource(rootSig); + fCurrentRootSignature = rootSig.get(); + } +} + +void GrD3DDirectCommandList::setVertexBuffers(unsigned int startSlot, + const GrD3DBuffer* vertexBuffer, + size_t vertexStride, + const GrD3DBuffer* instanceBuffer, + size_t instanceStride) { + if (fCurrentVertexBuffer != vertexBuffer || fCurrentVertexStride != vertexStride || + fCurrentInstanceBuffer != instanceBuffer || fCurrentInstanceStride != instanceStride) { + this->addResource(vertexBuffer->resource()); + + D3D12_VERTEX_BUFFER_VIEW views[2]; + int numViews = 0; + views[numViews].BufferLocation = vertexBuffer->d3dResource()->GetGPUVirtualAddress(); + views[numViews].SizeInBytes = vertexBuffer->size(); + views[numViews++].StrideInBytes = vertexStride; + if (instanceBuffer) { + this->addResource(instanceBuffer->resource()); + views[numViews].BufferLocation = instanceBuffer->d3dResource()->GetGPUVirtualAddress(); + views[numViews].SizeInBytes = instanceBuffer->size(); + views[numViews++].StrideInBytes = instanceStride; + } + fCommandList->IASetVertexBuffers(startSlot, numViews, views); + + fCurrentVertexBuffer = vertexBuffer; + fCurrentVertexStride = vertexStride; + fCurrentInstanceBuffer = instanceBuffer; + fCurrentInstanceStride = instanceStride; + } +} + +void GrD3DDirectCommandList::setIndexBuffer(const GrD3DBuffer* indexBuffer) { + if (fCurrentIndexBuffer != indexBuffer) { + this->addResource(indexBuffer->resource()); + + D3D12_INDEX_BUFFER_VIEW view = {}; + view.BufferLocation = indexBuffer->d3dResource()->GetGPUVirtualAddress(); + view.SizeInBytes = indexBuffer->size(); + view.Format = DXGI_FORMAT_R16_UINT; + fCommandList->IASetIndexBuffer(&view); + } +} + +void GrD3DDirectCommandList::drawInstanced(unsigned int vertexCount, unsigned int instanceCount, + unsigned int startVertex, unsigned int startInstance) { + SkASSERT(fIsActive); + this->addingWork(); + fCommandList->DrawInstanced(vertexCount, instanceCount, startVertex, startInstance); +} + +void GrD3DDirectCommandList::drawIndexedInstanced(unsigned int indexCount, + unsigned int instanceCount, + unsigned int startIndex, + unsigned int baseVertex, + unsigned int startInstance) { + SkASSERT(fIsActive); + this->addingWork(); + fCommandList->DrawIndexedInstanced(indexCount, instanceCount, startIndex, baseVertex, + startInstance); +} + +void GrD3DDirectCommandList::clearRenderTargetView(const GrD3DRenderTarget* renderTarget, + const SkPMColor4f& color, + const D3D12_RECT* rect) { + this->addingWork(); + this->addResource(renderTarget->resource()); + if (renderTarget->numSamples() > 1) { + this->addResource(renderTarget->msaaTextureResource()->resource()); + } + unsigned int numRects = rect ? 1 : 0; + fCommandList->ClearRenderTargetView(renderTarget->colorRenderTargetView(), + color.vec(), numRects, rect); +} + +void GrD3DDirectCommandList::clearDepthStencilView(const GrD3DStencilAttachment* stencil, + uint8_t stencilClearValue, + const D3D12_RECT* rect) { + this->addingWork(); + this->addResource(stencil->resource()); + unsigned int numRects = rect ? 1 : 0; + fCommandList->ClearDepthStencilView(stencil->view(), D3D12_CLEAR_FLAG_STENCIL, 0, + stencilClearValue, numRects, rect); +} + +void GrD3DDirectCommandList::setRenderTarget(const GrD3DRenderTarget* renderTarget) { + this->addingWork(); + this->addResource(renderTarget->resource()); + if (renderTarget->numSamples() > 1) { + this->addResource(renderTarget->msaaTextureResource()->resource()); + } + D3D12_CPU_DESCRIPTOR_HANDLE rtvDescriptor = renderTarget->colorRenderTargetView(); + + D3D12_CPU_DESCRIPTOR_HANDLE dsDescriptor; + D3D12_CPU_DESCRIPTOR_HANDLE* dsDescriptorPtr = nullptr; + if (auto stencil = renderTarget->renderTargetPriv().getStencilAttachment()) { + GrD3DStencilAttachment* d3dStencil = static_cast<GrD3DStencilAttachment*>(stencil); + this->addResource(d3dStencil->resource()); + dsDescriptor = d3dStencil->view(); + dsDescriptorPtr = &dsDescriptor; + } + + fCommandList->OMSetRenderTargets(1, &rtvDescriptor, false, dsDescriptorPtr); +} + +void GrD3DDirectCommandList::setGraphicsRootConstantBufferView( + unsigned int rootParameterIndex, D3D12_GPU_VIRTUAL_ADDRESS bufferLocation) { + fCommandList->SetGraphicsRootConstantBufferView(rootParameterIndex, bufferLocation); +} + +void GrD3DDirectCommandList::setGraphicsRootDescriptorTable( + unsigned int rootParameterIndex, D3D12_GPU_DESCRIPTOR_HANDLE baseDescriptor) { + fCommandList->SetGraphicsRootDescriptorTable(rootParameterIndex, baseDescriptor); +} + +void GrD3DDirectCommandList::setDescriptorHeaps(sk_sp<GrRecycledResource> srvCrvHeapResource, + ID3D12DescriptorHeap* srvCrvDescriptorHeap, + sk_sp<GrRecycledResource> samplerHeapResource, + ID3D12DescriptorHeap* samplerDescriptorHeap) { + if (srvCrvDescriptorHeap != fCurrentSRVCRVDescriptorHeap || + samplerDescriptorHeap != fCurrentSamplerDescriptorHeap) { + ID3D12DescriptorHeap* heaps[2] = { + srvCrvDescriptorHeap, + samplerDescriptorHeap + }; + + fCommandList->SetDescriptorHeaps(2, heaps); + this->addRecycledResource(std::move(srvCrvHeapResource)); + this->addRecycledResource(std::move(samplerHeapResource)); + fCurrentSRVCRVDescriptorHeap = srvCrvDescriptorHeap; + fCurrentSamplerDescriptorHeap = samplerDescriptorHeap; + } +} + +void GrD3DDirectCommandList::addSampledTextureRef(GrD3DTexture* texture) { + this->addResource(texture->resource()); +} + //////////////////////////////////////////////////////////////////////////////////////////////////// std::unique_ptr<GrD3DCopyCommandList> GrD3DCopyCommandList::Make(ID3D12Device* device) { diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DCommandList.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DCommandList.h index 781f8f7c52d..4bea28bad1e 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DCommandList.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DCommandList.h @@ -12,20 +12,25 @@ #include "include/gpu/d3d/GrD3DTypes.h" #include "include/private/SkColorData.h" #include "src/gpu/GrManagedResource.h" +#include "src/gpu/d3d/GrD3DConstantRingBuffer.h" #include <memory> class GrD3DGpu; class GrD3DBuffer; +class GrD3DConstantRingBuffer; class GrD3DPipelineState; class GrD3DRenderTarget; +class GrD3DRootSignature; +class GrD3DStencilAttachment; +class GrD3DTexture; class GrD3DTextureResource; -class GrFixedClip; +class GrScissorState; class GrD3DCommandList { public: - ~GrD3DCommandList() { + virtual ~GrD3DCommandList() { this->releaseResources(); } @@ -47,11 +52,11 @@ public: // All barriers should reference subresources of managedResource void resourceBarrier(sk_sp<GrManagedResource> managedResource, int numBarriers, - D3D12_RESOURCE_TRANSITION_BARRIER* barriers); + const D3D12_RESOURCE_TRANSITION_BARRIER* barriers); // Helper method that calls copyTextureRegion multiple times, once for each subresource - void copyBufferToTexture(GrD3DBuffer* srcBuffer, - GrD3DTextureResource* dstTexture, + void copyBufferToTexture(const GrD3DBuffer* srcBuffer, + const GrD3DTextureResource* dstTexture, uint32_t subresourceCount, D3D12_PLACED_SUBRESOURCE_FOOTPRINT* bufferFootprints, int left, int top); @@ -61,9 +66,24 @@ public: sk_sp<GrManagedResource> src, const D3D12_TEXTURE_COPY_LOCATION* srcLocation, const D3D12_BOX* srcBox); + void copyBufferToBuffer(sk_sp<GrManagedResource> dst, + ID3D12Resource* dstBuffer, uint64_t dstOffset, + sk_sp<GrManagedResource> src, + ID3D12Resource* srcBuffer, uint64_t srcOffset, + uint64_t numBytes); - void clearRenderTargetView(GrD3DRenderTarget* renderTarget, const SkPMColor4f& color, - const GrFixedClip& clip); + void releaseResources(); + + bool hasWork() const { return fHasWork; } + + void addFinishedCallback(sk_sp<GrRefCntedCallback> callback); + +private: + static const int kInitialTrackedResourcesCount = 32; + +protected: + GrD3DCommandList(gr_cp<ID3D12CommandAllocator> allocator, + gr_cp<ID3D12GraphicsCommandList> commandList); // Add ref-counted resource that will be tracked and released when this command buffer finishes // execution @@ -80,18 +100,8 @@ public: fTrackedRecycledResources.push_back(std::move(resource)); } - void releaseResources(); - - bool hasWork() const { return fHasWork; } - -private: - static const int kInitialTrackedResourcesCount = 32; - -protected: - GrD3DCommandList(gr_cp<ID3D12CommandAllocator> allocator, - gr_cp<ID3D12GraphicsCommandList> commandList); - void addingWork(); + virtual void onReset() {} void submitResourceBarriers(); @@ -105,26 +115,76 @@ protected: bool fHasWork = false; private: + void callFinishedCallbacks() { fFinishedCallbacks.reset(); } + gr_cp<ID3D12CommandAllocator> fAllocator; SkSTArray<4, D3D12_RESOURCE_BARRIER> fResourceBarriers; + + SkTArray<sk_sp<GrRefCntedCallback>> fFinishedCallbacks; }; class GrD3DDirectCommandList : public GrD3DCommandList { public: static std::unique_ptr<GrD3DDirectCommandList> Make(ID3D12Device* device); + ~GrD3DDirectCommandList() override = default; + void setPipelineState(sk_sp<GrD3DPipelineState> pipelineState); + void setCurrentConstantBuffer(const sk_sp<GrD3DConstantRingBuffer>& constantBuffer); + void setStencilRef(unsigned int stencilRef); void setBlendFactor(const float blendFactor[4]); void setPrimitiveTopology(D3D12_PRIMITIVE_TOPOLOGY primitiveTopology); void setScissorRects(unsigned int numRects, const D3D12_RECT* rects); void setViewports(unsigned int numViewports, const D3D12_VIEWPORT* viewports); + void setGraphicsRootSignature(const sk_sp<GrD3DRootSignature>& rootSignature); + void setVertexBuffers(unsigned int startSlot, + const GrD3DBuffer* vertexBuffer, size_t vertexStride, + const GrD3DBuffer* instanceBuffer, size_t instanceStride); + void setIndexBuffer(const GrD3DBuffer* indexBuffer); + void drawInstanced(unsigned int vertexCount, unsigned int instanceCount, + unsigned int startVertex, unsigned int startInstance); + void drawIndexedInstanced(unsigned int indexCount, unsigned int instanceCount, + unsigned int startIndex, unsigned int baseVertex, + unsigned int startInstance); + + void clearRenderTargetView(const GrD3DRenderTarget* renderTarget, const SkPMColor4f& color, + const D3D12_RECT* rect); + void clearDepthStencilView(const GrD3DStencilAttachment*, uint8_t stencilClearValue, + const D3D12_RECT* rect); + void setRenderTarget(const GrD3DRenderTarget* renderTarget); + + void setGraphicsRootConstantBufferView(unsigned int rootParameterIndex, + D3D12_GPU_VIRTUAL_ADDRESS bufferLocation); + void setGraphicsRootDescriptorTable(unsigned int rootParameterIndex, + D3D12_GPU_DESCRIPTOR_HANDLE bufferLocation); + void setDescriptorHeaps(sk_sp<GrRecycledResource> srvCrvHeapResource, + ID3D12DescriptorHeap* srvDescriptorHeap, + sk_sp<GrRecycledResource> samplerHeapResource, + ID3D12DescriptorHeap* samplerDescriptorHeap); + + void addSampledTextureRef(GrD3DTexture*); private: GrD3DDirectCommandList(gr_cp<ID3D12CommandAllocator> allocator, gr_cp<ID3D12GraphicsCommandList> commandList); + + void onReset() override; + + const GrD3DRootSignature* fCurrentRootSignature; + const GrD3DBuffer* fCurrentVertexBuffer; + size_t fCurrentVertexStride; + const GrD3DBuffer* fCurrentInstanceBuffer; + size_t fCurrentInstanceStride; + const GrD3DBuffer* fCurrentIndexBuffer; + + GrD3DConstantRingBuffer* fCurrentConstantRingBuffer; + GrD3DConstantRingBuffer::SubmitData fConstantRingBufferSubmitData; + + const ID3D12DescriptorHeap* fCurrentSRVCRVDescriptorHeap; + const ID3D12DescriptorHeap* fCurrentSamplerDescriptorHeap; }; class GrD3DCopyCommandList : public GrD3DCommandList { diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DConstantRingBuffer.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DConstantRingBuffer.cpp new file mode 100644 index 00000000000..cf719c7745b --- /dev/null +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DConstantRingBuffer.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/gpu/d3d/GrD3DConstantRingBuffer.h" + +#include "src/gpu/d3d/GrD3DBuffer.h" +#include "src/gpu/d3d/GrD3DGpu.h" + +sk_sp<GrD3DConstantRingBuffer> GrD3DConstantRingBuffer::Make(GrD3DGpu* gpu, size_t size, + size_t alignment) { + sk_sp<GrGpuBuffer> buffer = GrD3DBuffer::Make(gpu, size, GrGpuBufferType::kVertex, + kDynamic_GrAccessPattern); + if (!buffer) { + return nullptr; + } + + return sk_sp<GrD3DConstantRingBuffer>(new GrD3DConstantRingBuffer(std::move(buffer), size, + alignment, gpu)); +} + +sk_sp<GrGpuBuffer> GrD3DConstantRingBuffer::createBuffer(size_t size) { + // Make sure the old buffer is added to the current command list + fGpu->resourceProvider().prepForSubmit(); + + return GrD3DBuffer::Make(fGpu, size, GrGpuBufferType::kVertex, kDynamic_GrAccessPattern); +} diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DConstantRingBuffer.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DConstantRingBuffer.h new file mode 100644 index 00000000000..0a4bbf60675 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DConstantRingBuffer.h @@ -0,0 +1,33 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrD3DConstantRingBuffer_DEFINED + +#define GrD3DConstantRingBuffer_DEFINED + +#include "src/gpu/GrRingBuffer.h" + +class GrD3DGpu; + +class GrD3DConstantRingBuffer : public GrRingBuffer { +public: + static sk_sp<GrD3DConstantRingBuffer> Make(GrD3DGpu* gpu, size_t size, size_t alignment); + +private: + GrD3DConstantRingBuffer(sk_sp<GrGpuBuffer> buffer, size_t size, size_t alignment, GrD3DGpu* gpu) + : INHERITED(std::move(buffer), size, alignment) + , fGpu(gpu) {} + ~GrD3DConstantRingBuffer() override = default; + + sk_sp<GrGpuBuffer> createBuffer(size_t size) override; + + GrD3DGpu* fGpu; + + typedef GrRingBuffer INHERITED; +}; + +#endif diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DCpuDescriptorManager.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DCpuDescriptorManager.cpp new file mode 100644 index 00000000000..3ad33c388ea --- /dev/null +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DCpuDescriptorManager.cpp @@ -0,0 +1,158 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/gpu/d3d/GrD3DCpuDescriptorManager.h" + +#include "src/gpu/d3d/GrD3DGpu.h" + +GrD3DCpuDescriptorManager::GrD3DCpuDescriptorManager(GrD3DGpu* gpu) + : fRTVDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_RTV) + , fDSVDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_DSV) + , fCBVSRVDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) + , fSamplerDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) {} + +GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createRenderTargetView( + GrD3DGpu* gpu, ID3D12Resource* textureResource) { + const GrD3DDescriptorHeap::CPUHandle& descriptor = fRTVDescriptorPool.allocateHandle(gpu); + gpu->device()->CreateRenderTargetView(textureResource, nullptr, descriptor.fHandle); + return descriptor; +} + +void GrD3DCpuDescriptorManager::recycleRenderTargetView( + const GrD3DDescriptorHeap::CPUHandle& rtvDescriptor) { + fRTVDescriptorPool.releaseHandle(rtvDescriptor); +} + +GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createDepthStencilView( + GrD3DGpu* gpu, ID3D12Resource* textureResource) { + const GrD3DDescriptorHeap::CPUHandle& descriptor = fDSVDescriptorPool.allocateHandle(gpu); + gpu->device()->CreateDepthStencilView(textureResource, nullptr, descriptor.fHandle); + return descriptor; +} + +void GrD3DCpuDescriptorManager::recycleDepthStencilView( + const GrD3DDescriptorHeap::CPUHandle& dsvDescriptor) { + fDSVDescriptorPool.releaseHandle(dsvDescriptor); +} + +GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createConstantBufferView( + GrD3DGpu* gpu, ID3D12Resource* bufferResource, size_t offset, size_t size) { + const GrD3DDescriptorHeap::CPUHandle& descriptor = fCBVSRVDescriptorPool.allocateHandle(gpu); + D3D12_CONSTANT_BUFFER_VIEW_DESC desc = {}; + desc.BufferLocation = bufferResource->GetGPUVirtualAddress() + offset; + desc.SizeInBytes = size; + gpu->device()->CreateConstantBufferView(&desc, descriptor.fHandle); + return descriptor; +} + +GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createShaderResourceView( + GrD3DGpu* gpu, ID3D12Resource* resource) { + const GrD3DDescriptorHeap::CPUHandle& descriptor = fCBVSRVDescriptorPool.allocateHandle(gpu); + // TODO: for 4:2:0 YUV formats we'll need to map two different views, one for Y and one for UV. + // For now map the entire resource. + gpu->device()->CreateShaderResourceView(resource, nullptr, descriptor.fHandle); + return descriptor; +} + +void GrD3DCpuDescriptorManager::recycleConstantOrShaderView( + const GrD3DDescriptorHeap::CPUHandle& view) { + fCBVSRVDescriptorPool.releaseHandle(view); +} + +GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::createSampler( + GrD3DGpu* gpu, D3D12_FILTER filter, D3D12_TEXTURE_ADDRESS_MODE addressModeU, + D3D12_TEXTURE_ADDRESS_MODE addressModeV) { + const GrD3DDescriptorHeap::CPUHandle& descriptor = fSamplerDescriptorPool.allocateHandle(gpu); + D3D12_SAMPLER_DESC desc = {}; + desc.Filter = filter; + desc.AddressU = addressModeU; + desc.AddressV = addressModeV; + desc.AddressW = D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + desc.MipLODBias = 0; + desc.MaxAnisotropy = 1; + desc.ComparisonFunc = D3D12_COMPARISON_FUNC_ALWAYS; + // desc.BorderColor initialized to { 0, 0, 0, 0 } by default initializer, above. + desc.MinLOD = 0; + desc.MaxLOD = SK_ScalarMax; + + gpu->device()->CreateSampler(&desc, descriptor.fHandle); + return descriptor; +} + +void GrD3DCpuDescriptorManager::recycleSampler( + const GrD3DDescriptorHeap::CPUHandle& samplerDescriptor) { + fSamplerDescriptorPool.releaseHandle(samplerDescriptor); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +std::unique_ptr<GrD3DCpuDescriptorManager::Heap> GrD3DCpuDescriptorManager::Heap::Make( + GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE type, unsigned int numDescriptors) { + std::unique_ptr<GrD3DDescriptorHeap> heap = + GrD3DDescriptorHeap::Make(gpu, type, numDescriptors, D3D12_DESCRIPTOR_HEAP_FLAG_NONE); + if (!heap) { + return nullptr; + } + + return std::unique_ptr<Heap>(new Heap(heap, numDescriptors)); +} + +GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::Heap::allocateCPUHandle() { + SkBitSet::OptionalIndex freeBlock = fFreeBlocks.findFirst(); + SkASSERT(freeBlock); + fFreeBlocks.reset(*freeBlock); + --fFreeCount; + return fHeap->getCPUHandle(*freeBlock); +} + +void GrD3DCpuDescriptorManager::Heap::freeCPUHandle(const GrD3DDescriptorHeap::CPUHandle& handle) { + SkASSERT(this->ownsHandle(handle)); + size_t index = fHeap->getIndex(handle); + fFreeBlocks.set(index); + ++fFreeCount; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +GrD3DCpuDescriptorManager::HeapPool::HeapPool(GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE heapType) + : fMaxAvailableDescriptors(32) + , fHeapType(heapType) { + std::unique_ptr<GrD3DCpuDescriptorManager::Heap> heap = + GrD3DCpuDescriptorManager::Heap::Make(gpu, fHeapType, fMaxAvailableDescriptors); + fDescriptorHeaps.push_back(std::move(heap)); +} + +GrD3DDescriptorHeap::CPUHandle GrD3DCpuDescriptorManager::HeapPool::allocateHandle( + GrD3DGpu* gpu) { + for (unsigned int i = 0; i < fDescriptorHeaps.size(); ++i) { + if (fDescriptorHeaps[i]->canAllocate()) { + GrD3DDescriptorHeap::CPUHandle handle = fDescriptorHeaps[i]->allocateCPUHandle(); + return handle; + } + } + + // need to allocate more space + std::unique_ptr<GrD3DCpuDescriptorManager::Heap> heap = + GrD3DCpuDescriptorManager::Heap::Make(gpu, fHeapType, fMaxAvailableDescriptors); + + fDescriptorHeaps.push_back(std::move(heap)); + fMaxAvailableDescriptors *= 2; + GrD3DDescriptorHeap::CPUHandle handle = + fDescriptorHeaps[fDescriptorHeaps.size() - 1]->allocateCPUHandle(); + return handle; +} + +void GrD3DCpuDescriptorManager::HeapPool::releaseHandle( + const GrD3DDescriptorHeap::CPUHandle& dsvDescriptor) { + for (unsigned int i = 0; i < fDescriptorHeaps.size(); ++i) { + if (fDescriptorHeaps[i]->ownsHandle(dsvDescriptor)) { + fDescriptorHeaps[i]->freeCPUHandle(dsvDescriptor); + return; + } + } + SkASSERT(false); +} diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DCpuDescriptorManager.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DCpuDescriptorManager.h new file mode 100644 index 00000000000..056c6968738 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DCpuDescriptorManager.h @@ -0,0 +1,89 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrD3DCpuDescriptorManager_DEFINED +#define GrD3DCpuDescriptorManager_DEFINED + +#include "src/gpu/d3d/GrD3DDescriptorHeap.h" + +class GrD3DGpu; + +class GrD3DCpuDescriptorManager { +public: + GrD3DCpuDescriptorManager(GrD3DGpu*); + + GrD3DDescriptorHeap::CPUHandle createRenderTargetView(GrD3DGpu*, + ID3D12Resource* textureResource); + void recycleRenderTargetView(const GrD3DDescriptorHeap::CPUHandle&); + + GrD3DDescriptorHeap::CPUHandle createDepthStencilView(GrD3DGpu*, + ID3D12Resource* textureResource); + void recycleDepthStencilView(const GrD3DDescriptorHeap::CPUHandle&); + + GrD3DDescriptorHeap::CPUHandle createConstantBufferView(GrD3DGpu*, + ID3D12Resource* bufferResource, + size_t offset, + size_t size); + GrD3DDescriptorHeap::CPUHandle createShaderResourceView(GrD3DGpu*, + ID3D12Resource* resource); + void recycleConstantOrShaderView(const GrD3DDescriptorHeap::CPUHandle&); + + GrD3DDescriptorHeap::CPUHandle createSampler(GrD3DGpu*, + D3D12_FILTER filter, + D3D12_TEXTURE_ADDRESS_MODE addressModeU, + D3D12_TEXTURE_ADDRESS_MODE addressModeV); + void recycleSampler(const GrD3DDescriptorHeap::CPUHandle&); + +private: + class Heap { + public: + static std::unique_ptr<Heap> Make(GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE type, + unsigned int numDescriptors); + + GrD3DDescriptorHeap::CPUHandle allocateCPUHandle(); + void freeCPUHandle(const GrD3DDescriptorHeap::CPUHandle&); + bool ownsHandle(const GrD3DDescriptorHeap::CPUHandle& handle) { + return handle.fHeapID == fHeap->uniqueID(); + } + + bool canAllocate() { return fFreeCount > 0; } + + private: + Heap(std::unique_ptr<GrD3DDescriptorHeap>& heap, unsigned int numDescriptors) + : fHeap(std::move(heap)) + , fFreeBlocks(numDescriptors) + , fFreeCount(numDescriptors) { + for (unsigned int i = 0; i < numDescriptors; ++i) { + fFreeBlocks.set(i); + } + } + + std::unique_ptr<GrD3DDescriptorHeap> fHeap; + SkBitSet fFreeBlocks; + unsigned int fFreeCount; + }; + + class HeapPool { + public: + HeapPool(GrD3DGpu*, D3D12_DESCRIPTOR_HEAP_TYPE); + + GrD3DDescriptorHeap::CPUHandle allocateHandle(GrD3DGpu*); + void releaseHandle(const GrD3DDescriptorHeap::CPUHandle&); + + private: + std::vector<std::unique_ptr<Heap>> fDescriptorHeaps; + int fMaxAvailableDescriptors; + D3D12_DESCRIPTOR_HEAP_TYPE fHeapType; + }; + + HeapPool fRTVDescriptorPool; + HeapPool fDSVDescriptorPool; + HeapPool fCBVSRVDescriptorPool; + HeapPool fSamplerDescriptorPool; +}; + +#endif diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorHeap.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorHeap.cpp index b3ae3cc330e..8d2569783bf 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorHeap.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorHeap.cpp @@ -28,25 +28,24 @@ std::unique_ptr<GrD3DDescriptorHeap> GrD3DDescriptorHeap::Make(GrD3DGpu* gpu, GrD3DDescriptorHeap::GrD3DDescriptorHeap(const gr_cp<ID3D12DescriptorHeap>& heap, unsigned int handleIncrementSize) : fHeap(heap) - , fHandleIncrementSize(handleIncrementSize) { + , fHandleIncrementSize(handleIncrementSize) + , fUniqueID(GenID()) { fCPUHeapStart = fHeap->GetCPUDescriptorHandleForHeapStart(); fGPUHeapStart = fHeap->GetGPUDescriptorHandleForHeapStart(); } -D3D12_CPU_DESCRIPTOR_HANDLE GrD3DDescriptorHeap::getCPUHandle(unsigned int index) { - // valid only for non-shader-visible heaps - SkASSERT(!SkToBool(fHeap->GetDesc().Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE)); +GrD3DDescriptorHeap::CPUHandle GrD3DDescriptorHeap::getCPUHandle(unsigned int index) { SkASSERT(index < fHeap->GetDesc().NumDescriptors); D3D12_CPU_DESCRIPTOR_HANDLE handle = fCPUHeapStart; handle.ptr += index * fHandleIncrementSize; - return handle; + return {handle, fUniqueID}; } -D3D12_GPU_DESCRIPTOR_HANDLE GrD3DDescriptorHeap::getGPUHandle(unsigned int index) { +GrD3DDescriptorHeap::GPUHandle GrD3DDescriptorHeap::getGPUHandle(unsigned int index) { SkASSERT(index < fHeap->GetDesc().NumDescriptors); D3D12_GPU_DESCRIPTOR_HANDLE handle = fGPUHeapStart; handle.ptr += index * fHandleIncrementSize; - return handle; + return {handle, fUniqueID}; } diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorHeap.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorHeap.h index 19e2745011c..30fdc1358eb 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorHeap.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorHeap.h @@ -22,42 +22,56 @@ public: ~GrD3DDescriptorHeap() = default; - D3D12_CPU_DESCRIPTOR_HANDLE getCPUHandle(unsigned int index); // only if non-shader-visible - D3D12_GPU_DESCRIPTOR_HANDLE getGPUHandle(unsigned int index); - - bool getIndex(D3D12_CPU_DESCRIPTOR_HANDLE handle, size_t* indexPtr) { - if (handle.ptr < fCPUHeapStart.ptr) { - return false; - } - size_t index = (handle.ptr - fCPUHeapStart.ptr) / fHandleIncrementSize; - if (index >= fHeap->GetDesc().NumDescriptors) { - return false; - } - SkASSERT(handle.ptr == fCPUHeapStart.ptr + index * fHandleIncrementSize); - *indexPtr = index; - return true; + uint32_t uniqueID() const { return fUniqueID; } + + struct CPUHandle { + D3D12_CPU_DESCRIPTOR_HANDLE fHandle; + uint32_t fHeapID; + }; + + struct GPUHandle { + D3D12_GPU_DESCRIPTOR_HANDLE fHandle; + uint32_t fHeapID; + }; + + CPUHandle getCPUHandle(unsigned int index); // write-only if shader-visible + GPUHandle getGPUHandle(unsigned int index); + ID3D12DescriptorHeap* descriptorHeap() const { return fHeap.get(); } + size_t handleIncrementSize() { return fHandleIncrementSize; } + + size_t getIndex(const CPUHandle& handle) { + SkASSERT(handle.fHeapID == fUniqueID); + size_t index = (handle.fHandle.ptr - fCPUHeapStart.ptr) / fHandleIncrementSize; + SkASSERT(index < fHeap->GetDesc().NumDescriptors); + SkASSERT(handle.fHandle.ptr == fCPUHeapStart.ptr + index * fHandleIncrementSize); + return index; } - bool getIndex(D3D12_GPU_DESCRIPTOR_HANDLE handle, size_t* indexPtr) { - if (handle.ptr < fGPUHeapStart.ptr) { - return false; - } - size_t index = (handle.ptr - fGPUHeapStart.ptr) / fHandleIncrementSize; - if (index >= fHeap->GetDesc().NumDescriptors) { - return false; - } - SkASSERT(handle.ptr == fGPUHeapStart.ptr + index * fHandleIncrementSize); - *indexPtr = index; - return true; + size_t getIndex(const GPUHandle& handle) { + SkASSERT(handle.fHeapID == fUniqueID); + size_t index = (handle.fHandle.ptr - fCPUHeapStart.ptr) / fHandleIncrementSize; + SkASSERT(index < fHeap->GetDesc().NumDescriptors); + SkASSERT(handle.fHandle.ptr == fCPUHeapStart.ptr + index * fHandleIncrementSize); + return index; } protected: GrD3DDescriptorHeap(const gr_cp<ID3D12DescriptorHeap>&, unsigned int handleIncrementSize); + static uint32_t GenID() { + static std::atomic<uint32_t> nextID{1}; + uint32_t id; + do { + id = nextID++; + } while (id == SK_InvalidUniqueID); + return id; + } + gr_cp<ID3D12DescriptorHeap> fHeap; size_t fHandleIncrementSize; D3D12_CPU_DESCRIPTOR_HANDLE fCPUHeapStart; D3D12_GPU_DESCRIPTOR_HANDLE fGPUHeapStart; + uint32_t fUniqueID; }; #endif diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorTableManager.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorTableManager.cpp new file mode 100644 index 00000000000..7bbb95f2450 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorTableManager.cpp @@ -0,0 +1,150 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/gpu/d3d/GrD3DDescriptorTableManager.h" + +#include "src/gpu/d3d/GrD3DGpu.h" + +GrD3DDescriptorTableManager::GrD3DDescriptorTableManager(GrD3DGpu* gpu) + : fCBVSRVDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV) + , fSamplerDescriptorPool(gpu, D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER) {} + +std::unique_ptr<GrD3DDescriptorTable> + GrD3DDescriptorTableManager::createShaderOrConstantResourceTable(GrD3DGpu* gpu, + unsigned int size) { + std::unique_ptr<GrD3DDescriptorTable> table = fCBVSRVDescriptorPool.allocateTable(gpu, size); + this->setHeaps(gpu); + return table; +} + +std::unique_ptr<GrD3DDescriptorTable> GrD3DDescriptorTableManager::createSamplerTable( + GrD3DGpu* gpu, unsigned int size) { + std::unique_ptr<GrD3DDescriptorTable> table = fSamplerDescriptorPool.allocateTable(gpu, size); + this->setHeaps(gpu); + return table; +} + +void GrD3DDescriptorTableManager::setHeaps(GrD3DGpu* gpu) { + sk_sp<Heap>& currentCBVSRVHeap = fCBVSRVDescriptorPool.currentDescriptorHeap(); + sk_sp<Heap>& currentSamplerHeap = fSamplerDescriptorPool.currentDescriptorHeap(); + GrD3DDirectCommandList* commandList = gpu->currentCommandList(); + commandList->setDescriptorHeaps(currentCBVSRVHeap, + currentCBVSRVHeap->d3dDescriptorHeap(), + currentSamplerHeap, + currentSamplerHeap->d3dDescriptorHeap()); +} + +void GrD3DDescriptorTableManager::prepForSubmit(GrD3DGpu* gpu) { + fCBVSRVDescriptorPool.prepForSubmit(gpu); + fSamplerDescriptorPool.prepForSubmit(gpu); +} + +void GrD3DDescriptorTableManager::recycle(Heap* heap) { + // wrap the heap in an sk_sp and take ownership of it + sk_sp<Heap> wrappedHeap(heap); + + SkASSERT(heap); + switch (heap->type()) { + case D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV: + fCBVSRVDescriptorPool.recycle(std::move(wrappedHeap)); + break; + case D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER: + fSamplerDescriptorPool.recycle(std::move(wrappedHeap)); + break; + default: + SkUNREACHABLE; + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +sk_sp<GrD3DDescriptorTableManager::Heap> GrD3DDescriptorTableManager::Heap::Make( + GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE type, unsigned int descriptorCount) { + std::unique_ptr<GrD3DDescriptorHeap> heap = + GrD3DDescriptorHeap::Make(gpu, type, descriptorCount, + D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE); + if (!heap) { + return nullptr; + } + + return sk_sp< GrD3DDescriptorTableManager::Heap>(new Heap(gpu, heap, type, descriptorCount)); +} + +std::unique_ptr<GrD3DDescriptorTable> GrD3DDescriptorTableManager::Heap::allocateTable( + unsigned int count) { + SkASSERT(fDescriptorCount - fNextAvailable >= count); + unsigned int startIndex = fNextAvailable; + fNextAvailable += count; + return std::unique_ptr<GrD3DDescriptorTable>( + new GrD3DDescriptorTable(fHeap->getCPUHandle(startIndex).fHandle, + fHeap->getGPUHandle(startIndex).fHandle, fType)); +} + +void GrD3DDescriptorTableManager::Heap::onRecycle() const { + fGpu->resourceProvider().descriptorTableMgr()->recycle(const_cast<Heap*>(this)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +GrD3DDescriptorTableManager::HeapPool::HeapPool(GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE heapType) + : fHeapType(heapType) + , fCurrentHeapDescriptorCount(kInitialHeapDescriptorCount) { + sk_sp<Heap> heap = Heap::Make(gpu, fHeapType, fCurrentHeapDescriptorCount); + fDescriptorHeaps.push_back(heap); +} + +std::unique_ptr<GrD3DDescriptorTable> GrD3DDescriptorTableManager::HeapPool::allocateTable( + GrD3DGpu* gpu, unsigned int count) { + // In back-to-front order, iterate through heaps until we find one we can allocate from. + // Any heap we can't allocate from gets removed from the list. + // If it was already used, it will have been added to the commandlist, + // and then later recycled back to us. + while (fDescriptorHeaps.size() > 0) { + if (fDescriptorHeaps[fDescriptorHeaps.size() - 1]->canAllocate(count)) { + return fDescriptorHeaps[fDescriptorHeaps.size() - 1]->allocateTable(count); + } + // No space in current heap, pop off list + fDescriptorHeaps.pop_back(); + } + + // Out of available heaps, need to allocate a new one + fCurrentHeapDescriptorCount = std::min(2*fCurrentHeapDescriptorCount, 2048u); + sk_sp<GrD3DDescriptorTableManager::Heap> heap = + GrD3DDescriptorTableManager::Heap::Make(gpu, fHeapType, fCurrentHeapDescriptorCount); + fDescriptorHeaps.push_back(heap); + return fDescriptorHeaps[fDescriptorHeaps.size() - 1]->allocateTable(count); +} + +sk_sp<GrD3DDescriptorTableManager::Heap>& + GrD3DDescriptorTableManager::HeapPool::currentDescriptorHeap() { + SkASSERT(fDescriptorHeaps.size() > 0); + return fDescriptorHeaps[fDescriptorHeaps.size() - 1]; +} + +void GrD3DDescriptorTableManager::HeapPool::prepForSubmit(GrD3DGpu* gpu) { + // Pop off the current descriptor heap + if (fDescriptorHeaps[fDescriptorHeaps.size() - 1]->used()) { + fDescriptorHeaps.pop_back(); + } + + if (fDescriptorHeaps.size() == 0) { + fCurrentHeapDescriptorCount = std::min(fCurrentHeapDescriptorCount, 2048u); + sk_sp<GrD3DDescriptorTableManager::Heap> heap = + GrD3DDescriptorTableManager::Heap::Make(gpu, fHeapType, fCurrentHeapDescriptorCount); + fDescriptorHeaps.push_back(heap); + } +} + +void GrD3DDescriptorTableManager::HeapPool::recycle(sk_sp<Heap> heap) { + SkASSERT(heap); + // only add heaps back if they match our current size + // this purges any smaller heaps we no longer need + if (heap->descriptorCount() == fCurrentHeapDescriptorCount) { + heap->reset(); + fDescriptorHeaps.push_back(heap); + } +} diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorTableManager.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorTableManager.h new file mode 100644 index 00000000000..295b8680afc --- /dev/null +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DDescriptorTableManager.h @@ -0,0 +1,123 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrD3DGpuDescriptorTableManager_DEFINED +#define GrD3DGpuDescriptorTableManager_DEFINED + +#include "src/gpu/d3d/GrD3DDescriptorHeap.h" + +class GrD3DCommandList; +class GrD3DDirectCommandList; +class GrD3DGpu; + +class GrD3DDescriptorTable { +public: + GrD3DDescriptorTable(D3D12_CPU_DESCRIPTOR_HANDLE baseCPU, D3D12_GPU_DESCRIPTOR_HANDLE baseGPU, + D3D12_DESCRIPTOR_HEAP_TYPE type) + : fDescriptorTableCpuStart(baseCPU) + , fDescriptorTableGpuStart(baseGPU) + , fType(type) {} + + const D3D12_CPU_DESCRIPTOR_HANDLE* baseCpuDescriptorPtr() { + return &fDescriptorTableCpuStart; + } + + const D3D12_GPU_DESCRIPTOR_HANDLE baseGpuDescriptor() { + return fDescriptorTableGpuStart; + } + + D3D12_DESCRIPTOR_HEAP_TYPE type() const { return fType; } + +private: + D3D12_CPU_DESCRIPTOR_HANDLE fDescriptorTableCpuStart; + D3D12_GPU_DESCRIPTOR_HANDLE fDescriptorTableGpuStart; + D3D12_DESCRIPTOR_HEAP_TYPE fType; +}; + +class GrD3DDescriptorTableManager { +public: + GrD3DDescriptorTableManager(GrD3DGpu*); + + std::unique_ptr<GrD3DDescriptorTable> createShaderOrConstantResourceTable(GrD3DGpu*, + unsigned int count); + std::unique_ptr<GrD3DDescriptorTable> createSamplerTable(GrD3DGpu*, unsigned int count); + + void prepForSubmit(GrD3DGpu* gpu); + +private: + class Heap : public GrRecycledResource { + public: + static sk_sp<Heap> Make(GrD3DGpu* gpu, D3D12_DESCRIPTOR_HEAP_TYPE type, + unsigned int numDescriptors); + + std::unique_ptr<GrD3DDescriptorTable> allocateTable(unsigned int count); + bool canAllocate(unsigned int count) const { + return (fDescriptorCount - fNextAvailable) >= count; + } + ID3D12DescriptorHeap* d3dDescriptorHeap() const { return fHeap->descriptorHeap(); } + D3D12_DESCRIPTOR_HEAP_TYPE type() const { return fType; } + unsigned int descriptorCount() { return fDescriptorCount; } + bool used() { return fNextAvailable > 0; } + + void reset() { + fNextAvailable = 0; + } + + private: + Heap(GrD3DGpu* gpu, std::unique_ptr<GrD3DDescriptorHeap>& heap, + D3D12_DESCRIPTOR_HEAP_TYPE type, unsigned int descriptorCount) + : INHERITED() + , fGpu(gpu) + , fHeap(std::move(heap)) + , fType(type) + , fDescriptorCount(descriptorCount) + , fNextAvailable(0) { + } + + void freeGPUData() const override {} + void onRecycle() const override; + +#ifdef SK_TRACE_MANAGED_RESOURCES + void dumpInfo() const override { + SkDebugf("GrD3DDescriptorTable::Heap: %d (%d refs)\n", fHeap.get(), this->getRefCnt()); + } +#endif + + GrD3DGpu* fGpu; + std::unique_ptr<GrD3DDescriptorHeap> fHeap; + D3D12_DESCRIPTOR_HEAP_TYPE fType; + unsigned int fDescriptorCount; + unsigned int fNextAvailable; + + typedef GrRecycledResource INHERITED; + }; + + class HeapPool { + public: + HeapPool(GrD3DGpu*, D3D12_DESCRIPTOR_HEAP_TYPE); + + std::unique_ptr<GrD3DDescriptorTable> allocateTable(GrD3DGpu*, unsigned int count); + void recycle(sk_sp<Heap>); + sk_sp<Heap>& currentDescriptorHeap(); + void prepForSubmit(GrD3DGpu* gpu); + + private: + static constexpr int kInitialHeapDescriptorCount = 256; + + std::vector<sk_sp<Heap>> fDescriptorHeaps; + D3D12_DESCRIPTOR_HEAP_TYPE fHeapType; + unsigned int fCurrentHeapDescriptorCount; + }; + + void setHeaps(GrD3DGpu*); + void recycle(Heap*); + + HeapPool fCBVSRVDescriptorPool; + HeapPool fSamplerDescriptorPool; +}; + +#endif diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DGpu.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DGpu.cpp index fb79434c9e1..fbfc3c741bf 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DGpu.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DGpu.cpp @@ -11,6 +11,7 @@ #include "include/gpu/d3d/GrD3DBackendContext.h" #include "src/core/SkConvertPixels.h" #include "src/core/SkMipMap.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrDataUtils.h" #include "src/gpu/GrTexturePriv.h" #include "src/gpu/d3d/GrD3DBuffer.h" @@ -84,16 +85,19 @@ void GrD3DGpu::destroyResources() { // We used a placement new for each object in fOutstandingCommandLists, so we're responsible // for calling the destructor on each of them as well. while (!fOutstandingCommandLists.empty()) { - OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.back(); + OutstandingCommandList* list = (OutstandingCommandList*)fOutstandingCommandLists.front(); SkASSERT(list->fFenceValue <= fenceValue); // No reason to recycle the command lists since we are destroying all resources anyways. list->~OutstandingCommandList(); - fOutstandingCommandLists.pop_back(); + fOutstandingCommandLists.pop_front(); } + + fResourceProvider.destroyResources(); } GrOpsRenderPass* GrD3DGpu::getOpsRenderPass( - GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds, + GrRenderTarget* rt, GrStencilAttachment*, + GrSurfaceOrigin origin, const SkIRect& bounds, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { @@ -110,16 +114,23 @@ GrOpsRenderPass* GrD3DGpu::getOpsRenderPass( bool GrD3DGpu::submitDirectCommandList(SyncQueue sync) { SkASSERT(fCurrentDirectCommandList); + fResourceProvider.prepForSubmit(); + GrD3DDirectCommandList::SubmitResult result = fCurrentDirectCommandList->submit(fQueue.get()); if (result == GrD3DDirectCommandList::SubmitResult::kFailure) { return false; } else if (result == GrD3DDirectCommandList::SubmitResult::kNoWork) { if (sync == SyncQueue::kForce) { this->waitForQueueCompletion(); + this->checkForFinishedCommandLists(); } return true; } + // We just submitted the command list so make sure all GrD3DPipelineState's mark their cached + // uniform data as dirty. + fResourceProvider.markPipelineStateUniformsDirty(); + new (fOutstandingCommandLists.push_back()) OutstandingCommandList( std::move(fCurrentDirectCommandList), ++fCurrentFenceValue); @@ -180,6 +191,29 @@ void GrD3DGpu::submit(GrOpsRenderPass* renderPass) { fCachedOpsRenderPass.reset(); } +void GrD3DGpu::addFinishedProc(GrGpuFinishedProc finishedProc, + GrGpuFinishedContext finishedContext) { + SkASSERT(finishedProc); + sk_sp<GrRefCntedCallback> finishedCallback( + new GrRefCntedCallback(finishedProc, finishedContext)); + this->addFinishedCallback(std::move(finishedCallback)); +} + +void GrD3DGpu::addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback) { + SkASSERT(finishedCallback); + // Besides the current command list, we also add the finishedCallback to the newest outstanding + // command list. Our contract for calling the proc is that all previous submitted command lists + // have finished when we call it. However, if our current command list has no work when it is + // flushed it will drop its ref to the callback immediately. But the previous work may not have + // finished. It is safe to only add the proc to the newest outstanding commandlist cause that + // must finish after all previously submitted command lists. + OutstandingCommandList* back = (OutstandingCommandList*)fOutstandingCommandLists.back(); + if (back) { + back->fCommandList->addFinishedCallback(finishedCallback); + } + fCurrentDirectCommandList->addFinishedCallback(std::move(finishedCallback)); +} + void GrD3DGpu::querySampleLocations(GrRenderTarget* rt, SkTArray<SkPoint>* sampleLocations) { // TODO } @@ -561,14 +595,6 @@ bool GrD3DGpu::uploadToTexture(GrD3DTexture* tex, int left, int top, int width, return true; } -void GrD3DGpu::clear(const GrFixedClip& clip, const SkPMColor4f& color, GrRenderTarget* rt) { - GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(rt); - - d3dRT->setResourceState(this, D3D12_RESOURCE_STATE_RENDER_TARGET); - - fCurrentDirectCommandList->clearRenderTargetView(d3dRT, color, clip); -} - static bool check_resource_info(const GrD3DTextureResourceInfo& info) { if (!info.fResource.get()) { return false; @@ -884,10 +910,157 @@ GrBackendTexture GrD3DGpu::onCreateBackendTexture(SkISize dimensions, return GrBackendTexture(dimensions.width(), dimensions.height(), info); } +bool copy_src_data(GrD3DGpu* gpu, char* mapPtr, DXGI_FORMAT dxgiFormat, + D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints, + const SkPixmap srcData[], int numMipLevels) { + SkASSERT(srcData && numMipLevels); + SkASSERT(!GrDxgiFormatIsCompressed(dxgiFormat)); + SkASSERT(mapPtr); + + size_t bytesPerPixel = gpu->d3dCaps().bytesPerPixel(dxgiFormat); + + for (int currentMipLevel = 0; currentMipLevel < numMipLevels; currentMipLevel++) { + const size_t trimRowBytes = srcData[currentMipLevel].width() * bytesPerPixel; + + // copy data into the buffer, skipping any trailing bytes + char* dst = mapPtr + placedFootprints[currentMipLevel].Offset; + SkRectMemcpy(dst, placedFootprints[currentMipLevel].Footprint.RowPitch, + srcData[currentMipLevel].addr(), srcData[currentMipLevel].rowBytes(), + trimRowBytes, srcData[currentMipLevel].height()); + } + + return true; +} + +// Used to "clear" a backend texture to a constant color by transferring. +static GrColorType dxgi_format_to_backend_tex_clear_colortype(DXGI_FORMAT format) { + switch (format) { + case DXGI_FORMAT_A8_UNORM: return GrColorType::kAlpha_8; + case DXGI_FORMAT_R8_UNORM: return GrColorType::kR_8; + + case DXGI_FORMAT_B5G6R5_UNORM: return GrColorType::kBGR_565; + case DXGI_FORMAT_B4G4R4A4_UNORM: return GrColorType::kABGR_4444; + case DXGI_FORMAT_R8G8B8A8_UNORM: return GrColorType::kRGBA_8888; + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: return GrColorType::kRGBA_8888_SRGB; + + case DXGI_FORMAT_R8G8_UNORM: return GrColorType::kRG_88; + case DXGI_FORMAT_B8G8R8A8_UNORM: return GrColorType::kBGRA_8888; + case DXGI_FORMAT_R10G10B10A2_UNORM: return GrColorType::kRGBA_1010102; + case DXGI_FORMAT_R16_FLOAT: return GrColorType::kR_F16; + case DXGI_FORMAT_R16G16B16A16_FLOAT: return GrColorType::kRGBA_F16; + case DXGI_FORMAT_R16_UNORM: return GrColorType::kR_16; + case DXGI_FORMAT_R16G16_UNORM: return GrColorType::kRG_1616; + case DXGI_FORMAT_R16G16B16A16_UNORM: return GrColorType::kRGBA_16161616; + case DXGI_FORMAT_R16G16_FLOAT: return GrColorType::kRG_F16; + default: return GrColorType::kUnknown; + } + + SkUNREACHABLE; +} + + +bool copy_color_data(char* mapPtr, DXGI_FORMAT dxgiFormat, SkISize dimensions, + D3D12_PLACED_SUBRESOURCE_FOOTPRINT* placedFootprints, SkColor4f color) { + auto colorType = dxgi_format_to_backend_tex_clear_colortype(dxgiFormat); + if (colorType == GrColorType::kUnknown) { + return false; + } + GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, dimensions); + if (!GrClearImage(ii, mapPtr, placedFootprints[0].Footprint.RowPitch, color)) { + return false; + } + + return true; +} + bool GrD3DGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture, sk_sp<GrRefCntedCallback> finishedCallback, const BackendTextureData* data) { - // TODO: handle finishedCallback and data upload + GrD3DTextureResourceInfo info; + SkAssertResult(backendTexture.getD3DTextureResourceInfo(&info)); + + sk_sp<GrD3DResourceState> state = backendTexture.getGrD3DResourceState(); + SkASSERT(state); + sk_sp<GrD3DTexture> texture = + GrD3DTexture::MakeWrappedTexture(this, backendTexture.dimensions(), + GrWrapCacheable::kNo, + kRW_GrIOType, info, std::move(state)); + if (!texture) { + return false; + } + + GrD3DDirectCommandList* cmdList = this->currentCommandList(); + if (!cmdList) { + return false; + } + + texture->setResourceState(this, D3D12_RESOURCE_STATE_COPY_DEST); + + ID3D12Resource* d3dResource = texture->d3dResource(); + SkASSERT(d3dResource); + D3D12_RESOURCE_DESC desc = d3dResource->GetDesc(); + unsigned int mipLevelCount = 1; + if (backendTexture.fMipMapped == GrMipMapped::kYes) { + mipLevelCount = SkMipMap::ComputeLevelCount(backendTexture.dimensions().width(), + backendTexture.dimensions().height()) + 1; + } + SkASSERT(mipLevelCount == info.fLevelCount); + SkAutoTMalloc<D3D12_PLACED_SUBRESOURCE_FOOTPRINT> placedFootprints(mipLevelCount); + UINT64 combinedBufferSize; + fDevice->GetCopyableFootprints(&desc, 0, mipLevelCount, 0, placedFootprints.get(), + nullptr, nullptr, &combinedBufferSize); + SkASSERT(combinedBufferSize); + if (data->type() == BackendTextureData::Type::kColor && + !GrDxgiFormatIsCompressed(info.fFormat) && mipLevelCount > 1) { + // For a single uncompressed color, we reuse the same top-level buffer area for all levels. + combinedBufferSize = + placedFootprints[0].Footprint.RowPitch * placedFootprints[0].Footprint.Height; + for (unsigned int i = 1; i < mipLevelCount; ++i) { + placedFootprints[i].Offset = 0; + placedFootprints[i].Footprint.RowPitch = placedFootprints[0].Footprint.RowPitch; + } + } + + // TODO: do this until we have slices of buttery buffers + sk_sp<GrGpuBuffer> transferBuffer = this->createBuffer(combinedBufferSize, + GrGpuBufferType::kXferCpuToGpu, + kDynamic_GrAccessPattern); + if (!transferBuffer) { + return false; + } + char* bufferData = (char*)transferBuffer->map(); + SkASSERT(bufferData); + + bool result; + if (data->type() == BackendTextureData::Type::kPixmaps) { + result = copy_src_data(this, bufferData, info.fFormat, placedFootprints.get(), + data->pixmaps(), info.fLevelCount); + } else if (data->type() == BackendTextureData::Type::kCompressed) { + memcpy(bufferData, data->compressedData(), data->compressedSize()); + result = true; + } else { + SkASSERT(data->type() == BackendTextureData::Type::kColor); + SkImage::CompressionType compression = + GrBackendFormatToCompressionType(backendTexture.getBackendFormat()); + if (SkImage::CompressionType::kNone == compression) { + result = copy_color_data(bufferData, info.fFormat, backendTexture.dimensions(), + placedFootprints, data->color()); + } else { + GrFillInCompressedData(compression, backendTexture.dimensions(), + backendTexture.fMipMapped, bufferData, data->color()); + result = true; + } + } + transferBuffer->unmap(); + + GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(transferBuffer.get()); + cmdList->copyBufferToTexture(d3dBuffer, texture.get(), mipLevelCount, placedFootprints.get(), + 0, 0); + + if (finishedCallback) { + this->addFinishedCallback(std::move(finishedCallback)); + } + return true; } @@ -1006,6 +1179,31 @@ void GrD3DGpu::addResourceBarriers(sk_sp<GrManagedResource> resource, fCurrentDirectCommandList->resourceBarrier(std::move(resource), numBarriers, barriers); } +void GrD3DGpu::prepareSurfacesForBackendAccessAndStateUpdates( + GrSurfaceProxy* proxies[], + int numProxies, + SkSurface::BackendSurfaceAccess access, + const GrBackendSurfaceMutableState* newState) { + SkASSERT(numProxies >= 0); + SkASSERT(!numProxies || proxies); + + // prepare proxies by transitioning to PRESENT renderState + if (numProxies && access == SkSurface::BackendSurfaceAccess::kPresent) { + GrD3DTextureResource* resource; + for (int i = 0; i < numProxies; ++i) { + SkASSERT(proxies[i]->isInstantiated()); + if (GrTexture* tex = proxies[i]->peekTexture()) { + resource = static_cast<GrD3DTexture*>(tex); + } else { + GrRenderTarget* rt = proxies[i]->peekRenderTarget(); + SkASSERT(rt); + resource = static_cast<GrD3DRenderTarget*>(rt); + } + resource->prepareForPresent(this); + } + } +} + bool GrD3DGpu::onSubmitToGpu(bool syncCpu) { if (syncCpu) { return this->submitDirectCommandList(SyncQueue::kForce); diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DGpu.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DGpu.h index 3c1c9738a10..ce2488134c4 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DGpu.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DGpu.h @@ -64,13 +64,18 @@ public: void testingOnly_startCapture() override; void testingOnly_endCapture() override; + + void resetShaderCacheForTesting() const override { + fResourceProvider.resetShaderCacheForTesting(); + } #endif GrStencilAttachment* createStencilAttachmentForRenderTarget( const GrRenderTarget*, int width, int height, int numStencilSamples) override; GrOpsRenderPass* getOpsRenderPass( - GrRenderTarget*, GrSurfaceOrigin, const SkIRect&, + GrRenderTarget*, GrStencilAttachment*, + GrSurfaceOrigin, const SkIRect&, const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; @@ -98,11 +103,9 @@ public: return nullptr; } - void clear(const GrFixedClip& clip, const SkPMColor4f& color, GrRenderTarget*); - void submit(GrOpsRenderPass* renderPass) override; - void checkFinishProcs() override {} + void checkFinishProcs() override { this->checkForFinishedCommandLists(); } SkSL::Compiler* shaderCompiler() const { return fCompiler.get(); @@ -184,11 +187,14 @@ private: void onResolveRenderTarget(GrRenderTarget* target, const SkIRect&, ForExternalIO) override {} void addFinishedProc(GrGpuFinishedProc finishedProc, - GrGpuFinishedContext finishedContext) override { - // TODO: have this actually wait before calling the proc - SkASSERT(finishedProc); - finishedProc(finishedContext); - } + GrGpuFinishedContext finishedContext) override; + void addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback); + + void prepareSurfacesForBackendAccessAndStateUpdates( + GrSurfaceProxy* proxies[], + int numProxies, + SkSurface::BackendSurfaceAccess access, + const GrBackendSurfaceMutableState* newState) override; bool onSubmitToGpu(bool syncCpu) override; diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DOpsRenderPass.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DOpsRenderPass.cpp index bd681f9058f..baac3d222f2 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DOpsRenderPass.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DOpsRenderPass.cpp @@ -8,13 +8,16 @@ #include "src/gpu/d3d/GrD3DOpsRenderPass.h" #include "src/gpu/GrContextPriv.h" -#include "src/gpu/GrFixedClip.h" +#include "src/gpu/GrOpFlushState.h" #include "src/gpu/GrProgramDesc.h" #include "src/gpu/GrRenderTargetPriv.h" #include "src/gpu/GrStencilSettings.h" +#include "src/gpu/d3d/GrD3DBuffer.h" #include "src/gpu/d3d/GrD3DGpu.h" #include "src/gpu/d3d/GrD3DPipelineState.h" #include "src/gpu/d3d/GrD3DPipelineStateBuilder.h" +#include "src/gpu/d3d/GrD3DRenderTarget.h" +#include "src/gpu/d3d/GrD3DTexture.h" GrD3DOpsRenderPass::GrD3DOpsRenderPass(GrD3DGpu* gpu) : fGpu(gpu) {} @@ -41,11 +44,33 @@ GrD3DOpsRenderPass::~GrD3DOpsRenderPass() {} GrGpu* GrD3DOpsRenderPass::gpu() { return fGpu; } +void GrD3DOpsRenderPass::onBegin() { + GrD3DRenderTarget* d3dRT = static_cast<GrD3DRenderTarget*>(fRenderTarget); + d3dRT->setResourceState(fGpu, D3D12_RESOURCE_STATE_RENDER_TARGET); + fGpu->currentCommandList()->setRenderTarget(d3dRT); + + if (GrLoadOp::kClear == fColorLoadOp) { + // Passing in nullptr for the rect clears the entire d3d RT. Is this correct? Does the load + // op respect the logical bounds of a RT? + fGpu->currentCommandList()->clearRenderTargetView(d3dRT, fClearColor, nullptr); + } + + if (auto stencil = d3dRT->renderTargetPriv().getStencilAttachment()) { + GrD3DStencilAttachment* d3dStencil = static_cast<GrD3DStencilAttachment*>(stencil); + d3dStencil->setResourceState(fGpu, D3D12_RESOURCE_STATE_DEPTH_WRITE); + if (fStencilLoadOp == GrLoadOp::kClear) { + fGpu->currentCommandList()->clearDepthStencilView(d3dStencil, 0, nullptr); + } + } +} + void set_stencil_ref(GrD3DGpu* gpu, const GrProgramInfo& info) { GrStencilSettings stencilSettings = info.nonGLStencilSettings(); if (!stencilSettings.isDisabled()) { unsigned int stencilRef = 0; if (stencilSettings.isTwoSided()) { + SkASSERT(stencilSettings.postOriginCCWFace(info.origin()).fRef == + stencilSettings.postOriginCWFace(info.origin()).fRef); stencilRef = stencilSettings.postOriginCCWFace(info.origin()).fRef; } else { stencilRef = stencilSettings.singleSidedFace().fRef; @@ -97,6 +122,7 @@ void set_primitive_topology(GrD3DGpu* gpu, const GrProgramInfo& info) { default: SkUNREACHABLE; } + gpu->currentCommandList()->setPrimitiveTopology(topology); } void set_scissor_rects(GrD3DGpu* gpu, const GrRenderTarget* renderTarget, GrSurfaceOrigin rtOrigin, @@ -139,13 +165,16 @@ bool GrD3DOpsRenderPass::onBindPipeline(const GrProgramInfo& info, const SkRect& fCurrentPipelineBounds.setEmpty(); } - sk_sp<GrD3DPipelineState> pipelineState = + fCurrentPipelineState = fGpu->resourceProvider().findOrCreateCompatiblePipelineState(fRenderTarget, info); - if (!pipelineState) { + if (!fCurrentPipelineState) { return false; } - fGpu->currentCommandList()->setPipelineState(std::move(pipelineState)); + fGpu->currentCommandList()->setGraphicsRootSignature(fCurrentPipelineState->rootSignature()); + fGpu->currentCommandList()->setPipelineState(fCurrentPipelineState); + + fCurrentPipelineState->setAndBindConstants(fGpu, fRenderTarget, info); set_stencil_ref(fGpu, info); set_blend_factor(fGpu, info); @@ -159,13 +188,128 @@ bool GrD3DOpsRenderPass::onBindPipeline(const GrProgramInfo& info, const SkRect& return true; } -void GrD3DOpsRenderPass::onBegin() { - if (GrLoadOp::kClear == fColorLoadOp) { - GrFixedClip clip; - fGpu->clear(clip, fClearColor, fRenderTarget); +void GrD3DOpsRenderPass::onSetScissorRect(const SkIRect& scissor) { + SkIRect combinedScissorRect; + if (!combinedScissorRect.intersect(fCurrentPipelineBounds, scissor)) { + combinedScissorRect = SkIRect::MakeEmpty(); + } + + set_scissor_rects(fGpu, fRenderTarget, fOrigin, combinedScissorRect); +} + +void update_resource_state(GrTexture* tex, GrRenderTarget* rt, GrD3DGpu* gpu) { + SkASSERT(!tex->isProtected() || (rt->isProtected() && gpu->protectedContext())); + GrD3DTexture* d3dTex = static_cast<GrD3DTexture*>(tex); + SkASSERT(d3dTex); + d3dTex->setResourceState(gpu, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); +} + +bool GrD3DOpsRenderPass::onBindTextures(const GrPrimitiveProcessor& primProc, + const GrSurfaceProxy* const primProcTextures[], + const GrPipeline& pipeline) { + SkASSERT(fCurrentPipelineState); + + // update textures to sampled resource state + for (int i = 0; i < primProc.numTextureSamplers(); ++i) { + update_resource_state(primProcTextures[i]->peekTexture(), fRenderTarget, fGpu); + } + GrFragmentProcessor::PipelineTextureSamplerRange textureSamplerRange(pipeline); + for (auto [sampler, fp] : textureSamplerRange) { + update_resource_state(sampler.peekTexture(), fRenderTarget, fGpu); + } + if (GrTexture* dstTexture = pipeline.peekDstTexture()) { + update_resource_state(dstTexture, fRenderTarget, fGpu); + } + + // TODO: possibly check for success once we start binding properly + fCurrentPipelineState->setAndBindTextures(fGpu, primProc, primProcTextures, pipeline); + + return true; +} + +void GrD3DOpsRenderPass::onBindBuffers(const GrBuffer* indexBuffer, const GrBuffer* instanceBuffer, + const GrBuffer* vertexBuffer, + GrPrimitiveRestart primRestart) { + SkASSERT(GrPrimitiveRestart::kNo == primRestart); + SkASSERT(fCurrentPipelineState); + SkASSERT(!fGpu->caps()->usePrimitiveRestart()); // Ignore primitiveRestart parameter. + + GrD3DDirectCommandList* currCmdList = fGpu->currentCommandList(); + SkASSERT(currCmdList); + + // TODO: do we need a memory barrier here? + + fCurrentPipelineState->bindBuffers(fGpu, indexBuffer, instanceBuffer, vertexBuffer, + currCmdList); +} + +void GrD3DOpsRenderPass::onDrawInstanced(int instanceCount, int baseInstance, int vertexCount, + int baseVertex) { + SkASSERT(fCurrentPipelineState); + fGpu->currentCommandList()->drawInstanced(vertexCount, instanceCount, baseVertex, baseInstance); + fGpu->stats()->incNumDraws(); +} + +void GrD3DOpsRenderPass::onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, + int baseInstance, int baseVertex) { + SkASSERT(fCurrentPipelineState); + fGpu->currentCommandList()->drawIndexedInstanced(indexCount, instanceCount, baseIndex, + baseVertex, baseInstance); + fGpu->stats()->incNumDraws(); +} + +static D3D12_RECT scissor_to_d3d_clear_rect(const GrScissorState& scissor, + const GrSurface* surface, + GrSurfaceOrigin origin) { + D3D12_RECT clearRect; + // Flip rect if necessary + SkIRect d3dRect; + if (!scissor.enabled()) { + d3dRect.setXYWH(0, 0, surface->width(), surface->height()); + } else if (kBottomLeft_GrSurfaceOrigin != origin) { + d3dRect = scissor.rect(); + } else { + d3dRect.setLTRB(scissor.rect().fLeft, surface->height() - scissor.rect().fBottom, + scissor.rect().fRight, surface->height() - scissor.rect().fTop); } + clearRect.left = d3dRect.fLeft; + clearRect.right = d3dRect.fRight; + clearRect.top = d3dRect.fTop; + clearRect.bottom = d3dRect.fBottom; + return clearRect; +} + +void GrD3DOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) { + D3D12_RECT clearRect = scissor_to_d3d_clear_rect(scissor, fRenderTarget, fOrigin); + auto d3dRT = static_cast<GrD3DRenderTarget*>(fRenderTarget); + SkASSERT(d3dRT->grD3DResourceState()->getResourceState() == D3D12_RESOURCE_STATE_RENDER_TARGET); + fGpu->currentCommandList()->clearRenderTargetView(d3dRT, color, &clearRect); +} + +void GrD3DOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) { + GrStencilAttachment* sb = fRenderTarget->renderTargetPriv().getStencilAttachment(); + // this should only be called internally when we know we have a + // stencil buffer. + SkASSERT(sb); + int stencilBitCount = sb->bits(); + + // The contract with the callers does not guarantee that we preserve all bits in the stencil + // during this clear. Thus we will clear the entire stencil to the desired value. + + uint8_t stencilColor = 0; + if (insideStencilMask) { + stencilColor = (1 << (stencilBitCount - 1)); + } + + D3D12_RECT clearRect = scissor_to_d3d_clear_rect(scissor, fRenderTarget, fOrigin); + + auto d3dStencil = static_cast<GrD3DStencilAttachment*>(sb); + fGpu->currentCommandList()->clearDepthStencilView(d3dStencil, stencilColor, &clearRect); } -void GrD3DOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) { - fGpu->clear(clip, color, fRenderTarget); +void GrD3DOpsRenderPass::inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) { + // If we ever start using copy command lists for doing uploads, then we'll need to make sure + // we submit our main command list before doing the copy here and then start a new main command + // list. + state->doUpload(upload); } diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DOpsRenderPass.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DOpsRenderPass.h index 058d046422d..ed540bd7ed2 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DOpsRenderPass.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DOpsRenderPass.h @@ -14,6 +14,7 @@ #include "include/private/GrTypesPriv.h" class GrD3DGpu; +class GrD3DPipelineState; class GrD3DOpsRenderPass : public GrOpsRenderPass { public: @@ -21,7 +22,7 @@ public: ~GrD3DOpsRenderPass() override; - void inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) override {} + void inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) override; void onExecuteDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>) override {} @@ -36,31 +37,39 @@ private: void onBegin() override; bool onBindPipeline(const GrProgramInfo&, const SkRect& drawBounds) override; - void onSetScissorRect(const SkIRect&) override {} + void onSetScissorRect(const SkIRect&) override; bool onBindTextures(const GrPrimitiveProcessor&, const GrSurfaceProxy* const primProcTextures[], - const GrPipeline&) override { - return true; - } + const GrPipeline&) override; void onBindBuffers(const GrBuffer* indexBuffer, const GrBuffer* instanceBuffer, - const GrBuffer* vertexBuffer, GrPrimitiveRestart) override {} - void onDraw(int vertexCount, int baseVertex) override {} + const GrBuffer* vertexBuffer, GrPrimitiveRestart) override; + void onDraw(int vertexCount, int baseVertex) override { + this->onDrawInstanced(1, 0, vertexCount, baseVertex); + } void onDrawIndexed(int indexCount, int baseIndex, uint16_t minIndexValue, - uint16_t maxIndexValue, int baseVertex) override {} + uint16_t maxIndexValue, int baseVertex) override { + this->onDrawIndexedInstanced(indexCount, baseIndex, 1, 0, baseVertex); + } void onDrawInstanced(int instanceCount, int baseInstance, int vertexCount, - int baseVertex) override {} + int baseVertex) override; void onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, int baseInstance, - int baseVertex) override {} + int baseVertex) override; + void onDrawIndirect(const GrBuffer*, size_t offset, int drawCount) override {} + void onDrawIndexedIndirect(const GrBuffer*, size_t offset, int drawCount) override {} - void onClear(const GrFixedClip&, const SkPMColor4f& color) override; + void onClear(const GrScissorState& scissor, const SkPMColor4f& color) override; - void onClearStencilClip(const GrFixedClip&, bool insideStencilMask) override {} + void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override; GrD3DGpu* fGpu; + + sk_sp<GrD3DPipelineState> fCurrentPipelineState; + SkIRect fBounds; SkIRect fCurrentPipelineBounds; GrLoadOp fColorLoadOp; SkPMColor4f fClearColor; + GrLoadOp fStencilLoadOp; typedef GrOpsRenderPass INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineState.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineState.cpp index 21351763373..f7e3d6e26a4 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineState.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineState.cpp @@ -10,393 +10,183 @@ #include "include/private/SkTemplates.h" #include "src/gpu/GrProgramInfo.h" #include "src/gpu/GrStencilSettings.h" +#include "src/gpu/d3d/GrD3DBuffer.h" #include "src/gpu/d3d/GrD3DGpu.h" #include "src/gpu/d3d/GrD3DRootSignature.h" - -static DXGI_FORMAT attrib_type_to_format(GrVertexAttribType type) { - switch (type) { - case kFloat_GrVertexAttribType: - return DXGI_FORMAT_R32_FLOAT; - case kFloat2_GrVertexAttribType: - return DXGI_FORMAT_R32G32_FLOAT; - case kFloat3_GrVertexAttribType: - return DXGI_FORMAT_R32G32B32_FLOAT; - case kFloat4_GrVertexAttribType: - return DXGI_FORMAT_R32G32B32A32_FLOAT; - case kHalf_GrVertexAttribType: - return DXGI_FORMAT_R16_FLOAT; - case kHalf2_GrVertexAttribType: - return DXGI_FORMAT_R16G16_FLOAT; - case kHalf4_GrVertexAttribType: - return DXGI_FORMAT_R16G16B16A16_FLOAT; - case kInt2_GrVertexAttribType: - return DXGI_FORMAT_R32G32_SINT; - case kInt3_GrVertexAttribType: - return DXGI_FORMAT_R32G32B32_SINT; - case kInt4_GrVertexAttribType: - return DXGI_FORMAT_R32G32B32A32_SINT; - case kByte_GrVertexAttribType: - return DXGI_FORMAT_R8_SINT; - case kByte2_GrVertexAttribType: - return DXGI_FORMAT_R8G8_SINT; - case kByte4_GrVertexAttribType: - return DXGI_FORMAT_R8G8B8A8_SINT; - case kUByte_GrVertexAttribType: - return DXGI_FORMAT_R8_UINT; - case kUByte2_GrVertexAttribType: - return DXGI_FORMAT_R8G8_UINT; - case kUByte4_GrVertexAttribType: - return DXGI_FORMAT_R8G8B8A8_UINT; - case kUByte_norm_GrVertexAttribType: - return DXGI_FORMAT_R8_UNORM; - case kUByte4_norm_GrVertexAttribType: - return DXGI_FORMAT_R8G8B8A8_UNORM; - case kShort2_GrVertexAttribType: - return DXGI_FORMAT_R16G16_SINT; - case kShort4_GrVertexAttribType: - return DXGI_FORMAT_R16G16B16A16_SINT; - case kUShort2_GrVertexAttribType: - return DXGI_FORMAT_R16G16_UINT; - case kUShort2_norm_GrVertexAttribType: - return DXGI_FORMAT_R16G16_UNORM; - case kInt_GrVertexAttribType: - return DXGI_FORMAT_R32_SINT; - case kUint_GrVertexAttribType: - return DXGI_FORMAT_R32_UINT; - case kUShort_norm_GrVertexAttribType: - return DXGI_FORMAT_R16_UNORM; - case kUShort4_norm_GrVertexAttribType: - return DXGI_FORMAT_R16G16B16A16_UNORM; +#include "src/gpu/d3d/GrD3DTexture.h" +#include "src/gpu/glsl/GrGLSLFragmentProcessor.h" +#include "src/gpu/glsl/GrGLSLGeometryProcessor.h" +#include "src/gpu/glsl/GrGLSLXferProcessor.h" + +GrD3DPipelineState::GrD3DPipelineState( + gr_cp<ID3D12PipelineState> pipelineState, + sk_sp<GrD3DRootSignature> rootSignature, + const GrGLSLBuiltinUniformHandles& builtinUniformHandles, + const UniformInfoArray& uniforms, uint32_t uniformSize, + uint32_t numSamplers, + std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor, + std::unique_ptr<GrGLSLXferProcessor> xferProcessor, + std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors, + int fragmentProcessorCnt, + size_t vertexStride, + size_t instanceStride) + : fPipelineState(std::move(pipelineState)) + , fRootSignature(std::move(rootSignature)) + , fBuiltinUniformHandles(builtinUniformHandles) + , fGeometryProcessor(std::move(geometryProcessor)) + , fXferProcessor(std::move(xferProcessor)) + , fFragmentProcessors(std::move(fragmentProcessors)) + , fFragmentProcessorCnt(fragmentProcessorCnt) + , fDataManager(uniforms, uniformSize) + , fNumSamplers(numSamplers) + , fVertexStride(vertexStride) + , fInstanceStride(instanceStride) {} + +void GrD3DPipelineState::setAndBindConstants(GrD3DGpu* gpu, + const GrRenderTarget* renderTarget, + const GrProgramInfo& programInfo) { + this->setRenderTargetState(renderTarget, programInfo.origin()); + + GrFragmentProcessor::PipelineCoordTransformRange transformRange(programInfo.pipeline()); + fGeometryProcessor->setData(fDataManager, programInfo.primProc(), transformRange); + GrFragmentProcessor::CIter fpIter(programInfo.pipeline()); + GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt); + for (; fpIter && glslIter; ++fpIter, ++glslIter) { + glslIter->setData(fDataManager, *fpIter); } - SK_ABORT("Unknown vertex attrib type"); -} + SkASSERT(!fpIter && !glslIter); -static void setup_vertex_input_layout(const GrPrimitiveProcessor& primProc, - D3D12_INPUT_ELEMENT_DESC* inputElements) { - unsigned int slotNumber = 0; - unsigned int vertexSlot = 0; - unsigned int instanceSlot = 0; - if (primProc.hasVertexAttributes()) { - vertexSlot = slotNumber++; - } - if (primProc.hasInstanceAttributes()) { - instanceSlot = slotNumber++; - } + { + SkIPoint offset; + GrTexture* dstTexture = programInfo.pipeline().peekDstTexture(&offset); - unsigned int currentAttrib = 0; - unsigned int vertexAttributeOffset = 0; - - for (const auto& attrib : primProc.vertexAttributes()) { - // When using SPIRV-Cross it converts the location modifier in SPIRV to be - // TEXCOORD<N> where N is the location value for eveery vertext attribute - inputElements[currentAttrib] = {"TEXCOORD", currentAttrib, - attrib_type_to_format(attrib.cpuType()), - vertexSlot, vertexAttributeOffset, - D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}; - vertexAttributeOffset += attrib.sizeAlign4(); - currentAttrib++; + fXferProcessor->setData(fDataManager, programInfo.pipeline().getXferProcessor(), + dstTexture, offset); } - SkASSERT(vertexAttributeOffset == primProc.vertexStride()); - unsigned int instanceAttributeOffset = 0; - for (const auto& attrib : primProc.instanceAttributes()) { - // When using SPIRV-Cross it converts the location modifier in SPIRV to be - // TEXCOORD<N> where N is the location value for eveery vertext attribute - inputElements[currentAttrib] = {"TEXCOORD", currentAttrib, - attrib_type_to_format(attrib.cpuType()), - instanceSlot, instanceAttributeOffset, - D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0}; - instanceAttributeOffset += attrib.sizeAlign4(); - currentAttrib++; - } - SkASSERT(instanceAttributeOffset == primProc.instanceStride()); + D3D12_GPU_VIRTUAL_ADDRESS constantsAddress = fDataManager.uploadConstants(gpu); + gpu->currentCommandList()->setGraphicsRootConstantBufferView( + (unsigned int)(GrD3DRootSignature::ParamIndex::kConstantBufferView), + constantsAddress); } -static D3D12_BLEND blend_coeff_to_d3d_blend(GrBlendCoeff coeff) { - switch (coeff) { - case kZero_GrBlendCoeff: - return D3D12_BLEND_ZERO; - case kOne_GrBlendCoeff: - return D3D12_BLEND_ONE; - case kSC_GrBlendCoeff: - return D3D12_BLEND_SRC_COLOR; - case kISC_GrBlendCoeff: - return D3D12_BLEND_INV_SRC_COLOR; - case kDC_GrBlendCoeff: - return D3D12_BLEND_DEST_COLOR; - case kIDC_GrBlendCoeff: - return D3D12_BLEND_INV_DEST_COLOR; - case kSA_GrBlendCoeff: - return D3D12_BLEND_SRC_ALPHA; - case kISA_GrBlendCoeff: - return D3D12_BLEND_INV_SRC_ALPHA; - case kDA_GrBlendCoeff: - return D3D12_BLEND_DEST_ALPHA; - case kIDA_GrBlendCoeff: - return D3D12_BLEND_INV_DEST_ALPHA; - case kConstC_GrBlendCoeff: - return D3D12_BLEND_BLEND_FACTOR; - case kIConstC_GrBlendCoeff: - return D3D12_BLEND_INV_BLEND_FACTOR; - case kS2C_GrBlendCoeff: - return D3D12_BLEND_SRC1_COLOR; - case kIS2C_GrBlendCoeff: - return D3D12_BLEND_INV_SRC1_COLOR; - case kS2A_GrBlendCoeff: - return D3D12_BLEND_SRC1_ALPHA; - case kIS2A_GrBlendCoeff: - return D3D12_BLEND_INV_SRC1_ALPHA; - case kIllegal_GrBlendCoeff: - return D3D12_BLEND_ZERO; +void GrD3DPipelineState::setRenderTargetState(const GrRenderTarget* rt, GrSurfaceOrigin origin) { + // Load the RT height uniform if it is needed to y-flip gl_FragCoord. + if (fBuiltinUniformHandles.fRTHeightUni.isValid() && + fRenderTargetState.fRenderTargetSize.fHeight != rt->height()) { + fDataManager.set1f(fBuiltinUniformHandles.fRTHeightUni, SkIntToScalar(rt->height())); } - SkUNREACHABLE; -} -static D3D12_BLEND blend_coeff_to_d3d_blend_for_alpha(GrBlendCoeff coeff) { - switch (coeff) { - // Force all srcColor used in alpha slot to alpha version. - case kSC_GrBlendCoeff: - return D3D12_BLEND_SRC_ALPHA; - case kISC_GrBlendCoeff: - return D3D12_BLEND_INV_SRC_ALPHA; - case kDC_GrBlendCoeff: - return D3D12_BLEND_DEST_ALPHA; - case kIDC_GrBlendCoeff: - return D3D12_BLEND_INV_DEST_ALPHA; - case kS2C_GrBlendCoeff: - return D3D12_BLEND_SRC1_ALPHA; - case kIS2C_GrBlendCoeff: - return D3D12_BLEND_INV_SRC1_ALPHA; - - default: - return blend_coeff_to_d3d_blend(coeff); - } -} - - -static D3D12_BLEND_OP blend_equation_to_d3d_op(GrBlendEquation equation) { - switch (equation) { - case kAdd_GrBlendEquation: - return D3D12_BLEND_OP_ADD; - case kSubtract_GrBlendEquation: - return D3D12_BLEND_OP_SUBTRACT; - case kReverseSubtract_GrBlendEquation: - return D3D12_BLEND_OP_REV_SUBTRACT; - default: - SkUNREACHABLE; + // set RT adjustment + SkISize dimensions = rt->dimensions(); + SkASSERT(fBuiltinUniformHandles.fRTAdjustmentUni.isValid()); + if (fRenderTargetState.fRenderTargetOrigin != origin || + fRenderTargetState.fRenderTargetSize != dimensions) { + fRenderTargetState.fRenderTargetSize = dimensions; + fRenderTargetState.fRenderTargetOrigin = origin; + + float rtAdjustmentVec[4]; + fRenderTargetState.getRTAdjustmentVec(rtAdjustmentVec); + fDataManager.set4fv(fBuiltinUniformHandles.fRTAdjustmentUni, 1, rtAdjustmentVec); } } -static void fill_in_blend_state(const GrPipeline& pipeline, D3D12_BLEND_DESC* blendDesc) { - blendDesc->AlphaToCoverageEnable = false; - blendDesc->IndependentBlendEnable = false; - - const GrXferProcessor::BlendInfo& blendInfo = pipeline.getXferProcessor().getBlendInfo(); - - GrBlendEquation equation = blendInfo.fEquation; - GrBlendCoeff srcCoeff = blendInfo.fSrcBlend; - GrBlendCoeff dstCoeff = blendInfo.fDstBlend; - bool blendOff = GrBlendShouldDisable(equation, srcCoeff, dstCoeff); - - auto& rtBlend = blendDesc->RenderTarget[0]; - rtBlend.BlendEnable = !blendOff; - if (!blendOff) { - rtBlend.SrcBlend = blend_coeff_to_d3d_blend(srcCoeff); - rtBlend.DestBlend = blend_coeff_to_d3d_blend(dstCoeff); - rtBlend.BlendOp = blend_equation_to_d3d_op(equation); - rtBlend.SrcBlendAlpha = blend_coeff_to_d3d_blend_for_alpha(srcCoeff); - rtBlend.DestBlendAlpha = blend_coeff_to_d3d_blend_for_alpha(dstCoeff); - rtBlend.BlendOpAlpha = blend_equation_to_d3d_op(equation); +void GrD3DPipelineState::setAndBindTextures(GrD3DGpu* gpu, const GrPrimitiveProcessor& primProc, + const GrSurfaceProxy* const primProcTextures[], + const GrPipeline& pipeline) { + SkASSERT(primProcTextures || !primProc.numTextureSamplers()); + + SkAutoSTMalloc<8, D3D12_CPU_DESCRIPTOR_HANDLE> shaderResourceViews(fNumSamplers); + SkAutoSTMalloc<8, D3D12_CPU_DESCRIPTOR_HANDLE> samplers(fNumSamplers); + SkAutoSTMalloc<8, unsigned int> rangeSizes(fNumSamplers); + unsigned int currTextureBinding = 0; + + for (int i = 0; i < primProc.numTextureSamplers(); ++i) { + SkASSERT(primProcTextures[i]->asTextureProxy()); + const auto& sampler = primProc.textureSampler(i); + auto texture = static_cast<GrD3DTexture*>(primProcTextures[i]->peekTexture()); + shaderResourceViews[currTextureBinding] = texture->shaderResourceView(); + samplers[currTextureBinding] = + gpu->resourceProvider().findOrCreateCompatibleSampler(sampler.samplerState()); + gpu->currentCommandList()->addSampledTextureRef(texture); + rangeSizes[currTextureBinding++] = 1; } - if (!blendInfo.fWriteColor) { - rtBlend.RenderTargetWriteMask = 0; - } else { - rtBlend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + GrFragmentProcessor::CIter fpIter(pipeline); + GrGLSLFragmentProcessor::Iter glslIter(fFragmentProcessors.get(), fFragmentProcessorCnt); + for (; fpIter && glslIter; ++fpIter, ++glslIter) { + for (int i = 0; i < fpIter->numTextureSamplers(); ++i) { + const auto& sampler = fpIter->textureSampler(i); + auto texture = static_cast<GrD3DTexture*>(sampler.peekTexture()); + shaderResourceViews[currTextureBinding] = texture->shaderResourceView(); + samplers[currTextureBinding] = + gpu->resourceProvider().findOrCreateCompatibleSampler(sampler.samplerState()); + gpu->currentCommandList()->addSampledTextureRef(texture); + rangeSizes[currTextureBinding++] = 1; + } } -} - -static void fill_in_rasterizer_state(const GrPipeline& pipeline, const GrCaps* caps, - D3D12_RASTERIZER_DESC* rasterizer) { - rasterizer->FillMode = (caps->wireframeMode() || pipeline.isWireframe()) ? - D3D12_FILL_MODE_WIREFRAME : D3D12_FILL_MODE_SOLID; - rasterizer->CullMode = D3D12_CULL_MODE_NONE; - rasterizer->FrontCounterClockwise = true; - rasterizer->DepthBias = 0; - rasterizer->DepthBiasClamp = 0.0f; - rasterizer->SlopeScaledDepthBias = 0.0f; - rasterizer->DepthClipEnable = false; - rasterizer->MultisampleEnable = pipeline.isHWAntialiasState(); - rasterizer->AntialiasedLineEnable = false; - rasterizer->ForcedSampleCount = 0; - rasterizer->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; -} - -static D3D12_STENCIL_OP stencil_op_to_d3d_op(GrStencilOp op) { - switch (op) { - case GrStencilOp::kKeep: - return D3D12_STENCIL_OP_KEEP; - case GrStencilOp::kZero: - return D3D12_STENCIL_OP_ZERO; - case GrStencilOp::kReplace: - return D3D12_STENCIL_OP_REPLACE; - case GrStencilOp::kInvert: - return D3D12_STENCIL_OP_INVERT; - case GrStencilOp::kIncWrap: - return D3D12_STENCIL_OP_INCR; - case GrStencilOp::kDecWrap: - return D3D12_STENCIL_OP_DECR; - case GrStencilOp::kIncClamp: - return D3D12_STENCIL_OP_INCR_SAT; - case GrStencilOp::kDecClamp: - return D3D12_STENCIL_OP_DECR_SAT; + SkASSERT(!fpIter && !glslIter); + + if (GrTexture* dstTexture = pipeline.peekDstTexture()) { + auto texture = static_cast<GrD3DTexture*>(dstTexture); + shaderResourceViews[currTextureBinding] = texture->shaderResourceView(); + samplers[currTextureBinding] = gpu->resourceProvider().findOrCreateCompatibleSampler( + GrSamplerState::Filter::kNearest); + gpu->currentCommandList()->addSampledTextureRef(texture); + rangeSizes[currTextureBinding++] = 1; } - SkUNREACHABLE; -} -static D3D12_COMPARISON_FUNC stencil_test_to_d3d_func(GrStencilTest test) { - switch (test) { - case GrStencilTest::kAlways: - return D3D12_COMPARISON_FUNC_ALWAYS; - case GrStencilTest::kNever: - return D3D12_COMPARISON_FUNC_NEVER; - case GrStencilTest::kGreater: - return D3D12_COMPARISON_FUNC_GREATER; - case GrStencilTest::kGEqual: - return D3D12_COMPARISON_FUNC_GREATER_EQUAL; - case GrStencilTest::kLess: - return D3D12_COMPARISON_FUNC_LESS; - case GrStencilTest::kLEqual: - return D3D12_COMPARISON_FUNC_LESS_EQUAL; - case GrStencilTest::kEqual: - return D3D12_COMPARISON_FUNC_EQUAL; - case GrStencilTest::kNotEqual: - return D3D12_COMPARISON_FUNC_NOT_EQUAL; + SkASSERT(fNumSamplers == currTextureBinding); + + // fill in descriptor tables and bind to root signature + if (fNumSamplers > 0) { + // set up and bind shader resource view table + std::unique_ptr<GrD3DDescriptorTable> srvTable = + gpu->resourceProvider().createShaderOrConstantResourceTable(fNumSamplers); + gpu->device()->CopyDescriptors(1, srvTable->baseCpuDescriptorPtr(), &fNumSamplers, + fNumSamplers, shaderResourceViews.get(), rangeSizes.get(), + srvTable->type()); + gpu->currentCommandList()->setGraphicsRootDescriptorTable( + static_cast<unsigned int>(GrD3DRootSignature::ParamIndex::kTextureDescriptorTable), + srvTable->baseGpuDescriptor()); + + // set up and bind sampler table + std::unique_ptr<GrD3DDescriptorTable> samplerTable = + gpu->resourceProvider().createSamplerTable(fNumSamplers); + gpu->device()->CopyDescriptors(1, samplerTable->baseCpuDescriptorPtr(), &fNumSamplers, + fNumSamplers, samplers.get(), rangeSizes.get(), + samplerTable->type()); + gpu->currentCommandList()->setGraphicsRootDescriptorTable( + static_cast<unsigned int>(GrD3DRootSignature::ParamIndex::kSamplerDescriptorTable), + samplerTable->baseGpuDescriptor()); } - SkUNREACHABLE; -} - -static void setup_stencilop_desc(D3D12_DEPTH_STENCILOP_DESC* desc, - const GrStencilSettings::Face& stencilFace) { - desc->StencilFailOp = stencil_op_to_d3d_op(stencilFace.fFailOp); - desc->StencilDepthFailOp = desc->StencilFailOp; - desc->StencilPassOp = stencil_op_to_d3d_op(stencilFace.fPassOp); - desc->StencilFunc = stencil_test_to_d3d_func(stencilFace.fTest); } -static void fill_in_depth_stencil_state(const GrProgramInfo& programInfo, - D3D12_DEPTH_STENCIL_DESC* dsDesc) { - GrStencilSettings stencilSettings = programInfo.nonGLStencilSettings(); - GrSurfaceOrigin origin = programInfo.origin(); - - dsDesc->DepthEnable = false; - dsDesc->DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; - dsDesc->DepthFunc = D3D12_COMPARISON_FUNC_NEVER; - dsDesc->StencilEnable = !stencilSettings.isDisabled(); - if (!stencilSettings.isDisabled()) { - if (stencilSettings.isTwoSided()) { - const auto& frontFace = stencilSettings.postOriginCCWFace(origin); - const auto& backFace = stencilSettings.postOriginCCWFace(origin); - - SkASSERT(frontFace.fTestMask == backFace.fTestMask); - SkASSERT(frontFace.fWriteMask == backFace.fWriteMask); - dsDesc->StencilReadMask = frontFace.fTestMask; - dsDesc->StencilWriteMask = frontFace.fWriteMask; - - setup_stencilop_desc(&dsDesc->FrontFace, frontFace); - setup_stencilop_desc(&dsDesc->BackFace, backFace); - } else { - dsDesc->StencilReadMask = stencilSettings.singleSidedFace().fTestMask; - dsDesc->StencilWriteMask = stencilSettings.singleSidedFace().fTestMask; - setup_stencilop_desc(&dsDesc->FrontFace, stencilSettings.singleSidedFace()); - dsDesc->BackFace = dsDesc->FrontFace; +void GrD3DPipelineState::bindBuffers(GrD3DGpu* gpu, const GrBuffer* indexBuffer, + const GrBuffer* instanceBuffer, const GrBuffer* vertexBuffer, + GrD3DDirectCommandList* commandList) { + // Here our vertex and instance inputs need to match the same 0-based bindings they were + // assigned in the PipelineState. That is, vertex first (if any) followed by instance. + if (auto* d3dVertexBuffer = static_cast<const GrD3DBuffer*>(vertexBuffer)) { + SkASSERT(!d3dVertexBuffer->isCpuBuffer()); + SkASSERT(!d3dVertexBuffer->isMapped()); + const_cast<GrD3DBuffer*>(d3dVertexBuffer)->setResourceState( + gpu, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); + auto* d3dInstanceBuffer = static_cast<const GrD3DBuffer*>(instanceBuffer); + if (d3dInstanceBuffer) { + SkASSERT(!d3dInstanceBuffer->isCpuBuffer()); + SkASSERT(!d3dInstanceBuffer->isMapped()); + const_cast<GrD3DBuffer*>(d3dInstanceBuffer)->setResourceState( + gpu, D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER); } + commandList->setVertexBuffers(0, d3dVertexBuffer, fVertexStride, + d3dInstanceBuffer, fInstanceStride); } -} - -static D3D12_PRIMITIVE_TOPOLOGY_TYPE gr_primitive_type_to_d3d(GrPrimitiveType primitiveType) { - switch (primitiveType) { - case GrPrimitiveType::kTriangles: - case GrPrimitiveType::kTriangleStrip: //fall through - return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - case GrPrimitiveType::kPoints: - return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; - case GrPrimitiveType::kLines: // fall through - case GrPrimitiveType::kLineStrip: - return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; - case GrPrimitiveType::kPatches: // fall through, unsupported - case GrPrimitiveType::kPath: // fall through, unsupported - default: - SkUNREACHABLE; + if (auto* d3dIndexBuffer = static_cast<const GrD3DBuffer*>(indexBuffer)) { + SkASSERT(!d3dIndexBuffer->isCpuBuffer()); + SkASSERT(!d3dIndexBuffer->isMapped()); + const_cast<GrD3DBuffer*>(d3dIndexBuffer)->setResourceState( + gpu, D3D12_RESOURCE_STATE_INDEX_BUFFER); + commandList->setIndexBuffer(d3dIndexBuffer); } } - -sk_sp<GrD3DPipelineState> GrD3DPipelineState::Make(GrD3DGpu* gpu, - const GrProgramInfo& programInfo, - sk_sp<GrD3DRootSignature> rootSig, - gr_cp<ID3DBlob> vertexShader, - gr_cp<ID3DBlob> geometryShader, - gr_cp<ID3DBlob> pixelShader, - DXGI_FORMAT renderTargetFormat, - DXGI_FORMAT depthStencilFormat, - unsigned int sampleQualityLevel) { - D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; - - psoDesc.pRootSignature = rootSig->rootSignature(); - - psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()), - vertexShader->GetBufferSize() }; - psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()), - pixelShader->GetBufferSize() }; - - if (geometryShader.get()) { - psoDesc.GS = { reinterpret_cast<UINT8*>(geometryShader->GetBufferPointer()), - geometryShader->GetBufferSize() }; - } - - psoDesc.StreamOutput = {nullptr, 0, nullptr, 0, 0}; - - fill_in_blend_state(programInfo.pipeline(), &psoDesc.BlendState); - psoDesc.SampleMask = UINT_MAX; - - fill_in_rasterizer_state(programInfo.pipeline(), gpu->caps(), &psoDesc.RasterizerState); - - fill_in_depth_stencil_state(programInfo, &psoDesc.DepthStencilState); - - unsigned int totalAttributeCnt = programInfo.primProc().numVertexAttributes() + - programInfo.primProc().numInstanceAttributes(); - SkAutoSTArray<4, D3D12_INPUT_ELEMENT_DESC> inputElements(totalAttributeCnt); - setup_vertex_input_layout(programInfo.primProc(), inputElements.get()); - - psoDesc.InputLayout = { inputElements.get(), totalAttributeCnt }; - - psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; - - // This is for geometry or hull shader primitives - psoDesc.PrimitiveTopologyType = gr_primitive_type_to_d3d(programInfo.primitiveType()); - - psoDesc.NumRenderTargets = 1; - - psoDesc.RTVFormats[0] = renderTargetFormat; - - psoDesc.DSVFormat = depthStencilFormat; - - unsigned int numRasterSamples = programInfo.numRasterSamples(); - psoDesc.SampleDesc = {numRasterSamples, sampleQualityLevel}; - - // Only used for multi-adapter systems. - psoDesc.NodeMask = 0; - - psoDesc.CachedPSO = {nullptr, 0}; - psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; - - gr_cp<ID3D12PipelineState> pipelineState; - SkDEBUGCODE(HRESULT hr = )gpu->device()->CreateGraphicsPipelineState( - &psoDesc, IID_PPV_ARGS(&pipelineState)); - SkASSERT(SUCCEEDED(hr)); - - return sk_sp<GrD3DPipelineState>(new GrD3DPipelineState(std::move(pipelineState))); -} - -GrD3DPipelineState::GrD3DPipelineState(gr_cp<ID3D12PipelineState> pipelineState) - : fPipelineState(std::move(pipelineState)) {} diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineState.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineState.h index b6eb50a8d24..0925571d950 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineState.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineState.h @@ -12,21 +12,30 @@ #include "include/gpu/GrTypes.h" #include "include/gpu/d3d/GrD3DTypes.h" #include "src/gpu/GrManagedResource.h" +#include "src/gpu/d3d/GrD3DPipelineStateDataManager.h" +#include "src/gpu/glsl/GrGLSLProgramBuilder.h" +class GrD3DDirectCommandList; class GrD3DGpu; class GrD3DRootSignature; class GrProgramInfo; class GrD3DPipelineState : public GrManagedResource { public: - static sk_sp<GrD3DPipelineState> Make(GrD3DGpu* gpu, const GrProgramInfo&, - sk_sp<GrD3DRootSignature> rootSig, - gr_cp<ID3DBlob> vertexShader, - gr_cp<ID3DBlob> geometryShader, - gr_cp<ID3DBlob> pixelShader, - DXGI_FORMAT renderTargetFormat, - DXGI_FORMAT depthStencilFormat, - unsigned int sampleQualityLevel); + using UniformInfoArray = GrD3DPipelineStateDataManager::UniformInfoArray; + + GrD3DPipelineState(gr_cp<ID3D12PipelineState> pipelineState, + sk_sp<GrD3DRootSignature> rootSignature, + const GrGLSLBuiltinUniformHandles& builtinUniformHandles, + const UniformInfoArray& uniforms, + uint32_t uniformSize, + uint32_t numSamplers, + std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor, + std::unique_ptr<GrGLSLXferProcessor> xferProcessor, + std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragProcessors, + int fragmentProcessorCnt, + size_t vertexStride, + size_t instanceStride); #ifdef SK_TRACE_MANAGED_RESOURCES /** Output a human-readable dump of this resource's information @@ -41,12 +50,81 @@ public: void freeGPUData() const override {} ID3D12PipelineState* pipelineState() const { return fPipelineState.get(); } + const sk_sp<GrD3DRootSignature>& rootSignature() const { return fRootSignature; } + + void setAndBindConstants(GrD3DGpu*, const GrRenderTarget*, const GrProgramInfo&); + + void setAndBindTextures(GrD3DGpu*, const GrPrimitiveProcessor& primProc, + const GrSurfaceProxy* const primProcTextures[], + const GrPipeline& pipeline); + + void bindBuffers(GrD3DGpu*, const GrBuffer* indexBuffer, const GrBuffer* instanceBuffer, + const GrBuffer* vertexBuffer, GrD3DDirectCommandList* commandList); + + // We can only cache non dirty uniform values until we submit a command list. After that, the + // next frame will get a completely different uniform buffer and/or offset into the buffer. Thus + // we need a way to mark them all as dirty during submit. + void markUniformsDirty() { fDataManager.markDirty(); } private: - GrD3DPipelineState(gr_cp<ID3D12PipelineState> pipelineState); + /** + * We use the RT's size and origin to adjust from Skia device space to d3d normalized device + * space and to make device space positions have the correct origin for processors that require + * them. + */ + struct RenderTargetState { + SkISize fRenderTargetSize; + GrSurfaceOrigin fRenderTargetOrigin; + + RenderTargetState() { this->invalidate(); } + void invalidate() { + fRenderTargetSize.fWidth = -1; + fRenderTargetSize.fHeight = -1; + fRenderTargetOrigin = (GrSurfaceOrigin)-1; + } + + /** + * Gets a float4 that adjusts the position from Skia device coords to D3D's normalized device + * coords. Assuming the transformed position, pos, is a homogeneous float3, the vec, v, is + * applied as such: + * pos.x = dot(v.xy, pos.xz) + * pos.y = dot(v.zw, pos.yz) + */ + void getRTAdjustmentVec(float* destVec) { + destVec[0] = 2.f / fRenderTargetSize.fWidth; + destVec[1] = -1.f; + // D3D's NDC space is flipped from Vulkan and Metal + if (kTopLeft_GrSurfaceOrigin == fRenderTargetOrigin) { + destVec[2] = -2.f / fRenderTargetSize.fHeight; + destVec[3] = 1.f; + } else { + destVec[2] = 2.f / fRenderTargetSize.fHeight; + destVec[3] = -1.f; + } + } + }; + + // Helper for setData() that sets the view matrix and loads the render target height uniform + void setRenderTargetState(const GrRenderTarget*, GrSurfaceOrigin); gr_cp<ID3D12PipelineState> fPipelineState; + sk_sp<GrD3DRootSignature> fRootSignature; + + // Tracks the current render target uniforms stored in the vertex buffer. + RenderTargetState fRenderTargetState; + GrGLSLBuiltinUniformHandles fBuiltinUniformHandles; + + // Processors in the GrD3DPipelineState + std::unique_ptr<GrGLSLPrimitiveProcessor> fGeometryProcessor; + std::unique_ptr<GrGLSLXferProcessor> fXferProcessor; + std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors; + int fFragmentProcessorCnt; + + GrD3DPipelineStateDataManager fDataManager; + unsigned int fNumSamplers; + size_t fVertexStride; + size_t fInstanceStride; }; #endif diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp index f03858ec832..5c2b91f509d 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateBuilder.cpp @@ -14,6 +14,7 @@ #include "src/core/SkTraceEvent.h" #include "src/gpu/GrAutoLocaleSetter.h" #include "src/gpu/GrContextPriv.h" +#include "src/gpu/GrPersistentCacheUtils.h" #include "src/gpu/GrShaderCaps.h" #include "src/gpu/GrShaderUtils.h" #include "src/gpu/GrStencilSettings.h" @@ -24,8 +25,6 @@ #include <d3dcompiler.h> -typedef size_t shader_size; - sk_sp<GrD3DPipelineState> GrD3DPipelineStateBuilder::MakePipelineState( GrD3DGpu* gpu, GrRenderTarget* renderTarget, @@ -66,27 +65,9 @@ void GrD3DPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outp outputColor.addLayoutQualifier("location = 0, index = 1"); } -void GrD3DPipelineStateBuilder::compileD3DProgram(SkSL::Program::Kind kind, - const SkSL::String& sksl, - const SkSL::Program::Settings& settings, - ID3DBlob** shader, - SkSL::Program::Inputs* outInputs) { - auto errorHandler = fGpu->getContext()->priv().getShaderErrorHandler(); - std::unique_ptr<SkSL::Program> program = fGpu->shaderCompiler()->convertProgram( - kind, sksl, settings); - if (!program) { - errorHandler->compileError(sksl.c_str(), - fGpu->shaderCompiler()->errorText().c_str()); - return; - } - *outInputs = program->fInputs; - SkSL::String outHLSL; - if (!fGpu->shaderCompiler()->toHLSL(*program, &outHLSL)) { - errorHandler->compileError(sksl.c_str(), - fGpu->shaderCompiler()->errorText().c_str()); - return; - } - +static gr_cp<ID3DBlob> GrCompileHLSLShader(GrD3DGpu* gpu, + const SkSL::String& hlsl, + SkSL::Program::Kind kind) { const char* compileTarget = nullptr; switch (kind) { case SkSL::Program::kVertex_Kind: @@ -110,16 +91,452 @@ void GrD3DPipelineStateBuilder::compileD3DProgram(SkSL::Program::Kind kind, // SPRIV-cross does matrix multiplication expecting row major matrices compileFlags |= D3DCOMPILE_PACK_MATRIX_ROW_MAJOR; - // TODO: D3D Static Function + gr_cp<ID3DBlob> shader; gr_cp<ID3DBlob> errors; - HRESULT hr = D3DCompile(outHLSL.c_str(), outHLSL.length(), nullptr, nullptr, nullptr, "main", - compileTarget, compileFlags, 0, shader, &errors); + HRESULT hr = D3DCompile(hlsl.c_str(), hlsl.length(), nullptr, nullptr, nullptr, "main", + compileTarget, compileFlags, 0, &shader, &errors); if (!SUCCEEDED(hr)) { - errorHandler->compileError(outHLSL.c_str(), - reinterpret_cast<char*>(errors->GetBufferPointer())); + gpu->getContext()->priv().getShaderErrorHandler()->compileError( + hlsl.c_str(), reinterpret_cast<char*>(errors->GetBufferPointer())); + } + return shader; +} + +bool GrD3DPipelineStateBuilder::loadHLSLFromCache(SkReadBuffer* reader, gr_cp<ID3DBlob> shaders[]) { + + SkSL::String hlsl[kGrShaderTypeCount]; + SkSL::Program::Inputs inputs[kGrShaderTypeCount]; + + if (!GrPersistentCacheUtils::UnpackCachedShaders(reader, hlsl, inputs, kGrShaderTypeCount)) { + return false; } + + auto compile = [&](SkSL::Program::Kind kind, GrShaderType shaderType) { + if (inputs[shaderType].fRTHeight) { + this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); + } + shaders[shaderType] = GrCompileHLSLShader(fGpu, hlsl[shaderType], kind); + return shaders[shaderType].get(); + }; + + return compile(SkSL::Program::kVertex_Kind, kVertex_GrShaderType) && + compile(SkSL::Program::kFragment_Kind, kFragment_GrShaderType) && + (hlsl[kGeometry_GrShaderType].empty() || + compile(SkSL::Program::kGeometry_Kind, kGeometry_GrShaderType)); } +gr_cp<ID3DBlob> GrD3DPipelineStateBuilder::compileD3DProgram( + SkSL::Program::Kind kind, + const SkSL::String& sksl, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* outInputs, + SkSL::String* outHLSL) { + auto errorHandler = fGpu->getContext()->priv().getShaderErrorHandler(); + std::unique_ptr<SkSL::Program> program = fGpu->shaderCompiler()->convertProgram( + kind, sksl, settings); + if (!program) { + errorHandler->compileError(sksl.c_str(), + fGpu->shaderCompiler()->errorText().c_str()); + return gr_cp<ID3DBlob>(); + } + *outInputs = program->fInputs; + if (!fGpu->shaderCompiler()->toHLSL(*program, outHLSL)) { + errorHandler->compileError(sksl.c_str(), + fGpu->shaderCompiler()->errorText().c_str()); + return gr_cp<ID3DBlob>(); + } + + if (program->fInputs.fRTHeight) { + this->addRTHeightUniform(SKSL_RTHEIGHT_NAME); + } + + return GrCompileHLSLShader(fGpu, *outHLSL, kind); +} + +static DXGI_FORMAT attrib_type_to_format(GrVertexAttribType type) { + switch (type) { + case kFloat_GrVertexAttribType: + return DXGI_FORMAT_R32_FLOAT; + case kFloat2_GrVertexAttribType: + return DXGI_FORMAT_R32G32_FLOAT; + case kFloat3_GrVertexAttribType: + return DXGI_FORMAT_R32G32B32_FLOAT; + case kFloat4_GrVertexAttribType: + return DXGI_FORMAT_R32G32B32A32_FLOAT; + case kHalf_GrVertexAttribType: + return DXGI_FORMAT_R16_FLOAT; + case kHalf2_GrVertexAttribType: + return DXGI_FORMAT_R16G16_FLOAT; + case kHalf4_GrVertexAttribType: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + case kInt2_GrVertexAttribType: + return DXGI_FORMAT_R32G32_SINT; + case kInt3_GrVertexAttribType: + return DXGI_FORMAT_R32G32B32_SINT; + case kInt4_GrVertexAttribType: + return DXGI_FORMAT_R32G32B32A32_SINT; + case kByte_GrVertexAttribType: + return DXGI_FORMAT_R8_SINT; + case kByte2_GrVertexAttribType: + return DXGI_FORMAT_R8G8_SINT; + case kByte4_GrVertexAttribType: + return DXGI_FORMAT_R8G8B8A8_SINT; + case kUByte_GrVertexAttribType: + return DXGI_FORMAT_R8_UINT; + case kUByte2_GrVertexAttribType: + return DXGI_FORMAT_R8G8_UINT; + case kUByte4_GrVertexAttribType: + return DXGI_FORMAT_R8G8B8A8_UINT; + case kUByte_norm_GrVertexAttribType: + return DXGI_FORMAT_R8_UNORM; + case kUByte4_norm_GrVertexAttribType: + return DXGI_FORMAT_R8G8B8A8_UNORM; + case kShort2_GrVertexAttribType: + return DXGI_FORMAT_R16G16_SINT; + case kShort4_GrVertexAttribType: + return DXGI_FORMAT_R16G16B16A16_SINT; + case kUShort2_GrVertexAttribType: + return DXGI_FORMAT_R16G16_UINT; + case kUShort2_norm_GrVertexAttribType: + return DXGI_FORMAT_R16G16_UNORM; + case kInt_GrVertexAttribType: + return DXGI_FORMAT_R32_SINT; + case kUint_GrVertexAttribType: + return DXGI_FORMAT_R32_UINT; + case kUShort_norm_GrVertexAttribType: + return DXGI_FORMAT_R16_UNORM; + case kUShort4_norm_GrVertexAttribType: + return DXGI_FORMAT_R16G16B16A16_UNORM; + } + SK_ABORT("Unknown vertex attrib type"); +} + +static void setup_vertex_input_layout(const GrPrimitiveProcessor& primProc, + D3D12_INPUT_ELEMENT_DESC* inputElements) { + unsigned int slotNumber = 0; + unsigned int vertexSlot = 0; + unsigned int instanceSlot = 0; + if (primProc.hasVertexAttributes()) { + vertexSlot = slotNumber++; + } + if (primProc.hasInstanceAttributes()) { + instanceSlot = slotNumber++; + } + + unsigned int currentAttrib = 0; + unsigned int vertexAttributeOffset = 0; + + for (const auto& attrib : primProc.vertexAttributes()) { + // When using SPIRV-Cross it converts the location modifier in SPIRV to be + // TEXCOORD<N> where N is the location value for eveery vertext attribute + inputElements[currentAttrib] = { "TEXCOORD", currentAttrib, + attrib_type_to_format(attrib.cpuType()), + vertexSlot, vertexAttributeOffset, + D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }; + vertexAttributeOffset += attrib.sizeAlign4(); + currentAttrib++; + } + SkASSERT(vertexAttributeOffset == primProc.vertexStride()); + + unsigned int instanceAttributeOffset = 0; + for (const auto& attrib : primProc.instanceAttributes()) { + // When using SPIRV-Cross it converts the location modifier in SPIRV to be + // TEXCOORD<N> where N is the location value for eveery vertext attribute + inputElements[currentAttrib] = { "TEXCOORD", currentAttrib, + attrib_type_to_format(attrib.cpuType()), + instanceSlot, instanceAttributeOffset, + D3D12_INPUT_CLASSIFICATION_PER_INSTANCE_DATA, 1 }; + instanceAttributeOffset += attrib.sizeAlign4(); + currentAttrib++; + } + SkASSERT(instanceAttributeOffset == primProc.instanceStride()); +} + +static D3D12_BLEND blend_coeff_to_d3d_blend(GrBlendCoeff coeff) { + switch (coeff) { + case kZero_GrBlendCoeff: + return D3D12_BLEND_ZERO; + case kOne_GrBlendCoeff: + return D3D12_BLEND_ONE; + case kSC_GrBlendCoeff: + return D3D12_BLEND_SRC_COLOR; + case kISC_GrBlendCoeff: + return D3D12_BLEND_INV_SRC_COLOR; + case kDC_GrBlendCoeff: + return D3D12_BLEND_DEST_COLOR; + case kIDC_GrBlendCoeff: + return D3D12_BLEND_INV_DEST_COLOR; + case kSA_GrBlendCoeff: + return D3D12_BLEND_SRC_ALPHA; + case kISA_GrBlendCoeff: + return D3D12_BLEND_INV_SRC_ALPHA; + case kDA_GrBlendCoeff: + return D3D12_BLEND_DEST_ALPHA; + case kIDA_GrBlendCoeff: + return D3D12_BLEND_INV_DEST_ALPHA; + case kConstC_GrBlendCoeff: + return D3D12_BLEND_BLEND_FACTOR; + case kIConstC_GrBlendCoeff: + return D3D12_BLEND_INV_BLEND_FACTOR; + case kS2C_GrBlendCoeff: + return D3D12_BLEND_SRC1_COLOR; + case kIS2C_GrBlendCoeff: + return D3D12_BLEND_INV_SRC1_COLOR; + case kS2A_GrBlendCoeff: + return D3D12_BLEND_SRC1_ALPHA; + case kIS2A_GrBlendCoeff: + return D3D12_BLEND_INV_SRC1_ALPHA; + case kIllegal_GrBlendCoeff: + return D3D12_BLEND_ZERO; + } + SkUNREACHABLE; +} + +static D3D12_BLEND blend_coeff_to_d3d_blend_for_alpha(GrBlendCoeff coeff) { + switch (coeff) { + // Force all srcColor used in alpha slot to alpha version. + case kSC_GrBlendCoeff: + return D3D12_BLEND_SRC_ALPHA; + case kISC_GrBlendCoeff: + return D3D12_BLEND_INV_SRC_ALPHA; + case kDC_GrBlendCoeff: + return D3D12_BLEND_DEST_ALPHA; + case kIDC_GrBlendCoeff: + return D3D12_BLEND_INV_DEST_ALPHA; + case kS2C_GrBlendCoeff: + return D3D12_BLEND_SRC1_ALPHA; + case kIS2C_GrBlendCoeff: + return D3D12_BLEND_INV_SRC1_ALPHA; + + default: + return blend_coeff_to_d3d_blend(coeff); + } +} + + +static D3D12_BLEND_OP blend_equation_to_d3d_op(GrBlendEquation equation) { + switch (equation) { + case kAdd_GrBlendEquation: + return D3D12_BLEND_OP_ADD; + case kSubtract_GrBlendEquation: + return D3D12_BLEND_OP_SUBTRACT; + case kReverseSubtract_GrBlendEquation: + return D3D12_BLEND_OP_REV_SUBTRACT; + default: + SkUNREACHABLE; + } +} + +static void fill_in_blend_state(const GrPipeline& pipeline, D3D12_BLEND_DESC* blendDesc) { + blendDesc->AlphaToCoverageEnable = false; + blendDesc->IndependentBlendEnable = false; + + const GrXferProcessor::BlendInfo& blendInfo = pipeline.getXferProcessor().getBlendInfo(); + + GrBlendEquation equation = blendInfo.fEquation; + GrBlendCoeff srcCoeff = blendInfo.fSrcBlend; + GrBlendCoeff dstCoeff = blendInfo.fDstBlend; + bool blendOff = GrBlendShouldDisable(equation, srcCoeff, dstCoeff); + + auto& rtBlend = blendDesc->RenderTarget[0]; + rtBlend.BlendEnable = !blendOff; + if (!blendOff) { + rtBlend.SrcBlend = blend_coeff_to_d3d_blend(srcCoeff); + rtBlend.DestBlend = blend_coeff_to_d3d_blend(dstCoeff); + rtBlend.BlendOp = blend_equation_to_d3d_op(equation); + rtBlend.SrcBlendAlpha = blend_coeff_to_d3d_blend_for_alpha(srcCoeff); + rtBlend.DestBlendAlpha = blend_coeff_to_d3d_blend_for_alpha(dstCoeff); + rtBlend.BlendOpAlpha = blend_equation_to_d3d_op(equation); + } + + if (!blendInfo.fWriteColor) { + rtBlend.RenderTargetWriteMask = 0; + } else { + rtBlend.RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; + } +} + +static void fill_in_rasterizer_state(const GrPipeline& pipeline, const GrCaps* caps, + D3D12_RASTERIZER_DESC* rasterizer) { + rasterizer->FillMode = (caps->wireframeMode() || pipeline.isWireframe()) ? + D3D12_FILL_MODE_WIREFRAME : D3D12_FILL_MODE_SOLID; + rasterizer->CullMode = D3D12_CULL_MODE_NONE; + rasterizer->FrontCounterClockwise = true; + rasterizer->DepthBias = 0; + rasterizer->DepthBiasClamp = 0.0f; + rasterizer->SlopeScaledDepthBias = 0.0f; + rasterizer->DepthClipEnable = false; + rasterizer->MultisampleEnable = pipeline.isHWAntialiasState(); + rasterizer->AntialiasedLineEnable = false; + rasterizer->ForcedSampleCount = 0; + rasterizer->ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; +} + +static D3D12_STENCIL_OP stencil_op_to_d3d_op(GrStencilOp op) { + switch (op) { + case GrStencilOp::kKeep: + return D3D12_STENCIL_OP_KEEP; + case GrStencilOp::kZero: + return D3D12_STENCIL_OP_ZERO; + case GrStencilOp::kReplace: + return D3D12_STENCIL_OP_REPLACE; + case GrStencilOp::kInvert: + return D3D12_STENCIL_OP_INVERT; + case GrStencilOp::kIncWrap: + return D3D12_STENCIL_OP_INCR; + case GrStencilOp::kDecWrap: + return D3D12_STENCIL_OP_DECR; + case GrStencilOp::kIncClamp: + return D3D12_STENCIL_OP_INCR_SAT; + case GrStencilOp::kDecClamp: + return D3D12_STENCIL_OP_DECR_SAT; + } + SkUNREACHABLE; +} + +static D3D12_COMPARISON_FUNC stencil_test_to_d3d_func(GrStencilTest test) { + switch (test) { + case GrStencilTest::kAlways: + return D3D12_COMPARISON_FUNC_ALWAYS; + case GrStencilTest::kNever: + return D3D12_COMPARISON_FUNC_NEVER; + case GrStencilTest::kGreater: + return D3D12_COMPARISON_FUNC_GREATER; + case GrStencilTest::kGEqual: + return D3D12_COMPARISON_FUNC_GREATER_EQUAL; + case GrStencilTest::kLess: + return D3D12_COMPARISON_FUNC_LESS; + case GrStencilTest::kLEqual: + return D3D12_COMPARISON_FUNC_LESS_EQUAL; + case GrStencilTest::kEqual: + return D3D12_COMPARISON_FUNC_EQUAL; + case GrStencilTest::kNotEqual: + return D3D12_COMPARISON_FUNC_NOT_EQUAL; + } + SkUNREACHABLE; +} + +static void setup_stencilop_desc(D3D12_DEPTH_STENCILOP_DESC* desc, + const GrStencilSettings::Face& stencilFace) { + desc->StencilFailOp = stencil_op_to_d3d_op(stencilFace.fFailOp); + desc->StencilDepthFailOp = desc->StencilFailOp; + desc->StencilPassOp = stencil_op_to_d3d_op(stencilFace.fPassOp); + desc->StencilFunc = stencil_test_to_d3d_func(stencilFace.fTest); +} + +static void fill_in_depth_stencil_state(const GrProgramInfo& programInfo, + D3D12_DEPTH_STENCIL_DESC* dsDesc) { + GrStencilSettings stencilSettings = programInfo.nonGLStencilSettings(); + GrSurfaceOrigin origin = programInfo.origin(); + + dsDesc->DepthEnable = false; + dsDesc->DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; + dsDesc->DepthFunc = D3D12_COMPARISON_FUNC_NEVER; + dsDesc->StencilEnable = !stencilSettings.isDisabled(); + if (!stencilSettings.isDisabled()) { + if (stencilSettings.isTwoSided()) { + const auto& frontFace = stencilSettings.postOriginCCWFace(origin); + const auto& backFace = stencilSettings.postOriginCWFace(origin); + + SkASSERT(frontFace.fTestMask == backFace.fTestMask); + SkASSERT(frontFace.fWriteMask == backFace.fWriteMask); + dsDesc->StencilReadMask = frontFace.fTestMask; + dsDesc->StencilWriteMask = frontFace.fWriteMask; + + setup_stencilop_desc(&dsDesc->FrontFace, frontFace); + setup_stencilop_desc(&dsDesc->BackFace, backFace); + } else { + dsDesc->StencilReadMask = stencilSettings.singleSidedFace().fTestMask; + dsDesc->StencilWriteMask = stencilSettings.singleSidedFace().fWriteMask; + setup_stencilop_desc(&dsDesc->FrontFace, stencilSettings.singleSidedFace()); + dsDesc->BackFace = dsDesc->FrontFace; + } + } +} + +static D3D12_PRIMITIVE_TOPOLOGY_TYPE gr_primitive_type_to_d3d(GrPrimitiveType primitiveType) { + switch (primitiveType) { + case GrPrimitiveType::kTriangles: + case GrPrimitiveType::kTriangleStrip: //fall through + return D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + case GrPrimitiveType::kPoints: + return D3D12_PRIMITIVE_TOPOLOGY_TYPE_POINT; + case GrPrimitiveType::kLines: // fall through + case GrPrimitiveType::kLineStrip: + return D3D12_PRIMITIVE_TOPOLOGY_TYPE_LINE; + case GrPrimitiveType::kPatches: // fall through, unsupported + case GrPrimitiveType::kPath: // fall through, unsupported + default: + SkUNREACHABLE; + } +} + +gr_cp<ID3D12PipelineState> create_pipeline_state( + GrD3DGpu* gpu, const GrProgramInfo& programInfo, const sk_sp<GrD3DRootSignature>& rootSig, + gr_cp<ID3DBlob> vertexShader, gr_cp<ID3DBlob> geometryShader, gr_cp<ID3DBlob> pixelShader, + DXGI_FORMAT renderTargetFormat, DXGI_FORMAT depthStencilFormat, + unsigned int sampleQualityLevel) { + D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {}; + + psoDesc.pRootSignature = rootSig->rootSignature(); + + psoDesc.VS = { reinterpret_cast<UINT8*>(vertexShader->GetBufferPointer()), + vertexShader->GetBufferSize() }; + psoDesc.PS = { reinterpret_cast<UINT8*>(pixelShader->GetBufferPointer()), + pixelShader->GetBufferSize() }; + + if (geometryShader.get()) { + psoDesc.GS = { reinterpret_cast<UINT8*>(geometryShader->GetBufferPointer()), + geometryShader->GetBufferSize() }; + } + + psoDesc.StreamOutput = { nullptr, 0, nullptr, 0, 0 }; + + fill_in_blend_state(programInfo.pipeline(), &psoDesc.BlendState); + psoDesc.SampleMask = UINT_MAX; + + fill_in_rasterizer_state(programInfo.pipeline(), gpu->caps(), &psoDesc.RasterizerState); + + fill_in_depth_stencil_state(programInfo, &psoDesc.DepthStencilState); + + unsigned int totalAttributeCnt = programInfo.primProc().numVertexAttributes() + + programInfo.primProc().numInstanceAttributes(); + SkAutoSTArray<4, D3D12_INPUT_ELEMENT_DESC> inputElements(totalAttributeCnt); + setup_vertex_input_layout(programInfo.primProc(), inputElements.get()); + + psoDesc.InputLayout = { inputElements.get(), totalAttributeCnt }; + + psoDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; + + // This is for geometry or hull shader primitives + psoDesc.PrimitiveTopologyType = gr_primitive_type_to_d3d(programInfo.primitiveType()); + + psoDesc.NumRenderTargets = 1; + + psoDesc.RTVFormats[0] = renderTargetFormat; + + psoDesc.DSVFormat = depthStencilFormat; + + unsigned int numRasterSamples = programInfo.numRasterSamples(); + psoDesc.SampleDesc = { numRasterSamples, sampleQualityLevel }; + + // Only used for multi-adapter systems. + psoDesc.NodeMask = 0; + + psoDesc.CachedPSO = { nullptr, 0 }; + psoDesc.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; + + gr_cp<ID3D12PipelineState> pipelineState; + SkDEBUGCODE(HRESULT hr = )gpu->device()->CreateGraphicsPipelineState( + &psoDesc, IID_PPV_ARGS(&pipelineState)); + SkASSERT(SUCCEEDED(hr)); + + return pipelineState; +} + +static constexpr SkFourByteTag kHLSL_Tag = SkSetFourByteTag('H', 'L', 'S', 'L'); +static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L'); + sk_sp<GrD3DPipelineState> GrD3DPipelineStateBuilder::finalize() { TRACE_EVENT0("skia.gpu", TRACE_FUNC); @@ -135,32 +552,86 @@ sk_sp<GrD3DPipelineState> GrD3DPipelineStateBuilder::finalize() { SkSL::Program::Settings settings; settings.fCaps = this->caps()->shaderCaps(); settings.fFlipY = this->origin() != kTopLeft_GrSurfaceOrigin; + settings.fInverseW = true; settings.fSharpenTextures = this->gpu()->getContext()->priv().options().fSharpenMipmappedTextures; settings.fRTHeightOffset = fUniformHandler.getRTHeightOffset(); settings.fRTHeightBinding = 0; settings.fRTHeightSet = 0; - gr_cp<ID3DBlob> vertexShader; - gr_cp<ID3DBlob> geometryShader; - gr_cp<ID3DBlob> pixelShader; - SkSL::Program::Inputs vertInputs, fragInputs, geomInputs; + sk_sp<SkData> cached; + SkReadBuffer reader; + SkFourByteTag shaderType = 0; + auto persistentCache = fGpu->getContext()->priv().getPersistentCache(); + if (persistentCache) { + // Shear off the D3D-specific portion of the Desc to get the persistent key. We only cache + // shader code, not entire pipelines. + sk_sp<SkData> key = + SkData::MakeWithoutCopy(this->desc().asKey(), this->desc().initialKeyLength()); + cached = persistentCache->load(*key); + if (cached) { + reader.setMemory(cached->data(), cached->size()); + shaderType = GrPersistentCacheUtils::GetType(&reader); + } + } - this->compileD3DProgram(SkSL::Program::kVertex_Kind, fVS.fCompilerString, settings, - &vertexShader, &vertInputs); - this->compileD3DProgram(SkSL::Program::kFragment_Kind, fFS.fCompilerString, settings, - &pixelShader, &fragInputs); + const GrPrimitiveProcessor& primProc = this->primitiveProcessor(); + gr_cp<ID3DBlob> shaders[kGrShaderTypeCount]; - if (!vertexShader.get() || !pixelShader.get()) { - return nullptr; - } + if (kHLSL_Tag == shaderType && this->loadHLSLFromCache(&reader, shaders)) { + // We successfully loaded and compiled HLSL + } else { + SkSL::Program::Inputs inputs[kGrShaderTypeCount]; + SkSL::String* sksl[kGrShaderTypeCount] = { + &fVS.fCompilerString, + &fGS.fCompilerString, + &fFS.fCompilerString, + }; + SkSL::String cached_sksl[kGrShaderTypeCount]; + SkSL::String hlsl[kGrShaderTypeCount]; - if (this->primitiveProcessor().willUseGeoShader()) { - this->compileD3DProgram(SkSL::Program::kGeometry_Kind, fGS.fCompilerString, settings, - &geometryShader, &geomInputs); - if (!geometryShader.get()) { + if (kSKSL_Tag == shaderType) { + if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, inputs, + kGrShaderTypeCount)) { + for (int i = 0; i < kGrShaderTypeCount; ++i) { + sksl[i] = &cached_sksl[i]; + } + } + } + + auto compile = [&](SkSL::Program::Kind kind, GrShaderType shaderType) { + shaders[shaderType] = this->compileD3DProgram(kind, *sksl[shaderType], settings, + &inputs[shaderType], &hlsl[shaderType]); + return shaders[shaderType].get(); + }; + + if (!compile(SkSL::Program::kVertex_Kind, kVertex_GrShaderType) || + !compile(SkSL::Program::kFragment_Kind, kFragment_GrShaderType)) { return nullptr; } + + if (primProc.willUseGeoShader()) { + if (!compile(SkSL::Program::kGeometry_Kind, kGeometry_GrShaderType)) { + return nullptr; + } + } + + if (persistentCache && !cached) { + const bool cacheSkSL = fGpu->getContext()->priv().options().fShaderCacheStrategy == + GrContextOptions::ShaderCacheStrategy::kSkSL; + if (cacheSkSL) { + // Replace the HLSL with formatted SkSL to be cached. This looks odd, but this is + // the last time we're going to use these strings, so it's safe. + for (int i = 0; i < kGrShaderTypeCount; ++i) { + hlsl[i] = GrShaderUtils::PrettyPrint(*sksl[i]); + } + } + sk_sp<SkData> key = + SkData::MakeWithoutCopy(this->desc().asKey(), this->desc().initialKeyLength()); + sk_sp<SkData> data = GrPersistentCacheUtils::PackCachedShaders( + cacheSkSL ? kSKSL_Tag : kHLSL_Tag, hlsl, inputs, kGrShaderTypeCount); + persistentCache->store(*key, *data); + } } sk_sp<GrD3DRootSignature> rootSig = @@ -170,8 +641,21 @@ sk_sp<GrD3DPipelineState> GrD3DPipelineStateBuilder::finalize() { } const GrD3DRenderTarget* rt = static_cast<const GrD3DRenderTarget*>(fRenderTarget); - return GrD3DPipelineState::Make(fGpu, fProgramInfo, std::move(rootSig), - std::move(vertexShader), std::move(geometryShader), - std::move(pixelShader), rt->dxgiFormat(), - rt->stencilDxgiFormat(), rt->sampleQualityLevel()); + gr_cp<ID3D12PipelineState> pipelineState = create_pipeline_state( + fGpu, fProgramInfo, rootSig, std::move(shaders[kVertex_GrShaderType]), + std::move(shaders[kGeometry_GrShaderType]), std::move(shaders[kFragment_GrShaderType]), + rt->dxgiFormat(), rt->stencilDxgiFormat(), rt->sampleQualityLevel()); + + return sk_sp<GrD3DPipelineState>(new GrD3DPipelineState(std::move(pipelineState), + std::move(rootSig), + fUniformHandles, + fUniformHandler.fUniforms, + fUniformHandler.fCurrentUBOOffset, + fUniformHandler.fSamplers.count(), + std::move(fGeometryProcessor), + std::move(fXferProcessor), + std::move(fFragmentProcessors), + fFragmentProcessorCnt, + primProc.vertexStride(), + primProc.instanceStride())); } diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateBuilder.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateBuilder.h index e5fc4171bbd..357c024b0cd 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateBuilder.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateBuilder.h @@ -18,7 +18,6 @@ class GrProgramDesc; class GrD3DGpu; class GrVkRenderPass; -class SkReader32; class GrD3DPipelineStateBuilder : public GrGLSLProgramBuilder { public: @@ -46,11 +45,13 @@ private: sk_sp<GrD3DPipelineState> finalize(); - void compileD3DProgram(SkSL::Program::Kind kind, - const SkSL::String& sksl, - const SkSL::Program::Settings& settings, - ID3DBlob** shader, - SkSL::Program::Inputs* outInputs); + bool loadHLSLFromCache(SkReadBuffer* reader, gr_cp<ID3DBlob> shaders[]); + + gr_cp<ID3DBlob> compileD3DProgram(SkSL::Program::Kind kind, + const SkSL::String& sksl, + const SkSL::Program::Settings& settings, + SkSL::Program::Inputs* outInputs, + SkSL::String* outHLSL); GrGLSLUniformHandler* uniformHandler() override { return &fUniformHandler; } const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; } diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateDataManager.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateDataManager.cpp new file mode 100644 index 00000000000..a902bddc9a5 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateDataManager.cpp @@ -0,0 +1,41 @@ +/* +* Copyright 2016 Google Inc. +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#include "src/gpu/d3d/GrD3DPipelineStateDataManager.h" + +#include "src/gpu/d3d/GrD3DGpu.h" +#include "src/gpu/d3d/GrD3DResourceProvider.h" + +GrD3DPipelineStateDataManager::GrD3DPipelineStateDataManager(const UniformInfoArray& uniforms, + uint32_t uniformSize) + : INHERITED(uniforms.count(), uniformSize) { + // We must add uniforms in same order as the UniformInfoArray so that UniformHandles already + // owned by other objects will still match up here. + int i = 0; + for (const auto& uniformInfo : uniforms.items()) { + Uniform& uniform = fUniforms[i]; + SkASSERT(GrShaderVar::kNonArray == uniformInfo.fVariable.getArrayCount() || + uniformInfo.fVariable.getArrayCount() > 0); + SkDEBUGCODE( + uniform.fArrayCount = uniformInfo.fVariable.getArrayCount(); + uniform.fType = uniformInfo.fVariable.getType(); + ) + + uniform.fOffset = uniformInfo.fUBOOffset; + ++i; + } +} + +D3D12_GPU_VIRTUAL_ADDRESS GrD3DPipelineStateDataManager::uploadConstants(GrD3DGpu* gpu) { + if (fUniformsDirty) { + fConstantBufferAddress = gpu->resourceProvider().uploadConstantData(fUniformData.get(), + fUniformSize); + fUniformsDirty = false; + } + + return fConstantBufferAddress; +} diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateDataManager.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateDataManager.h new file mode 100644 index 00000000000..15a41abc42f --- /dev/null +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DPipelineStateDataManager.h @@ -0,0 +1,34 @@ +/* +* Copyright 2020 Google LLC +* +* Use of this source code is governed by a BSD-style license that can be +* found in the LICENSE file. +*/ + +#ifndef GrD3DPipelineStateDataManager_DEFINED +#define GrD3DPipelineStateDataManager_DEFINED + +#include "src/gpu/GrUniformDataManager.h" + +#include "include/gpu/d3d/GrD3DTypes.h" +#include "src/gpu/GrSPIRVUniformHandler.h" + +class GrD3DConstantRingBuffer; +class GrD3DGpu; + +class GrD3DPipelineStateDataManager : public GrUniformDataManager { +public: + typedef GrSPIRVUniformHandler::UniformInfoArray UniformInfoArray; + + GrD3DPipelineStateDataManager(const UniformInfoArray&, + uint32_t uniformSize); + + D3D12_GPU_VIRTUAL_ADDRESS uploadConstants(GrD3DGpu* gpu); + +private: + D3D12_GPU_VIRTUAL_ADDRESS fConstantBufferAddress; + + typedef GrUniformDataManager INHERITED; +}; + +#endif diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DRenderTarget.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DRenderTarget.cpp index 4dd2e6092ec..b572a6f5c7b 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DRenderTarget.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DRenderTarget.cpp @@ -24,8 +24,8 @@ GrD3DRenderTarget::GrD3DRenderTarget(GrD3DGpu* gpu, sk_sp<GrD3DResourceState> state, const GrD3DTextureResourceInfo& msaaInfo, sk_sp<GrD3DResourceState> msaaState, - const D3D12_CPU_DESCRIPTOR_HANDLE& colorRenderTargetView, - const D3D12_CPU_DESCRIPTOR_HANDLE& resolveRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& colorRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& resolveRenderTargetView, Wrapped) : GrSurface(gpu, dimensions, info.fProtected) , GrD3DTextureResource(info, std::move(state)) @@ -48,8 +48,8 @@ GrD3DRenderTarget::GrD3DRenderTarget(GrD3DGpu* gpu, sk_sp<GrD3DResourceState> state, const GrD3DTextureResourceInfo& msaaInfo, sk_sp<GrD3DResourceState> msaaState, - const D3D12_CPU_DESCRIPTOR_HANDLE& colorRenderTargetView, - const D3D12_CPU_DESCRIPTOR_HANDLE& resolveRenderTargetView) + const GrD3DDescriptorHeap::CPUHandle& colorRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& resolveRenderTargetView) : GrSurface(gpu, dimensions, info.fProtected) , GrD3DTextureResource(info, std::move(state)) // for the moment we only support 1:1 color to stencil @@ -67,7 +67,7 @@ GrD3DRenderTarget::GrD3DRenderTarget(GrD3DGpu* gpu, SkISize dimensions, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, - const D3D12_CPU_DESCRIPTOR_HANDLE& renderTargetView, + const GrD3DDescriptorHeap::CPUHandle& renderTargetView, Wrapped) : GrSurface(gpu, dimensions, info.fProtected) , GrD3DTextureResource(info, std::move(state)) @@ -83,7 +83,7 @@ GrD3DRenderTarget::GrD3DRenderTarget(GrD3DGpu* gpu, SkISize dimensions, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, - const D3D12_CPU_DESCRIPTOR_HANDLE& renderTargetView) + const GrD3DDescriptorHeap::CPUHandle& renderTargetView) : GrSurface(gpu, dimensions, info.fProtected) , GrD3DTextureResource(info, std::move(state)) , GrRenderTarget(gpu, dimensions, 1, info.fProtected) @@ -98,7 +98,7 @@ sk_sp<GrD3DRenderTarget> GrD3DRenderTarget::MakeWrappedRenderTarget( SkASSERT(1 == info.fLevelCount); DXGI_FORMAT dxgiFormat = info.fFormat; - D3D12_CPU_DESCRIPTOR_HANDLE renderTargetView = + GrD3DDescriptorHeap::CPUHandle renderTargetView = gpu->resourceProvider().createRenderTargetView(info.fResource.get()); // create msaa surface if necessary @@ -137,7 +137,7 @@ sk_sp<GrD3DRenderTarget> GrD3DRenderTarget::MakeWrappedRenderTarget( msState.reset(new GrD3DResourceState( static_cast<D3D12_RESOURCE_STATES>(msInfo.fResourceState))); - D3D12_CPU_DESCRIPTOR_HANDLE msaaRenderTargetView = + GrD3DDescriptorHeap::CPUHandle msaaRenderTargetView = gpu->resourceProvider().createRenderTargetView(msInfo.fResource.get()); d3dRT = new GrD3DRenderTarget(gpu, dimensions, sampleCnt, info, std::move(state), msInfo, @@ -162,10 +162,10 @@ void GrD3DRenderTarget::releaseInternalObjects() { if (fMSAATextureResource) { fMSAATextureResource->releaseResource(gpu); fMSAATextureResource.reset(); - gpu->resourceProvider().recycleRenderTargetView(&fResolveRenderTargetView); + gpu->resourceProvider().recycleRenderTargetView(fResolveRenderTargetView); } - gpu->resourceProvider().recycleRenderTargetView(&fColorRenderTargetView); + gpu->resourceProvider().recycleRenderTargetView(fColorRenderTargetView); } void GrD3DRenderTarget::onRelease() { diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DRenderTarget.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DRenderTarget.h index e2829a444ca..c83cf60020e 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DRenderTarget.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DRenderTarget.h @@ -14,6 +14,7 @@ #include "include/gpu/d3d/GrD3DTypes.h" #include "src/gpu/GrGpu.h" +#include "src/gpu/d3d/GrD3DDescriptorHeap.h" #include "src/gpu/d3d/GrD3DResourceProvider.h" class GrD3DGpu; @@ -36,7 +37,7 @@ public: GrBackendFormat backendFormat() const override { return this->getBackendFormat(); } - GrD3DTextureResource* msaaTextureResource() { return fMSAATextureResource.get(); } + GrD3DTextureResource* msaaTextureResource() const { return fMSAATextureResource.get(); } bool canAttemptStencilAttachment() const override { return true; @@ -44,8 +45,8 @@ public: GrBackendRenderTarget getBackendRenderTarget() const override; - D3D12_CPU_DESCRIPTOR_HANDLE colorRenderTargetView() { - return fColorRenderTargetView; + D3D12_CPU_DESCRIPTOR_HANDLE colorRenderTargetView() const { + return fColorRenderTargetView.fHandle; } DXGI_FORMAT stencilDxgiFormat() const; @@ -61,14 +62,14 @@ protected: sk_sp<GrD3DResourceState> state, const GrD3DTextureResourceInfo& msaaInfo, sk_sp<GrD3DResourceState> msaaState, - const D3D12_CPU_DESCRIPTOR_HANDLE& colorRenderTargetView, - const D3D12_CPU_DESCRIPTOR_HANDLE& resolveRenderTargetView); + const GrD3DDescriptorHeap::CPUHandle& colorRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& resolveRenderTargetView); GrD3DRenderTarget(GrD3DGpu* gpu, SkISize dimensions, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, - const D3D12_CPU_DESCRIPTOR_HANDLE& renderTargetView); + const GrD3DDescriptorHeap::CPUHandle& renderTargetView); void onAbandon() override; void onRelease() override; @@ -95,15 +96,15 @@ private: sk_sp<GrD3DResourceState> state, const GrD3DTextureResourceInfo& msaaInfo, sk_sp<GrD3DResourceState> msaaState, - const D3D12_CPU_DESCRIPTOR_HANDLE& colorRenderTargetView, - const D3D12_CPU_DESCRIPTOR_HANDLE& resolveRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& colorRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& resolveRenderTargetView, Wrapped); GrD3DRenderTarget(GrD3DGpu* gpu, SkISize dimensions, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, - const D3D12_CPU_DESCRIPTOR_HANDLE& renderTargetView, + const GrD3DDescriptorHeap::CPUHandle& renderTargetView, Wrapped); GrD3DGpu* getD3DGpu() const; @@ -121,8 +122,8 @@ private: std::unique_ptr<GrD3DTextureResource> fMSAATextureResource; - D3D12_CPU_DESCRIPTOR_HANDLE fColorRenderTargetView; - D3D12_CPU_DESCRIPTOR_HANDLE fResolveRenderTargetView; + GrD3DDescriptorHeap::CPUHandle fColorRenderTargetView; + GrD3DDescriptorHeap::CPUHandle fResolveRenderTargetView; }; #endif diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DResourceProvider.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DResourceProvider.cpp index f93b36c2687..c933743e358 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DResourceProvider.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DResourceProvider.cpp @@ -9,6 +9,7 @@ #include "include/gpu/GrContextOptions.h" #include "src/gpu/GrContextPriv.h" +#include "src/gpu/d3d/GrD3DBuffer.h" #include "src/gpu/d3d/GrD3DCommandList.h" #include "src/gpu/d3d/GrD3DGpu.h" #include "src/gpu/d3d/GrD3DPipelineState.h" @@ -16,8 +17,14 @@ GrD3DResourceProvider::GrD3DResourceProvider(GrD3DGpu* gpu) : fGpu(gpu) - , fAttachmentViewManager(gpu) - , fPipelineStateCache(new PipelineStateCache(gpu)) { + , fCpuDescriptorManager(gpu) + , fDescriptorTableManager(gpu) + , fPipelineStateCache(new PipelineStateCache(gpu)) {} + +void GrD3DResourceProvider::destroyResources() { + fSamplers.reset(); + + fPipelineStateCache->release(); } std::unique_ptr<GrD3DDirectCommandList> GrD3DResourceProvider::findOrCreateDirectCommandList() { @@ -52,22 +59,91 @@ sk_sp<GrD3DRootSignature> GrD3DResourceProvider::findOrCreateRootSignature(int n } -D3D12_CPU_DESCRIPTOR_HANDLE GrD3DResourceProvider::createRenderTargetView( +GrD3DDescriptorHeap::CPUHandle GrD3DResourceProvider::createRenderTargetView( ID3D12Resource* textureResource) { - return fAttachmentViewManager.createRenderTargetView(fGpu, textureResource); + return fCpuDescriptorManager.createRenderTargetView(fGpu, textureResource); } -void GrD3DResourceProvider::recycleRenderTargetView(D3D12_CPU_DESCRIPTOR_HANDLE* rtvDescriptor) { - fAttachmentViewManager.recycleRenderTargetView(rtvDescriptor); +void GrD3DResourceProvider::recycleRenderTargetView( + const GrD3DDescriptorHeap::CPUHandle& rtvDescriptor) { + fCpuDescriptorManager.recycleRenderTargetView(rtvDescriptor); } -D3D12_CPU_DESCRIPTOR_HANDLE GrD3DResourceProvider::createDepthStencilView( +GrD3DDescriptorHeap::CPUHandle GrD3DResourceProvider::createDepthStencilView( ID3D12Resource* textureResource) { - return fAttachmentViewManager.createDepthStencilView(fGpu, textureResource); + return fCpuDescriptorManager.createDepthStencilView(fGpu, textureResource); +} + +void GrD3DResourceProvider::recycleDepthStencilView( + const GrD3DDescriptorHeap::CPUHandle& dsvDescriptor) { + fCpuDescriptorManager.recycleDepthStencilView(dsvDescriptor); +} + +GrD3DDescriptorHeap::CPUHandle GrD3DResourceProvider::createConstantBufferView( + ID3D12Resource* bufferResource, size_t offset, size_t size) { + return fCpuDescriptorManager.createConstantBufferView(fGpu, bufferResource, offset, size); +} + +GrD3DDescriptorHeap::CPUHandle GrD3DResourceProvider::createShaderResourceView( + ID3D12Resource* resource) { + return fCpuDescriptorManager.createShaderResourceView(fGpu, resource); +} + +void GrD3DResourceProvider::recycleConstantOrShaderView( + const GrD3DDescriptorHeap::CPUHandle& view) { + fCpuDescriptorManager.recycleConstantOrShaderView(view); } -void GrD3DResourceProvider::recycleDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE* dsvDescriptor) { - fAttachmentViewManager.recycleDepthStencilView(dsvDescriptor); +static D3D12_TEXTURE_ADDRESS_MODE wrap_mode_to_d3d_address_mode(GrSamplerState::WrapMode wrapMode) { + switch (wrapMode) { + case GrSamplerState::WrapMode::kClamp: + return D3D12_TEXTURE_ADDRESS_MODE_CLAMP; + case GrSamplerState::WrapMode::kRepeat: + return D3D12_TEXTURE_ADDRESS_MODE_WRAP; + case GrSamplerState::WrapMode::kMirrorRepeat: + return D3D12_TEXTURE_ADDRESS_MODE_MIRROR; + case GrSamplerState::WrapMode::kClampToBorder: + return D3D12_TEXTURE_ADDRESS_MODE_BORDER; + } + SK_ABORT("Unknown wrap mode."); +} + +D3D12_CPU_DESCRIPTOR_HANDLE GrD3DResourceProvider::findOrCreateCompatibleSampler( + const GrSamplerState& params) { + uint32_t key = GrSamplerState::GenerateKey(params); + D3D12_CPU_DESCRIPTOR_HANDLE* samplerPtr = fSamplers.find(key); + if (samplerPtr) { + return *samplerPtr; + } + + static D3D12_FILTER d3dFilterModes[] = { + D3D12_FILTER_MIN_MAG_MIP_POINT, + D3D12_FILTER_MIN_MAG_LINEAR_MIP_POINT, + D3D12_FILTER_MIN_MAG_MIP_LINEAR + }; + + static_assert((int)GrSamplerState::Filter::kNearest == 0); + static_assert((int)GrSamplerState::Filter::kBilerp == 1); + static_assert((int)GrSamplerState::Filter::kMipMap == 2); + + D3D12_FILTER filter = d3dFilterModes[static_cast<int>(params.filter())]; + D3D12_TEXTURE_ADDRESS_MODE addressModeU = wrap_mode_to_d3d_address_mode(params.wrapModeX()); + D3D12_TEXTURE_ADDRESS_MODE addressModeV = wrap_mode_to_d3d_address_mode(params.wrapModeY()); + + D3D12_CPU_DESCRIPTOR_HANDLE sampler = + fCpuDescriptorManager.createSampler( + fGpu, filter, addressModeU, addressModeV).fHandle; + fSamplers.set(key, sampler); + return sampler; +} + +std::unique_ptr<GrD3DDescriptorTable> GrD3DResourceProvider::createShaderOrConstantResourceTable( + unsigned int size) { + return fDescriptorTableManager.createShaderOrConstantResourceTable(fGpu, size); +} + +std::unique_ptr<GrD3DDescriptorTable> GrD3DResourceProvider::createSamplerTable(unsigned int size) { + return fDescriptorTableManager.createSamplerTable(fGpu, size); } sk_sp<GrD3DPipelineState> GrD3DResourceProvider::findOrCreateCompatiblePipelineState( @@ -75,6 +151,34 @@ sk_sp<GrD3DPipelineState> GrD3DResourceProvider::findOrCreateCompatiblePipelineS return fPipelineStateCache->refPipelineState(rt, info); } +D3D12_GPU_VIRTUAL_ADDRESS GrD3DResourceProvider::uploadConstantData(void* data, size_t size) { + // constant size has to be aligned to 256 + constexpr int kConstantAlignment = 256; + + // Due to dependency on the resource cache we can't initialize this in the constructor, so + // we do so it here. + if (!fConstantBuffer) { + fConstantBuffer = GrD3DConstantRingBuffer::Make(fGpu, 128 * 1024, kConstantAlignment); + SkASSERT(fConstantBuffer); + } + + // upload the data + size_t paddedSize = GrAlignTo(size, kConstantAlignment); + GrRingBuffer::Slice slice = fConstantBuffer->suballocate(paddedSize); + char* destPtr = static_cast<char*>(slice.fBuffer->map()) + slice.fOffset; + memcpy(destPtr, data, size); + + // create the associated constant buffer view descriptor + GrD3DBuffer* d3dBuffer = static_cast<GrD3DBuffer*>(slice.fBuffer.get()); + D3D12_GPU_VIRTUAL_ADDRESS gpuAddress = d3dBuffer->d3dResource()->GetGPUVirtualAddress(); + return gpuAddress + slice.fOffset; +} + +void GrD3DResourceProvider::prepForSubmit() { + fGpu->currentCommandList()->setCurrentConstantBuffer(fConstantBuffer); + fDescriptorTableManager.prepForSubmit(fGpu); +} + //////////////////////////////////////////////////////////////////////////////////////////////// #ifdef GR_PIPELINE_STATE_CACHE_STATS @@ -114,6 +218,10 @@ GrD3DResourceProvider::PipelineStateCache::~PipelineStateCache() { #endif } +void GrD3DResourceProvider::PipelineStateCache::release() { + fMap.reset(); +} + sk_sp<GrD3DPipelineState> GrD3DResourceProvider::PipelineStateCache::refPipelineState( GrRenderTarget* renderTarget, const GrProgramInfo& programInfo) { #ifdef GR_PIPELINE_STATE_CACHE_STATS @@ -144,3 +252,10 @@ sk_sp<GrD3DPipelineState> GrD3DResourceProvider::PipelineStateCache::refPipeline } return (*entry)->fPipelineState; } + +void GrD3DResourceProvider::PipelineStateCache::markPipelineStateUniformsDirty() { + fMap.foreach ([](const GrProgramDesc*, std::unique_ptr<Entry>* entry) { + (*entry)->fPipelineState->markUniformsDirty(); + }); +} + diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DResourceProvider.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DResourceProvider.h index 4e244cb632f..923342ab79f 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DResourceProvider.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DResourceProvider.h @@ -10,9 +10,12 @@ #include "include/gpu/d3d/GrD3DTypes.h" #include "include/private/SkTArray.h" +#include "include/private/SkTHash.h" #include "src/core/SkLRUCache.h" #include "src/gpu/GrProgramDesc.h" -#include "src/gpu/d3d/GrD3DAttachmentViewManager.h" +#include "src/gpu/d3d/GrD3DConstantRingBuffer.h" +#include "src/gpu/d3d/GrD3DCpuDescriptorManager.h" +#include "src/gpu/d3d/GrD3DDescriptorTableManager.h" #include "src/gpu/d3d/GrD3DRootSignature.h" #include <memory> @@ -20,26 +23,53 @@ class GrD3DDirectCommandList; class GrD3DGpu; class GrD3DPipelineState; +class GrSamplerState; class GrD3DResourceProvider { public: GrD3DResourceProvider(GrD3DGpu*); + void destroyResources(); + std::unique_ptr<GrD3DDirectCommandList> findOrCreateDirectCommandList(); void recycleDirectCommandList(std::unique_ptr<GrD3DDirectCommandList>); sk_sp<GrD3DRootSignature> findOrCreateRootSignature(int numTextureSamplers); - D3D12_CPU_DESCRIPTOR_HANDLE createRenderTargetView(ID3D12Resource* textureResource); - void recycleRenderTargetView(D3D12_CPU_DESCRIPTOR_HANDLE*); + GrD3DDescriptorHeap::CPUHandle createRenderTargetView(ID3D12Resource* textureResource); + void recycleRenderTargetView(const GrD3DDescriptorHeap::CPUHandle&); + + GrD3DDescriptorHeap::CPUHandle createDepthStencilView(ID3D12Resource* textureResource); + void recycleDepthStencilView(const GrD3DDescriptorHeap::CPUHandle&); + + GrD3DDescriptorHeap::CPUHandle createConstantBufferView(ID3D12Resource* bufferResource, + size_t offset, + size_t size); + GrD3DDescriptorHeap::CPUHandle createShaderResourceView(ID3D12Resource* resource); + void recycleConstantOrShaderView(const GrD3DDescriptorHeap::CPUHandle&); - D3D12_CPU_DESCRIPTOR_HANDLE createDepthStencilView(ID3D12Resource* textureResource); - void recycleDepthStencilView(D3D12_CPU_DESCRIPTOR_HANDLE*); + D3D12_CPU_DESCRIPTOR_HANDLE findOrCreateCompatibleSampler(const GrSamplerState& params); - sk_sp<GrD3DPipelineState> findOrCreateCompatiblePipelineState(GrRenderTarget*, + + std::unique_ptr<GrD3DDescriptorTable> createShaderOrConstantResourceTable(unsigned int size); + std::unique_ptr<GrD3DDescriptorTable> createSamplerTable(unsigned int size); + GrD3DDescriptorTableManager* descriptorTableMgr() { + return &fDescriptorTableManager; + } + + sk_sp<GrD3DPipelineState> findOrCreateCompatiblePipelineState(GrRenderTarget*, const GrProgramInfo&); + D3D12_GPU_VIRTUAL_ADDRESS uploadConstantData(void* data, size_t size); + void prepForSubmit(); + + void markPipelineStateUniformsDirty() { fPipelineStateCache->markPipelineStateUniformsDirty(); } + +#if GR_TEST_UTILS + void resetShaderCacheForTesting() const { fPipelineStateCache->release(); } +#endif + private: #ifdef SK_DEBUG #define GR_PIPELINE_STATE_CACHE_STATS @@ -50,8 +80,11 @@ private: PipelineStateCache(GrD3DGpu* gpu); ~PipelineStateCache(); + void release(); sk_sp<GrD3DPipelineState> refPipelineState(GrRenderTarget*, const GrProgramInfo&); + void markPipelineStateUniformsDirty(); + private: struct Entry; @@ -76,9 +109,14 @@ private: SkSTArray<4, std::unique_ptr<GrD3DDirectCommandList>> fAvailableDirectCommandLists; SkSTArray<4, sk_sp<GrD3DRootSignature>> fRootSignatures; - GrD3DAttachmentViewManager fAttachmentViewManager; + GrD3DCpuDescriptorManager fCpuDescriptorManager; + GrD3DDescriptorTableManager fDescriptorTableManager; + + sk_sp<GrD3DConstantRingBuffer> fConstantBuffer; std::unique_ptr<PipelineStateCache> fPipelineStateCache; + + SkTHashMap<uint32_t, D3D12_CPU_DESCRIPTOR_HANDLE> fSamplers; }; #endif diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DRootSignature.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DRootSignature.cpp index b4f2d8ddc04..e64faa2ba0c 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DRootSignature.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DRootSignature.cpp @@ -15,17 +15,9 @@ sk_sp<GrD3DRootSignature> GrD3DRootSignature::Make(GrD3DGpu* gpu, int numTexture D3D12_ROOT_PARAMETER parameters[3]; // The first will always be our uniforms - D3D12_DESCRIPTOR_RANGE uniformRange{}; - uniformRange.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; - uniformRange.NumDescriptors = 1; - uniformRange.BaseShaderRegister = 0; - // Spirv-Cross uses the descriptor set as the space in HSLS - uniformRange.RegisterSpace = GrSPIRVUniformHandler::kUniformDescriptorSet; - uniformRange.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; - - parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; - parameters[0].DescriptorTable.NumDescriptorRanges = 1; - parameters[0].DescriptorTable.pDescriptorRanges = &uniformRange; + parameters[0].ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; + parameters[0].Descriptor.ShaderRegister = 0; + parameters[0].Descriptor.RegisterSpace = GrSPIRVUniformHandler::kUniformDescriptorSet; parameters[0].ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; SkAutoTArray<D3D12_DESCRIPTOR_RANGE> samplerRanges(numTextureSamplers); diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DRootSignature.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DRootSignature.h index c133e2e5aca..025ac4d2a8e 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DRootSignature.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DRootSignature.h @@ -17,6 +17,12 @@ class GrD3DRootSignature : public GrManagedResource { public: static sk_sp<GrD3DRootSignature> Make(GrD3DGpu* gpu, int numTextureSamplers); + enum class ParamIndex { + kConstantBufferView = 0, + kSamplerDescriptorTable = 1, + kTextureDescriptorTable = 2 + }; + bool isCompatible(int numTextureSamplers) const; ID3D12RootSignature* rootSignature() const { return fRootSignature.get(); } diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DStencilAttachment.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DStencilAttachment.cpp index e5dd5bcf339..c8925c1d87f 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DStencilAttachment.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DStencilAttachment.cpp @@ -13,10 +13,12 @@ GrD3DStencilAttachment::GrD3DStencilAttachment(GrD3DGpu* gpu, const Format& format, const D3D12_RESOURCE_DESC& desc, const GrD3DTextureResourceInfo& info, - sk_sp<GrD3DResourceState> state) + sk_sp<GrD3DResourceState> state, + const GrD3DDescriptorHeap::CPUHandle& view) : GrStencilAttachment(gpu, desc.Width, desc.Height, format.fStencilBits, desc.SampleDesc.Count) - , GrD3DTextureResource(info, state) { + , GrD3DTextureResource(info, state) + , fView(view) { this->registerWithCache(SkBudgeted::kYes); } @@ -51,9 +53,12 @@ GrD3DStencilAttachment* GrD3DStencilAttachment::Make(GrD3DGpu* gpu, return nullptr; } + GrD3DDescriptorHeap::CPUHandle view = + gpu->resourceProvider().createDepthStencilView(info.fResource.get()); + sk_sp<GrD3DResourceState> state(new GrD3DResourceState(info.fResourceState)); GrD3DStencilAttachment* stencil = new GrD3DStencilAttachment(gpu, format, resourceDesc, - info, std::move(state)); + info, std::move(state), view); return stencil; } diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DStencilAttachment.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DStencilAttachment.h index 096626d9053..927637c9e15 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DStencilAttachment.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DStencilAttachment.h @@ -11,11 +11,11 @@ #include "src/gpu/GrStencilAttachment.h" #include "include/gpu/d3d/GrD3DTypes.h" +#include "src/gpu/d3d/GrD3DDescriptorHeap.h" #include "src/gpu/d3d/GrD3DTextureResource.h" class GrD3DGpu; - class GrD3DStencilAttachment : public GrStencilAttachment, public GrD3DTextureResource { public: struct Format { @@ -28,6 +28,10 @@ public: ~GrD3DStencilAttachment() override {} + D3D12_CPU_DESCRIPTOR_HANDLE view() const { + return fView.fHandle; + } + protected: void onRelease() override; void onAbandon() override; @@ -39,9 +43,12 @@ private: const Format& format, const D3D12_RESOURCE_DESC&, const GrD3DTextureResourceInfo&, - sk_sp<GrD3DResourceState>); + sk_sp<GrD3DResourceState>, + const GrD3DDescriptorHeap::CPUHandle& view); GrD3DGpu* getD3DGpu() const; + + GrD3DDescriptorHeap::CPUHandle fView; }; #endif diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DTexture.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DTexture.cpp index 458853a3ad6..b59fb4d5f4d 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DTexture.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DTexture.cpp @@ -19,10 +19,12 @@ GrD3DTexture::GrD3DTexture(GrD3DGpu* gpu, SkISize dimensions, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, GrMipMapsStatus mipMapsStatus) : GrSurface(gpu, dimensions, info.fProtected) , GrD3DTextureResource(info, std::move(state)) - , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) { + , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) + , fShaderResourceView(shaderResourceView) { SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount)); this->registerWithCache(budgeted); if (GrDxgiFormatIsCompressed(info.fFormat)) { @@ -31,11 +33,14 @@ GrD3DTexture::GrD3DTexture(GrD3DGpu* gpu, } GrD3DTexture::GrD3DTexture(GrD3DGpu* gpu, SkISize dimensions, const GrD3DTextureResourceInfo& info, - sk_sp<GrD3DResourceState> state, GrMipMapsStatus mipMapsStatus, - GrWrapCacheable cacheable, GrIOType ioType) + sk_sp<GrD3DResourceState> state, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, + GrMipMapsStatus mipMapsStatus, GrWrapCacheable cacheable, + GrIOType ioType) : GrSurface(gpu, dimensions, info.fProtected) , GrD3DTextureResource(info, std::move(state)) - , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) { + , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) + , fShaderResourceView(shaderResourceView) { SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount)); if (ioType == kRead_GrIOType) { this->setReadOnly(); @@ -48,10 +53,12 @@ GrD3DTexture::GrD3DTexture(GrD3DGpu* gpu, SkISize dimensions, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, GrMipMapsStatus mipMapsStatus) : GrSurface(gpu, dimensions, info.fProtected) , GrD3DTextureResource(info, state) - , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) { + , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) + , fShaderResourceView(shaderResourceView) { SkASSERT((GrMipMapsStatus::kNotAllocated == mipMapsStatus) == (1 == info.fLevelCount)); } @@ -70,8 +77,11 @@ sk_sp<GrD3DTexture> GrD3DTexture::MakeNewTexture(GrD3DGpu* gpu, SkBudgeted budge sk_sp<GrD3DResourceState> state( new GrD3DResourceState(static_cast<D3D12_RESOURCE_STATES>(info.fResourceState))); + GrD3DDescriptorHeap::CPUHandle shaderResourceView = + gpu->resourceProvider().createShaderResourceView(info.fResource.get()); + GrD3DTexture* tex = new GrD3DTexture(gpu, budgeted, dimensions, info, std::move(state), - mipMapsStatus); + shaderResourceView, mipMapsStatus); return sk_sp<GrD3DTexture>(tex); } @@ -90,8 +100,12 @@ sk_sp<GrD3DTexture> GrD3DTexture::MakeWrappedTexture(GrD3DGpu* gpu, GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kValid : GrMipMapsStatus::kNotAllocated; + GrD3DDescriptorHeap::CPUHandle shaderResourceView = + gpu->resourceProvider().createShaderResourceView(info.fResource.get()); + return sk_sp<GrD3DTexture>(new GrD3DTexture(gpu, dimensions, info, std::move(state), - mipMapsStatus, cacheable, ioType)); + shaderResourceView, mipMapsStatus, cacheable, + ioType)); } void GrD3DTexture::onRelease() { @@ -103,7 +117,9 @@ void GrD3DTexture::onRelease() { this->removeFinishIdleProcs(); } - this->releaseResource(this->getD3DGpu()); + GrD3DGpu* gpu = this->getD3DGpu(); + gpu->resourceProvider().recycleConstantOrShaderView(fShaderResourceView); + this->releaseResource(gpu); INHERITED::onRelease(); } @@ -117,7 +133,9 @@ void GrD3DTexture::onAbandon() { this->removeFinishIdleProcs(); } - this->releaseResource(this->getD3DGpu()); + GrD3DGpu* gpu = this->getD3DGpu(); + gpu->resourceProvider().recycleConstantOrShaderView(fShaderResourceView); + this->releaseResource(gpu); INHERITED::onAbandon(); } diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DTexture.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DTexture.h index 704f1b2146d..e6e9b56a42a 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DTexture.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DTexture.h @@ -11,6 +11,7 @@ #include "src/core/SkLRUCache.h" #include "src/gpu/GrSamplerState.h" #include "src/gpu/GrTexture.h" +#include "src/gpu/d3d/GrD3DDescriptorHeap.h" #include "src/gpu/d3d/GrD3DTextureResource.h" class GrD3DTexture : public GrTexture, public virtual GrD3DTextureResource { @@ -34,6 +35,7 @@ public: GrBackendTexture getBackendTexture() const override; GrBackendFormat backendFormat() const override { return this->getBackendFormat(); } + D3D12_CPU_DESCRIPTOR_HANDLE shaderResourceView() { return fShaderResourceView.fHandle; } void textureParamsModified() override {} @@ -45,6 +47,7 @@ protected: SkISize dimensions, const GrD3DTextureResourceInfo&, sk_sp<GrD3DResourceState>, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, GrMipMapsStatus); GrD3DGpu* getD3DGpu() const; @@ -60,9 +63,13 @@ protected: private: GrD3DTexture(GrD3DGpu*, SkBudgeted, SkISize dimensions, const GrD3DTextureResourceInfo&, - sk_sp<GrD3DResourceState>, GrMipMapsStatus); + sk_sp<GrD3DResourceState>, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, + GrMipMapsStatus); GrD3DTexture(GrD3DGpu*, SkISize dimensions, const GrD3DTextureResourceInfo&, - sk_sp<GrD3DResourceState>, GrMipMapsStatus, GrWrapCacheable, GrIOType); + sk_sp<GrD3DResourceState>, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, + GrMipMapsStatus, GrWrapCacheable, GrIOType); // In D3D we call the release proc after we are finished with the underlying // GrSurfaceResource::Resource object (which occurs after the GPU has finished all work on it). @@ -79,6 +86,8 @@ private: } }; + GrD3DDescriptorHeap::CPUHandle fShaderResourceView; + typedef GrTexture INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureRenderTarget.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureRenderTarget.cpp index 1aa178b5f61..f352e8d7954 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureRenderTarget.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureRenderTarget.cpp @@ -13,13 +13,14 @@ GrD3DTextureRenderTarget::GrD3DTextureRenderTarget( GrD3DGpu* gpu, SkBudgeted budgeted, SkISize dimensions, int sampleCnt, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, const GrD3DTextureResourceInfo& msaaInfo, sk_sp<GrD3DResourceState> msaaState, - const D3D12_CPU_DESCRIPTOR_HANDLE& colorRenderTargetView, - const D3D12_CPU_DESCRIPTOR_HANDLE& resolveRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& colorRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& resolveRenderTargetView, GrMipMapsStatus mipMapsStatus) : GrSurface(gpu, dimensions, info.fProtected) , GrD3DTextureResource(info, state) - , GrD3DTexture(gpu, dimensions, info, state, mipMapsStatus) + , GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipMapsStatus) , GrD3DRenderTarget(gpu, dimensions, sampleCnt, info, state, msaaInfo, std::move(msaaState), colorRenderTargetView, resolveRenderTargetView) { SkASSERT(info.fProtected == msaaInfo.fProtected); @@ -29,11 +30,12 @@ GrD3DTextureRenderTarget::GrD3DTextureRenderTarget( GrD3DTextureRenderTarget::GrD3DTextureRenderTarget( GrD3DGpu* gpu, SkBudgeted budgeted, SkISize dimensions, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, - const D3D12_CPU_DESCRIPTOR_HANDLE& renderTargetView, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, + const GrD3DDescriptorHeap::CPUHandle& renderTargetView, GrMipMapsStatus mipMapsStatus) : GrSurface(gpu, dimensions, info.fProtected) , GrD3DTextureResource(info, state) - , GrD3DTexture(gpu, dimensions, info, state, mipMapsStatus) + , GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipMapsStatus) , GrD3DRenderTarget(gpu, dimensions, info, state, renderTargetView) { this->registerWithCache(budgeted); } @@ -41,14 +43,15 @@ GrD3DTextureRenderTarget::GrD3DTextureRenderTarget( GrD3DTextureRenderTarget::GrD3DTextureRenderTarget( GrD3DGpu* gpu, SkISize dimensions, int sampleCnt, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, const GrD3DTextureResourceInfo& msaaInfo, sk_sp<GrD3DResourceState> msaaState, - const D3D12_CPU_DESCRIPTOR_HANDLE& colorRenderTargetView, - const D3D12_CPU_DESCRIPTOR_HANDLE& resolveRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& colorRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& resolveRenderTargetView, GrMipMapsStatus mipMapsStatus, GrWrapCacheable cacheable) : GrSurface(gpu, dimensions, info.fProtected) , GrD3DTextureResource(info, state) - , GrD3DTexture(gpu, dimensions, info, state, mipMapsStatus) + , GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipMapsStatus) , GrD3DRenderTarget(gpu, dimensions, sampleCnt, info, state, msaaInfo, std::move(msaaState), colorRenderTargetView, resolveRenderTargetView) { SkASSERT(info.fProtected == msaaInfo.fProtected); @@ -58,12 +61,13 @@ GrD3DTextureRenderTarget::GrD3DTextureRenderTarget( GrD3DTextureRenderTarget::GrD3DTextureRenderTarget( GrD3DGpu* gpu, SkISize dimensions, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, - const D3D12_CPU_DESCRIPTOR_HANDLE& renderTargetView, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, + const GrD3DDescriptorHeap::CPUHandle& renderTargetView, GrMipMapsStatus mipMapsStatus, GrWrapCacheable cacheable) : GrSurface(gpu, dimensions, info.fProtected) , GrD3DTextureResource(info, state) - , GrD3DTexture(gpu, dimensions, info, state, mipMapsStatus) + , GrD3DTexture(gpu, dimensions, info, state, shaderResourceView, mipMapsStatus) , GrD3DRenderTarget(gpu, dimensions, info, state, renderTargetView) { this->registerWithCacheWrapped(cacheable); } @@ -134,8 +138,11 @@ sk_sp<GrD3DTextureRenderTarget> GrD3DTextureRenderTarget::MakeNewTextureRenderTa sk_sp<GrD3DResourceState> state(new GrD3DResourceState( static_cast<D3D12_RESOURCE_STATES>(info.fResourceState))); - const D3D12_CPU_DESCRIPTOR_HANDLE renderTargetView = - gpu->resourceProvider().createRenderTargetView(info.fResource.get()); + const GrD3DDescriptorHeap::CPUHandle shaderResourceView = + gpu->resourceProvider().createShaderResourceView(info.fResource.get()); + + const GrD3DDescriptorHeap::CPUHandle renderTargetView = + gpu->resourceProvider().createRenderTargetView(info.fResource.get()); if (sampleCnt > 1) { GrD3DTextureResourceInfo msInfo; @@ -143,16 +150,17 @@ sk_sp<GrD3DTextureRenderTarget> GrD3DTextureRenderTarget::MakeNewTextureRenderTa std::tie(msInfo, msState) = create_msaa_resource(gpu, dimensions, sampleCnt, info); - const D3D12_CPU_DESCRIPTOR_HANDLE msaaRenderTargetView = - gpu->resourceProvider().createRenderTargetView(msInfo.fResource.get()); + const GrD3DDescriptorHeap::CPUHandle msaaRenderTargetView = + gpu->resourceProvider().createRenderTargetView(msInfo.fResource.get()); GrD3DTextureRenderTarget* trt = new GrD3DTextureRenderTarget( - gpu, budgeted, dimensions, sampleCnt, info, std::move(state), + gpu, budgeted, dimensions, sampleCnt, info, std::move(state), shaderResourceView, msInfo, std::move(msState), msaaRenderTargetView, renderTargetView, mipMapsStatus); return sk_sp<GrD3DTextureRenderTarget>(trt); } else { GrD3DTextureRenderTarget* trt = new GrD3DTextureRenderTarget( - gpu, budgeted, dimensions, info, std::move(state), renderTargetView, mipMapsStatus); + gpu, budgeted, dimensions, info, std::move(state), shaderResourceView, + renderTargetView, mipMapsStatus); return sk_sp<GrD3DTextureRenderTarget>(trt); } } @@ -172,25 +180,29 @@ sk_sp<GrD3DTextureRenderTarget> GrD3DTextureRenderTarget::MakeWrappedTextureRend GrMipMapsStatus mipMapsStatus = info.fLevelCount > 1 ? GrMipMapsStatus::kDirty : GrMipMapsStatus::kNotAllocated; - const D3D12_CPU_DESCRIPTOR_HANDLE renderTargetView = - gpu->resourceProvider().createRenderTargetView(info.fResource.get()); + const GrD3DDescriptorHeap::CPUHandle shaderResourceView = + gpu->resourceProvider().createShaderResourceView(info.fResource.get()); + + const GrD3DDescriptorHeap::CPUHandle renderTargetView = + gpu->resourceProvider().createRenderTargetView(info.fResource.get()); if (sampleCnt > 1) { GrD3DTextureResourceInfo msInfo; sk_sp<GrD3DResourceState> msState; std::tie(msInfo, msState) = create_msaa_resource(gpu, dimensions, sampleCnt, info); - const D3D12_CPU_DESCRIPTOR_HANDLE msaaRenderTargetView = + const GrD3DDescriptorHeap::CPUHandle msaaRenderTargetView = gpu->resourceProvider().createRenderTargetView(msInfo.fResource.get()); GrD3DTextureRenderTarget* trt = new GrD3DTextureRenderTarget( - gpu, dimensions, sampleCnt, info, std::move(state), msInfo, std::move(msState), - msaaRenderTargetView, renderTargetView, mipMapsStatus, cacheable); + gpu, dimensions, sampleCnt, info, std::move(state), shaderResourceView, + msInfo, std::move(msState), msaaRenderTargetView, renderTargetView, mipMapsStatus, + cacheable); return sk_sp<GrD3DTextureRenderTarget>(trt); } else { return sk_sp<GrD3DTextureRenderTarget>(new GrD3DTextureRenderTarget( - gpu, dimensions, info, std::move(state), renderTargetView, mipMapsStatus, - cacheable)); + gpu, dimensions, info, std::move(state), shaderResourceView, renderTargetView, + mipMapsStatus, cacheable)); } } diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureRenderTarget.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureRenderTarget.h index 75ac076fb07..46d3ca5a3fc 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureRenderTarget.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureRenderTarget.h @@ -59,10 +59,11 @@ private: int sampleCnt, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, const GrD3DTextureResourceInfo& msaaInfo, sk_sp<GrD3DResourceState> msaaState, - const D3D12_CPU_DESCRIPTOR_HANDLE& colorRenderTargetView, - const D3D12_CPU_DESCRIPTOR_HANDLE& resolveRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& colorRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& resolveRenderTargetView, GrMipMapsStatus); // non-MSAA, not-wrapped @@ -71,7 +72,8 @@ private: SkISize dimensions, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, - const D3D12_CPU_DESCRIPTOR_HANDLE& renderTargetView, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, + const GrD3DDescriptorHeap::CPUHandle& renderTargetView, GrMipMapsStatus); // MSAA, wrapped @@ -80,10 +82,11 @@ private: int sampleCnt, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, const GrD3DTextureResourceInfo& msaaInfo, sk_sp<GrD3DResourceState> msaaState, - const D3D12_CPU_DESCRIPTOR_HANDLE& colorRenderTargetView, - const D3D12_CPU_DESCRIPTOR_HANDLE& resolveRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& colorRenderTargetView, + const GrD3DDescriptorHeap::CPUHandle& resolveRenderTargetView, GrMipMapsStatus, GrWrapCacheable); @@ -92,7 +95,8 @@ private: SkISize dimensions, const GrD3DTextureResourceInfo& info, sk_sp<GrD3DResourceState> state, - const D3D12_CPU_DESCRIPTOR_HANDLE& renderTargetView, + const GrD3DDescriptorHeap::CPUHandle& shaderResourceView, + const GrD3DDescriptorHeap::CPUHandle& renderTargetView, GrMipMapsStatus, GrWrapCacheable); diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureResource.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureResource.cpp index a62f2d8554d..a307d110365 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureResource.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureResource.cpp @@ -16,14 +16,12 @@ void GrD3DTextureResource::setResourceState(const GrD3DGpu* gpu, return; } - SkAutoTMalloc<D3D12_RESOURCE_TRANSITION_BARRIER> barriers(fInfo.fLevelCount); - for (uint32_t mipLevel = 0; mipLevel < fInfo.fLevelCount; ++mipLevel) { - barriers[mipLevel].pResource = this->d3dResource(); - barriers[mipLevel].Subresource = mipLevel; - barriers[mipLevel].StateBefore = currentResourceState; - barriers[mipLevel].StateAfter = newResourceState; - } - gpu->addResourceBarriers(this->resource(), fInfo.fLevelCount, barriers.get()); + D3D12_RESOURCE_TRANSITION_BARRIER barrier; + barrier.pResource = this->d3dResource(); + barrier.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + barrier.StateBefore = currentResourceState; + barrier.StateAfter = newResourceState; + gpu->addResourceBarriers(this->resource(), 1, &barrier); this->updateResourceState(newResourceState); } @@ -78,6 +76,10 @@ GrD3DTextureResource::~GrD3DTextureResource() { SkASSERT(!fResource); } +void GrD3DTextureResource::prepareForPresent(GrD3DGpu* gpu) { + this->setResourceState(gpu, D3D12_RESOURCE_STATE_PRESENT); +} + void GrD3DTextureResource::releaseResource(GrD3DGpu* gpu) { // TODO: do we need to migrate resource state if we change queues? if (fResource) { diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureResource.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureResource.h index bffb68988f3..6f091ea406b 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureResource.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DTextureResource.h @@ -55,6 +55,9 @@ public: void setResourceState(const GrD3DGpu* gpu, D3D12_RESOURCE_STATES newResourceState); + // Changes the layout to present + void prepareForPresent(GrD3DGpu* gpu); + unsigned int sampleQualityLevel() const { return fInfo.fSampleQualityLevel; } // This simply updates our tracking of the resourceState and does not actually do any gpu work. diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DUtil.cpp b/chromium/third_party/skia/src/gpu/d3d/GrD3DUtil.cpp index 521fd5d684d..dd66b8355be 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DUtil.cpp +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DUtil.cpp @@ -21,11 +21,3 @@ bool GrDxgiFormatIsCompressed(DXGI_FORMAT format) { } SkUNREACHABLE; } - -SkImage::CompressionType GrDxgiFormatToCompressionType(DXGI_FORMAT format) { - switch (format) { - case DXGI_FORMAT_BC1_UNORM: return SkImage::CompressionType::kBC1_RGBA8_UNORM; - default: return SkImage::CompressionType::kNone; - } - SkUNREACHABLE; -} diff --git a/chromium/third_party/skia/src/gpu/d3d/GrD3DUtil.h b/chromium/third_party/skia/src/gpu/d3d/GrD3DUtil.h index b17f7a5dae8..c5aa209acf3 100644 --- a/chromium/third_party/skia/src/gpu/d3d/GrD3DUtil.h +++ b/chromium/third_party/skia/src/gpu/d3d/GrD3DUtil.h @@ -18,11 +18,6 @@ */ bool GrDxgiFormatIsCompressed(DXGI_FORMAT); -/** - * Maps a dxgi format into the CompressionType enum if applicable. - */ -SkImage::CompressionType GrDxgiFormatToCompressionType(DXGI_FORMAT dxgiFormat); - static constexpr uint32_t GrDxgiFormatChannels(DXGI_FORMAT vkFormat) { switch (vkFormat) { case DXGI_FORMAT_R8G8B8A8_UNORM: return kRGBA_SkColorChannelFlags; diff --git a/chromium/third_party/skia/src/gpu/dawn/GrDawnCaps.cpp b/chromium/third_party/skia/src/gpu/dawn/GrDawnCaps.cpp index 15c4d8941c7..41b9fd851a4 100644 --- a/chromium/third_party/skia/src/gpu/dawn/GrDawnCaps.cpp +++ b/chromium/third_party/skia/src/gpu/dawn/GrDawnCaps.cpp @@ -38,10 +38,6 @@ bool GrDawnCaps::isFormatSRGB(const GrBackendFormat& format) const { return false; } -SkImage::CompressionType GrDawnCaps::compressionType(const GrBackendFormat& format) const { - return SkImage::CompressionType::kNone; -} - bool GrDawnCaps::isFormatTexturable(const GrBackendFormat& format) const { // Currently, all the formats in GrDawnFormatToPixelConfig are texturable. wgpu::TextureFormat dawnFormat; @@ -67,6 +63,7 @@ static GrSwizzle get_swizzle(const GrBackendFormat& format, GrColorType colorTyp if (!forOutput) { return GrSwizzle::RGB1(); } + break; default: return GrSwizzle::RGBA(); } @@ -88,6 +85,18 @@ bool GrDawnCaps::isFormatAsColorTypeRenderable(GrColorType ct, const GrBackendFo return isFormatRenderable(format, sampleCount); } +GrCaps::SurfaceReadPixelsSupport GrDawnCaps::surfaceSupportsReadPixels( + const GrSurface* surface) const { + // We currently support readbacks only from Textures and TextureRenderTargets. + return surface->asTexture() ? SurfaceReadPixelsSupport::kSupported + : SurfaceReadPixelsSupport::kUnsupported; +} + +bool GrDawnCaps::onSurfaceSupportsWritePixels(const GrSurface* surface) const { + // We currently support writePixels only to Textures and TextureRenderTargets. + return surface->asTexture() != nullptr; +} + size_t GrDawnCaps::bytesPerPixel(const GrBackendFormat& backendFormat) const { wgpu::TextureFormat dawnFormat; if (!backendFormat.asDawnFormat(&dawnFormat)) { @@ -122,7 +131,7 @@ GrBackendFormat GrDawnCaps::getBackendFormatFromCompressionType(SkImage::Compres return GrBackendFormat(); } -GrSwizzle GrDawnCaps::getReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const +GrSwizzle GrDawnCaps::onGetReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const { return get_swizzle(format, colorType, false); } diff --git a/chromium/third_party/skia/src/gpu/dawn/GrDawnCaps.h b/chromium/third_party/skia/src/gpu/dawn/GrDawnCaps.h index c6922a9855e..fc2f8b52ed2 100644 --- a/chromium/third_party/skia/src/gpu/dawn/GrDawnCaps.h +++ b/chromium/third_party/skia/src/gpu/dawn/GrDawnCaps.h @@ -18,7 +18,6 @@ public: GrDawnCaps(const GrContextOptions& contextOptions); bool isFormatSRGB(const GrBackendFormat&) const override; - SkImage::CompressionType compressionType(const GrBackendFormat&) const override; bool isFormatRenderable(const GrBackendFormat& format, int sampleCount = 1) const override; @@ -36,9 +35,7 @@ public: return {surfaceColorType, GrColorTypeBytesPerPixel(surfaceColorType)}; } - SurfaceReadPixelsSupport surfaceSupportsReadPixels(const GrSurface*) const override { - return SurfaceReadPixelsSupport::kSupported; - } + SurfaceReadPixelsSupport surfaceSupportsReadPixels(const GrSurface*) const override; size_t bytesPerPixel(const GrBackendFormat&) const override; @@ -49,8 +46,6 @@ public: GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override; - GrSwizzle getReadSwizzle(const GrBackendFormat&, GrColorType) const override; - GrSwizzle getWriteSwizzle(const GrBackendFormat&, GrColorType) const override; uint64_t computeFormatKey(const GrBackendFormat&) const override; @@ -62,9 +57,7 @@ public: #endif private: - bool onSurfaceSupportsWritePixels(const GrSurface* surface) const override { - return true; - } + bool onSurfaceSupportsWritePixels(const GrSurface* surface) const override; bool onCanCopySurface(const GrSurfaceProxy* dst, const GrSurfaceProxy* src, const SkIRect& srcRect, const SkIPoint& dstPoint) const override { return true; @@ -79,6 +72,8 @@ private: return { srcColorType, GrColorTypeBytesPerPixel(srcColorType) }; } + GrSwizzle onGetReadSwizzle(const GrBackendFormat&, GrColorType) const override; + typedef GrCaps INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/dawn/GrDawnGpu.cpp b/chromium/third_party/skia/src/gpu/dawn/GrDawnGpu.cpp index cc0f446134c..f35a2e7e630 100644 --- a/chromium/third_party/skia/src/gpu/dawn/GrDawnGpu.cpp +++ b/chromium/third_party/skia/src/gpu/dawn/GrDawnGpu.cpp @@ -10,6 +10,7 @@ #include "include/gpu/GrBackendSemaphore.h" #include "include/gpu/GrBackendSurface.h" #include "include/gpu/GrContextOptions.h" +#include "src/gpu/GrDataUtils.h" #include "src/gpu/GrGeometryProcessor.h" #include "src/gpu/GrGpuResourceCacheAccess.h" #include "src/gpu/GrPipeline.h" @@ -92,7 +93,6 @@ static wgpu::AddressMode to_dawn_address_mode(GrSamplerState::WrapMode wrapMode) } SkASSERT(!"unsupported address mode"); return wgpu::AddressMode::ClampToEdge; - } sk_sp<GrGpu> GrDawnGpu::Make(const wgpu::Device& device, @@ -124,20 +124,22 @@ GrDawnGpu::~GrDawnGpu() { } } - void GrDawnGpu::disconnect(DisconnectType type) { if (DisconnectType::kCleanup == type) { while (!this->busyStagingBuffers().isEmpty()) { fDevice.Tick(); } } + fQueue = nullptr; + fDevice = nullptr; INHERITED::disconnect(type); } /////////////////////////////////////////////////////////////////////////////// GrOpsRenderPass* GrDawnGpu::getOpsRenderPass( - GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds, + GrRenderTarget* rt, GrStencilAttachment*, + GrSurfaceOrigin origin, const SkIRect& bounds, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { @@ -193,7 +195,10 @@ sk_sp<GrTexture> GrDawnGpu::onCreateTexture(SkISize dimensions, GrProtected, int mipLevelCount, uint32_t levelClearMask) { - SkASSERT(!levelClearMask); + if (levelClearMask) { + return nullptr; + } + wgpu::TextureFormat format; if (!backendFormat.asDawnFormat(&format)) { return nullptr; @@ -353,7 +358,13 @@ bool GrDawnGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture, pixels = data->pixmap(0).addr(); } else { pixels = defaultStorage.get(); - memset(defaultStorage.get(), 0, baseLayerSize); + GrColorType colorType; + if (!GrDawnFormatToGrColorType(info.fFormat, &colorType)) { + return false; + } + SkISize size{backendTexture.width(), backendTexture.height()}; + GrImageInfo imageInfo(colorType, kUnpremul_SkAlphaType, nullptr, size); + GrClearImage(imageInfo, defaultStorage.get(), bpp * backendTexture.width(), data->color()); } wgpu::Device device = this->device(); wgpu::CommandEncoder copyEncoder = this->getCopyEncoder(); @@ -530,7 +541,6 @@ bool GrDawnGpu::onReadPixels(GrSurface* surface, int left, int top, int width, i GrColorType surfaceColorType, GrColorType dstColorType, void* buffer, size_t rowBytes) { wgpu::Texture tex = get_dawn_texture_from_surface(surface); - SkASSERT(tex); if (!tex || 0 == rowBytes) { return false; @@ -638,7 +648,6 @@ std::unique_ptr<GrSemaphore> GrDawnGpu::prepareTextureForCrossContextUsage(GrTex sk_sp<GrDawnProgram> GrDawnGpu::getOrCreateRenderPipeline( GrRenderTarget* rt, const GrProgramInfo& programInfo) { - GrProgramDesc desc = this->caps()->makeDesc(rt, programInfo); if (!desc.isValid()) { return nullptr; diff --git a/chromium/third_party/skia/src/gpu/dawn/GrDawnGpu.h b/chromium/third_party/skia/src/gpu/dawn/GrDawnGpu.h index ac4f983bb62..fd09f9e5f56 100644 --- a/chromium/third_party/skia/src/gpu/dawn/GrDawnGpu.h +++ b/chromium/third_party/skia/src/gpu/dawn/GrDawnGpu.h @@ -61,7 +61,8 @@ public: int numStencilSamples) override; GrOpsRenderPass* getOpsRenderPass( - GrRenderTarget*, GrSurfaceOrigin, const SkIRect& bounds, + GrRenderTarget*, GrStencilAttachment*, + GrSurfaceOrigin, const SkIRect& bounds, const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; diff --git a/chromium/third_party/skia/src/gpu/dawn/GrDawnOpsRenderPass.cpp b/chromium/third_party/skia/src/gpu/dawn/GrDawnOpsRenderPass.cpp index 8c23a31d973..ba4c73e77ac 100644 --- a/chromium/third_party/skia/src/gpu/dawn/GrDawnOpsRenderPass.cpp +++ b/chromium/third_party/skia/src/gpu/dawn/GrDawnOpsRenderPass.cpp @@ -7,7 +7,6 @@ #include "src/gpu/dawn/GrDawnOpsRenderPass.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrOpFlushState.h" #include "src/gpu/GrPipeline.h" #include "src/gpu/GrRenderTargetPriv.h" @@ -94,12 +93,15 @@ void GrDawnOpsRenderPass::submit() { fGpu->appendCommandBuffer(fEncoder.Finish()); } -void GrDawnOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) { +void GrDawnOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, + bool insideStencilMask) { + SkASSERT(!scissor.enabled()); fPassEncoder.EndPass(); fPassEncoder = beginRenderPass(wgpu::LoadOp::Load, wgpu::LoadOp::Clear); } -void GrDawnOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) { +void GrDawnOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) { + SkASSERT(!scissor.enabled()); fPassEncoder.EndPass(); fPassEncoder = beginRenderPass(wgpu::LoadOp::Clear, wgpu::LoadOp::Load); } @@ -108,7 +110,8 @@ void GrDawnOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& co void GrDawnOpsRenderPass::inlineUpload(GrOpFlushState* state, GrDeferredTextureUploadFn& upload) { - SkASSERT(!"unimplemented"); + fGpu->submitToGpu(false); + state->doUpload(upload); } //////////////////////////////////////////////////////////////////////////////// @@ -144,20 +147,22 @@ bool GrDawnOpsRenderPass::onBindPipeline(const GrProgramInfo& programInfo, } void GrDawnOpsRenderPass::onSetScissorRect(const SkIRect& scissor) { - SkIRect rect; - SkIRect currentPipelineBounds = - SkIRect::MakeWH(fRenderTarget->width(), fRenderTarget->height()); - if (!rect.intersect(currentPipelineBounds, scissor)) { - rect = SkIRect::MakeEmpty(); - } - fPassEncoder.SetScissorRect(rect.x(), rect.y(), rect.width(), rect.height()); + // Higher-level GrRenderTargetContext and clips should have already ensured draw bounds are + // restricted to the render target. This is a sanity check. + SkASSERT(SkIRect::MakeSize(fRenderTarget->dimensions()).contains(scissor)); + auto nativeScissorRect = + GrNativeRect::MakeRelativeTo(fOrigin, fRenderTarget->height(), scissor); + fPassEncoder.SetScissorRect(nativeScissorRect.fX, nativeScissorRect.fY, + nativeScissorRect.fWidth, nativeScissorRect.fHeight); } bool GrDawnOpsRenderPass::onBindTextures(const GrPrimitiveProcessor& primProc, const GrSurfaceProxy* const primProcTextures[], const GrPipeline& pipeline) { auto bindGroup = fCurrentProgram->setTextures(fGpu, primProc, pipeline, primProcTextures); - fPassEncoder.SetBindGroup(1, bindGroup, 0, nullptr); + if (bindGroup) { + fPassEncoder.SetBindGroup(1, bindGroup, 0, nullptr); + } return true; } diff --git a/chromium/third_party/skia/src/gpu/dawn/GrDawnOpsRenderPass.h b/chromium/third_party/skia/src/gpu/dawn/GrDawnOpsRenderPass.h index 8ab0c771445..1f7b70f25ea 100644 --- a/chromium/third_party/skia/src/gpu/dawn/GrDawnOpsRenderPass.h +++ b/chromium/third_party/skia/src/gpu/dawn/GrDawnOpsRenderPass.h @@ -51,9 +51,9 @@ private: void onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, int baseInstance, int baseVertex) override; - void onClear(const GrFixedClip&, const SkPMColor4f& color) override; + void onClear(const GrScissorState& scissor, const SkPMColor4f& color) override; - void onClearStencilClip(const GrFixedClip&, bool insideStencilMask) override; + void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override; struct InlineUploadInfo { InlineUploadInfo(GrOpFlushState* state, const GrDeferredTextureUploadFn& upload) diff --git a/chromium/third_party/skia/src/gpu/dawn/GrDawnProgramBuilder.cpp b/chromium/third_party/skia/src/gpu/dawn/GrDawnProgramBuilder.cpp index 95d85fb7501..1008eac3d0b 100644 --- a/chromium/third_party/skia/src/gpu/dawn/GrDawnProgramBuilder.cpp +++ b/chromium/third_party/skia/src/gpu/dawn/GrDawnProgramBuilder.cpp @@ -325,29 +325,32 @@ sk_sp<GrDawnProgram> GrDawnProgramBuilder::Build(GrDawnGpu* gpu, if (0 != uniformBufferSize) { uniformLayoutEntries.push_back({ GrSPIRVUniformHandler::kUniformBinding, wgpu::ShaderStage::Vertex | wgpu::ShaderStage::Fragment, - wgpu::BindingType::UniformBuffer}); + wgpu::BindingType::UniformBuffer }); } wgpu::BindGroupLayoutDescriptor uniformBindGroupLayoutDesc; uniformBindGroupLayoutDesc.entryCount = uniformLayoutEntries.size(); uniformBindGroupLayoutDesc.entries = uniformLayoutEntries.data(); - result->fBindGroupLayouts[0] = - gpu->device().CreateBindGroupLayout(&uniformBindGroupLayoutDesc); + result->fBindGroupLayouts.push_back( + gpu->device().CreateBindGroupLayout(&uniformBindGroupLayoutDesc)); uint32_t binding = 0; std::vector<wgpu::BindGroupLayoutEntry> textureLayoutEntries; - for (int i = 0; i < builder.fUniformHandler.fSamplers.count(); ++i) { - textureLayoutEntries.push_back({ binding++, wgpu::ShaderStage::Fragment, - wgpu::BindingType::Sampler}); - textureLayoutEntries.push_back({ binding++, wgpu::ShaderStage::Fragment, - wgpu::BindingType::SampledTexture}); + int textureCount = builder.fUniformHandler.fSamplers.count(); + if (textureCount > 0) { + for (int i = 0; i < textureCount; ++i) { + textureLayoutEntries.push_back({ binding++, wgpu::ShaderStage::Fragment, + wgpu::BindingType::Sampler }); + textureLayoutEntries.push_back({ binding++, wgpu::ShaderStage::Fragment, + wgpu::BindingType::SampledTexture }); + } + wgpu::BindGroupLayoutDescriptor textureBindGroupLayoutDesc; + textureBindGroupLayoutDesc.entryCount = textureLayoutEntries.size(); + textureBindGroupLayoutDesc.entries = textureLayoutEntries.data(); + result->fBindGroupLayouts.push_back( + gpu->device().CreateBindGroupLayout(&textureBindGroupLayoutDesc)); } - wgpu::BindGroupLayoutDescriptor textureBindGroupLayoutDesc; - textureBindGroupLayoutDesc.entryCount = textureLayoutEntries.size(); - textureBindGroupLayoutDesc.entries = textureLayoutEntries.data(); - result->fBindGroupLayouts[1] = - gpu->device().CreateBindGroupLayout(&textureBindGroupLayoutDesc); wgpu::PipelineLayoutDescriptor pipelineLayoutDesc; - pipelineLayoutDesc.bindGroupLayoutCount = 2; - pipelineLayoutDesc.bindGroupLayouts = &result->fBindGroupLayouts[0]; + pipelineLayoutDesc.bindGroupLayoutCount = result->fBindGroupLayouts.size(); + pipelineLayoutDesc.bindGroupLayouts = result->fBindGroupLayouts.data(); auto pipelineLayout = gpu->device().CreatePipelineLayout(&pipelineLayoutDesc); result->fBuiltinUniformHandles = builder.fUniformHandles; const GrPipeline& pipeline = programInfo.pipeline(); @@ -365,9 +368,9 @@ sk_sp<GrDawnProgram> GrDawnProgramBuilder::Build(GrDawnGpu* gpu, std::vector<wgpu::VertexAttributeDescriptor> vertexAttributes; const GrPrimitiveProcessor& primProc = programInfo.primProc(); + int i = 0; if (primProc.numVertexAttributes() > 0) { size_t offset = 0; - int i = 0; for (const auto& attrib : primProc.vertexAttributes()) { wgpu::VertexAttributeDescriptor attribute; attribute.shaderLocation = i; @@ -387,7 +390,6 @@ sk_sp<GrDawnProgram> GrDawnProgramBuilder::Build(GrDawnGpu* gpu, std::vector<wgpu::VertexAttributeDescriptor> instanceAttributes; if (primProc.numInstanceAttributes() > 0) { size_t offset = 0; - int i = 0; for (const auto& attrib : primProc.instanceAttributes()) { wgpu::VertexAttributeDescriptor attribute; attribute.shaderLocation = i; @@ -543,6 +545,9 @@ wgpu::BindGroup GrDawnProgram::setTextures(GrDawnGpu* gpu, const GrPrimitiveProcessor& primProc, const GrPipeline& pipeline, const GrSurfaceProxy* const primProcTextures[]) { + if (fBindGroupLayouts.size() < 2) { + return nullptr; + } std::vector<wgpu::BindGroupEntry> bindings; int binding = 0; if (primProcTextures) { diff --git a/chromium/third_party/skia/src/gpu/dawn/GrDawnProgramBuilder.h b/chromium/third_party/skia/src/gpu/dawn/GrDawnProgramBuilder.h index b4f75d4e058..af707843b65 100644 --- a/chromium/third_party/skia/src/gpu/dawn/GrDawnProgramBuilder.h +++ b/chromium/third_party/skia/src/gpu/dawn/GrDawnProgramBuilder.h @@ -57,7 +57,7 @@ struct GrDawnProgram : public SkRefCnt { std::unique_ptr<GrGLSLXferProcessor> fXferProcessor; std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fFragmentProcessors; int fFragmentProcessorCnt; - wgpu::BindGroupLayout fBindGroupLayouts[2]; + std::vector<wgpu::BindGroupLayout> fBindGroupLayouts; wgpu::RenderPipeline fRenderPipeline; GrDawnProgramDataManager fDataManager; RenderTargetState fRenderTargetState; diff --git a/chromium/third_party/skia/src/gpu/dawn/GrDawnUtil.cpp b/chromium/third_party/skia/src/gpu/dawn/GrDawnUtil.cpp index 9f6daec00cc..91b155d8e76 100644 --- a/chromium/third_party/skia/src/gpu/dawn/GrDawnUtil.cpp +++ b/chromium/third_party/skia/src/gpu/dawn/GrDawnUtil.cpp @@ -45,6 +45,22 @@ bool GrColorTypeToDawnFormat(GrColorType ct, wgpu::TextureFormat* format) { } } +bool GrDawnFormatToGrColorType(wgpu::TextureFormat format, GrColorType* colorType) { + switch (format) { + case wgpu::TextureFormat::RGBA8Unorm: + *colorType = GrColorType::kRGBA_8888; + return true; + case wgpu::TextureFormat::BGRA8Unorm: + *colorType = GrColorType::kBGRA_8888; + return true; + case wgpu::TextureFormat::R8Unorm: + *colorType = GrColorType::kR_8; + return true; + default: + return false; + } +} + size_t GrDawnRoundRowBytes(size_t rowBytes) { // Dawn requires that rowBytes be a multiple of 256. (This is actually imposed by D3D12.) return (rowBytes + 0xFF) & ~0xFF; diff --git a/chromium/third_party/skia/src/gpu/dawn/GrDawnUtil.h b/chromium/third_party/skia/src/gpu/dawn/GrDawnUtil.h index 7b5ac6c5715..6f090ffe4a1 100644 --- a/chromium/third_party/skia/src/gpu/dawn/GrDawnUtil.h +++ b/chromium/third_party/skia/src/gpu/dawn/GrDawnUtil.h @@ -14,6 +14,7 @@ size_t GrDawnBytesPerPixel(wgpu::TextureFormat format); bool GrDawnFormatIsRenderable(wgpu::TextureFormat format); bool GrColorTypeToDawnFormat(GrColorType colorType, wgpu::TextureFormat* format); +bool GrDawnFormatToGrColorType(wgpu::TextureFormat format, GrColorType* colorType); size_t GrDawnRoundRowBytes(size_t rowBytes); #if GR_TEST_UTILS const char* GrDawnFormatToStr(wgpu::TextureFormat format); diff --git a/chromium/third_party/skia/src/gpu/effects/GrAARectEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrAARectEffect.fp index 856b761a0f5..6a66a69d732 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrAARectEffect.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrAARectEffect.fp @@ -5,12 +5,16 @@ * found in the LICENSE file. */ +in fragmentProcessor? inputFP; layout(key) in GrClipEdgeType edgeType; layout(ctype=SkRect) in float4 rect; layout(ctype=SkRect) float4 prevRect = float4(-1); uniform float4 rectUniform; -@optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag } +@optimizationFlags { + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag +} void main() { half alpha; @@ -37,7 +41,8 @@ void main() { @if (edgeType == GrClipEdgeType::kInverseFillBW || edgeType == GrClipEdgeType::kInverseFillAA) { alpha = 1.0 - alpha; } - sk_OutColor = sk_InColor * alpha; + half4 inputColor = sample(inputFP, sk_InColor); + sk_OutColor = inputColor * alpha; } @setData(pdman) { @@ -59,7 +64,7 @@ void main() { GrClipEdgeType edgeType = static_cast<GrClipEdgeType>( d->fRandom->nextULessThan(kGrClipEdgeTypeCnt)); - fp = GrAARectEffect::Make(edgeType, rect); + fp = GrAARectEffect::Make(/*inputFP=*/nullptr, edgeType, rect); } while (nullptr == fp); return fp; } diff --git a/chromium/third_party/skia/src/gpu/effects/GrAlphaThresholdFragmentProcessor.fp b/chromium/third_party/skia/src/gpu/effects/GrAlphaThresholdFragmentProcessor.fp index 4eb3a4eeeff..24aaf921c7e 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrAlphaThresholdFragmentProcessor.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrAlphaThresholdFragmentProcessor.fp @@ -5,47 +5,19 @@ * found in the LICENSE file. */ -in uniform sampler2D mask; +in fragmentProcessor? inputFP; +in fragmentProcessor maskFP; in uniform half innerThreshold; in uniform half outerThreshold; -@class { - inline OptimizationFlags optFlags(float outerThreshold); -} - -@constructorParams { - const SkIRect& bounds -} - -@make { - static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView mask, - float innerThreshold, - float outerThreshold, - const SkIRect& bounds) { - return std::unique_ptr<GrFragmentProcessor>(new GrAlphaThresholdFragmentProcessor( - std::move(mask), innerThreshold, outerThreshold, bounds)); - } -} - -@coordTransform(mask) { - SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())) -} - -@cpp { - inline GrFragmentProcessor::OptimizationFlags GrAlphaThresholdFragmentProcessor::optFlags( - float outerThreshold) { - if (outerThreshold >= 1.0) { - return kPreservesOpaqueInput_OptimizationFlag | - kCompatibleWithCoverageAsAlpha_OptimizationFlag; - } else { - return kCompatibleWithCoverageAsAlpha_OptimizationFlag; - } - } +@optimizationFlags { + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & + ((outerThreshold >= 1.0) ? kPreservesOpaqueInput_OptimizationFlag : kNone_OptimizationFlags) } void main() { - half4 color = sk_InColor; - half4 mask_color = sample(mask, sk_TransformedCoords2D[0]); + half4 color = sample(inputFP, sk_InColor); + half4 mask_color = sample(maskFP); if (mask_color.a < 0.5) { if (color.a > outerThreshold) { half scale = outerThreshold / color.a; @@ -61,18 +33,15 @@ void main() { } @test(testData) { - auto [maskView, ct, at] = testData->randomAlphaOnlyView(); - // Make the inner and outer thresholds be in (0, 1) exclusive and be sorted correctly. - float innerThresh = testData->fRandom->nextUScalar1() * .99f + 0.005f; - float outerThresh = testData->fRandom->nextUScalar1() * .99f + 0.005f; - const int kMaxWidth = 1000; - const int kMaxHeight = 1000; - uint32_t width = testData->fRandom->nextULessThan(kMaxWidth); - uint32_t height = testData->fRandom->nextULessThan(kMaxHeight); - uint32_t x = testData->fRandom->nextULessThan(kMaxWidth - width); - uint32_t y = testData->fRandom->nextULessThan(kMaxHeight - height); - SkIRect bounds = SkIRect::MakeXYWH(x, y, width, height); + // Make the inner and outer thresholds be in [0, 1]. + float outerThresh = testData->fRandom->nextUScalar1(); + float innerThresh = testData->fRandom->nextUScalar1(); + std::unique_ptr<GrFragmentProcessor> inputChild, maskChild; + if (testData->fRandom->nextBool()) { + inputChild = GrProcessorUnitTest::MakeChildFP(testData); + } + maskChild = GrProcessorUnitTest::MakeChildFP(testData); - return GrAlphaThresholdFragmentProcessor::Make(std::move(maskView), innerThresh, outerThresh, - bounds); + return GrAlphaThresholdFragmentProcessor::Make(std::move(inputChild), std::move(maskChild), + innerThresh, outerThresh); } diff --git a/chromium/third_party/skia/src/gpu/effects/GrBezierEffect.cpp b/chromium/third_party/skia/src/gpu/effects/GrBezierEffect.cpp index 2fc715c70f2..e127ab4a0d3 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrBezierEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrBezierEffect.cpp @@ -28,12 +28,8 @@ public: const CoordTransformRange& transformRange) override { const GrConicEffect& ce = primProc.cast<GrConicEffect>(); - if (!ce.viewMatrix().isIdentity() && - !SkMatrixPriv::CheapEqual(fViewMatrix, ce.viewMatrix())) - { - fViewMatrix = ce.viewMatrix(); - pdman.setSkMatrix(fViewMatrixUniform, fViewMatrix); - } + this->setTransform(pdman, fViewMatrixUniform, ce.viewMatrix(), &fViewMatrix); + this->setTransform(pdman, fLocalMatrixUniform, ce.localMatrix(), &fLocalMatrix); if (ce.color() != fColor) { pdman.set4fv(fColorUniform, 1, ce.color().vec()); @@ -44,26 +40,27 @@ public: pdman.set1f(fCoverageScaleUniform, GrNormalizeByteToFloat(ce.coverageScale())); fCoverageScale = ce.coverageScale(); } - this->setTransformDataHelper(ce.localMatrix(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); } private: SkMatrix fViewMatrix; + SkMatrix fLocalMatrix; SkPMColor4f fColor; uint8_t fCoverageScale; - GrClipEdgeType fEdgeType; UniformHandle fColorUniform; UniformHandle fCoverageScaleUniform; UniformHandle fViewMatrixUniform; + UniformHandle fLocalMatrixUniform; typedef GrGLSLGeometryProcessor INHERITED; }; GrGLConicEffect::GrGLConicEffect(const GrGeometryProcessor& processor) - : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(SK_PMColor4fILLEGAL), fCoverageScale(0xff) { - const GrConicEffect& ce = processor.cast<GrConicEffect>(); - fEdgeType = ce.getEdgeType(); -} + : fViewMatrix(SkMatrix::InvalidMatrix()) + , fLocalMatrix(SkMatrix::InvalidMatrix()) + , fColor(SK_PMColor4fILLEGAL) + , fCoverageScale(0xff) {} void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; @@ -89,14 +86,10 @@ void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { gp.inPosition().name(), gp.viewMatrix(), &fViewMatrixUniform); - - // emit transforms with position - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - gp.inPosition().asShaderVar(), - gp.localMatrix(), - args.fFPCoordTransformHandler); + if (gp.usesLocalCoords()) { + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, gp.inPosition().asShaderVar(), + gp.localMatrix(), &fLocalMatrixUniform); + } // TODO: we should check on the number of bits float and half provide and use the smallest one // that suffices. Additionally we should assert that the upstream code only lets us get here if @@ -120,74 +113,31 @@ void GrGLConicEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { fragBuilder->declAppend(gFM); fragBuilder->declAppend(func); - switch (fEdgeType) { - case GrClipEdgeType::kHairlineAA: { - fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn()); - fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn()); - fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", - dfdx.c_str(), - v.fsIn(), dklmdx.c_str(), - v.fsIn(), dklmdx.c_str(), - v.fsIn(), dklmdx.c_str()); - fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", - dfdy.c_str(), - v.fsIn(), dklmdy.c_str(), - v.fsIn(), dklmdy.c_str(), - v.fsIn(), dklmdy.c_str()); - fragBuilder->codeAppendf("%s = float2(%s, %s);", gF.c_str(), dfdx.c_str(), - dfdy.c_str()); - fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", - gFM.c_str(), gF.c_str(), gF.c_str()); - fragBuilder->codeAppendf("%s = %s.x*%s.x - %s.y*%s.z;", - func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); - fragBuilder->codeAppendf("%s = abs(%s);", func.c_str(), func.c_str()); - fragBuilder->codeAppendf("%s = half(%s / %s);", - edgeAlpha.c_str(), func.c_str(), gFM.c_str()); - fragBuilder->codeAppendf("%s = max(1.0 - %s, 0.0);", - edgeAlpha.c_str(), edgeAlpha.c_str()); - // Add line below for smooth cubic ramp - // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);"); - break; - } - case GrClipEdgeType::kFillAA: { - fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn()); - fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn()); - fragBuilder->codeAppendf("%s =" - "2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", - dfdx.c_str(), - v.fsIn(), dklmdx.c_str(), - v.fsIn(), dklmdx.c_str(), - v.fsIn(), dklmdx.c_str()); - fragBuilder->codeAppendf("%s =" - "2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", - dfdy.c_str(), - v.fsIn(), dklmdy.c_str(), - v.fsIn(), dklmdy.c_str(), - v.fsIn(), dklmdy.c_str()); - fragBuilder->codeAppendf("%s = float2(%s, %s);", gF.c_str(), dfdx.c_str(), - dfdy.c_str()); - fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", - gFM.c_str(), gF.c_str(), gF.c_str()); - fragBuilder->codeAppendf("%s = %s.x * %s.x - %s.y * %s.z;", - func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); - fragBuilder->codeAppendf("%s = half(%s / %s);", - edgeAlpha.c_str(), func.c_str(), gFM.c_str()); - fragBuilder->codeAppendf("%s = saturate(0.5 - %s);", - edgeAlpha.c_str(), edgeAlpha.c_str()); - // Add line below for smooth cubic ramp - // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);"); - break; - } - case GrClipEdgeType::kFillBW: { - fragBuilder->codeAppendf("%s = half(%s.x * %s.x - %s.y * %s.z);", - edgeAlpha.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); - fragBuilder->codeAppendf("%s = half(%s < 0.0);", - edgeAlpha.c_str(), edgeAlpha.c_str()); - break; - } - default: - SK_ABORT("Shouldn't get here"); - } + fragBuilder->codeAppendf("%s = dFdx(%s.xyz);", dklmdx.c_str(), v.fsIn()); + fragBuilder->codeAppendf("%s = dFdy(%s.xyz);", dklmdy.c_str(), v.fsIn()); + fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", + dfdx.c_str(), + v.fsIn(), dklmdx.c_str(), + v.fsIn(), dklmdx.c_str(), + v.fsIn(), dklmdx.c_str()); + fragBuilder->codeAppendf("%s = 2.0 * %s.x * %s.x - %s.y * %s.z - %s.z * %s.y;", + dfdy.c_str(), + v.fsIn(), dklmdy.c_str(), + v.fsIn(), dklmdy.c_str(), + v.fsIn(), dklmdy.c_str()); + fragBuilder->codeAppendf("%s = float2(%s, %s);", gF.c_str(), dfdx.c_str(), + dfdy.c_str()); + fragBuilder->codeAppendf("%s = sqrt(dot(%s, %s));", + gFM.c_str(), gF.c_str(), gF.c_str()); + fragBuilder->codeAppendf("%s = %s.x*%s.x - %s.y*%s.z;", + func.c_str(), v.fsIn(), v.fsIn(), v.fsIn(), v.fsIn()); + fragBuilder->codeAppendf("%s = abs(%s);", func.c_str(), func.c_str()); + fragBuilder->codeAppendf("%s = half(%s / %s);", + edgeAlpha.c_str(), func.c_str(), gFM.c_str()); + fragBuilder->codeAppendf("%s = max(1.0 - %s, 0.0);", + edgeAlpha.c_str(), edgeAlpha.c_str()); + // Add line below for smooth cubic ramp + // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);"); // TODO should we really be doing this? if (gp.coverageScale() != 0xff) { @@ -210,8 +160,9 @@ void GrGLConicEffect::GenKey(const GrGeometryProcessor& gp, const GrConicEffect& ce = gp.cast<GrConicEffect>(); uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2; key |= 0xff != ce.coverageScale() ? 0x8 : 0x0; - key |= ce.usesLocalCoords() && ce.localMatrix().hasPerspective() ? 0x10 : 0x0; - key |= ComputePosKey(ce.viewMatrix()) << 5; + key |= ce.usesLocalCoords() ? 0x10 : 0x0; + key = AddMatrixKeys(key, ce.viewMatrix(), ce.usesLocalCoords() ? ce.localMatrix() + : SkMatrix::I()); b->add32(key); } @@ -231,15 +182,13 @@ GrGLSLPrimitiveProcessor* GrConicEffect::createGLSLInstance(const GrShaderCaps&) } GrConicEffect::GrConicEffect(const SkPMColor4f& color, const SkMatrix& viewMatrix, uint8_t coverage, - GrClipEdgeType edgeType, const SkMatrix& localMatrix, - bool usesLocalCoords) + const SkMatrix& localMatrix, bool usesLocalCoords) : INHERITED(kGrConicEffect_ClassID) , fColor(color) , fViewMatrix(viewMatrix) , fLocalMatrix(viewMatrix) , fUsesLocalCoords(usesLocalCoords) - , fCoverageScale(coverage) - , fEdgeType(edgeType) { + , fCoverageScale(coverage) { this->setVertexAttributes(kAttributes, SK_ARRAY_COUNT(kAttributes)); } @@ -249,17 +198,10 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrConicEffect); #if GR_TEST_UTILS GrGeometryProcessor* GrConicEffect::TestCreate(GrProcessorTestData* d) { - GrGeometryProcessor* gp; - do { - GrClipEdgeType edgeType = - static_cast<GrClipEdgeType>( - d->fRandom->nextULessThan(kGrClipEdgeTypeCnt)); - gp = GrConicEffect::Make(d->allocator(), - SkPMColor4f::FromBytes_RGBA(GrRandomColor(d->fRandom)), - GrTest::TestMatrix(d->fRandom), edgeType, *d->caps(), - GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool()); - } while (nullptr == gp); - return gp; + return GrConicEffect::Make(d->allocator(), + SkPMColor4f::FromBytes_RGBA(GrRandomColor(d->fRandom)), + GrTest::TestMatrix(d->fRandom), *d->caps(), + GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool()); } #endif @@ -281,12 +223,8 @@ public: const CoordTransformRange& transformRange) override { const GrQuadEffect& qe = primProc.cast<GrQuadEffect>(); - if (!qe.viewMatrix().isIdentity() && - !SkMatrixPriv::CheapEqual(fViewMatrix, qe.viewMatrix())) - { - fViewMatrix = qe.viewMatrix(); - pdman.setSkMatrix(fViewMatrixUniform, fViewMatrix); - } + this->setTransform(pdman, fViewMatrixUniform, qe.viewMatrix(), &fViewMatrix); + this->setTransform(pdman, fLocalMatrixUniform, qe.localMatrix(), &fLocalMatrix); if (qe.color() != fColor) { pdman.set4fv(fColorUniform, 1, qe.color().vec()); @@ -297,26 +235,28 @@ public: pdman.set1f(fCoverageScaleUniform, GrNormalizeByteToFloat(qe.coverageScale())); fCoverageScale = qe.coverageScale(); } - this->setTransformDataHelper(qe.localMatrix(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); } private: SkMatrix fViewMatrix; + SkMatrix fLocalMatrix; SkPMColor4f fColor; uint8_t fCoverageScale; - GrClipEdgeType fEdgeType; + UniformHandle fColorUniform; UniformHandle fCoverageScaleUniform; UniformHandle fViewMatrixUniform; + UniformHandle fLocalMatrixUniform; typedef GrGLSLGeometryProcessor INHERITED; }; GrGLQuadEffect::GrGLQuadEffect(const GrGeometryProcessor& processor) - : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(SK_PMColor4fILLEGAL), fCoverageScale(0xff) { - const GrQuadEffect& ce = processor.cast<GrQuadEffect>(); - fEdgeType = ce.getEdgeType(); -} + : fViewMatrix(SkMatrix::InvalidMatrix()) + , fLocalMatrix(SkMatrix::InvalidMatrix()) + , fColor(SK_PMColor4fILLEGAL) + , fCoverageScale(0xff) {} void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; @@ -342,55 +282,24 @@ void GrGLQuadEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { gp.inPosition().name(), gp.viewMatrix(), &fViewMatrixUniform); - - // emit transforms with position - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - gp.inPosition().asShaderVar(), - gp.localMatrix(), - args.fFPCoordTransformHandler); + if (gp.usesLocalCoords()) { + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, gp.inPosition().asShaderVar(), + gp.localMatrix(), &fLocalMatrixUniform); + } fragBuilder->codeAppendf("half edgeAlpha;"); - switch (fEdgeType) { - case GrClipEdgeType::kHairlineAA: { - fragBuilder->codeAppendf("half2 duvdx = half2(dFdx(%s.xy));", v.fsIn()); - fragBuilder->codeAppendf("half2 duvdy = half2(dFdy(%s.xy));", v.fsIn()); - fragBuilder->codeAppendf("half2 gF = half2(2.0 * %s.x * duvdx.x - duvdx.y," - " 2.0 * %s.x * duvdy.x - duvdy.y);", - v.fsIn(), v.fsIn()); - fragBuilder->codeAppendf("edgeAlpha = half(%s.x * %s.x - %s.y);", - v.fsIn(), v.fsIn(), v.fsIn()); - fragBuilder->codeAppend("edgeAlpha = sqrt(edgeAlpha * edgeAlpha / dot(gF, gF));"); - fragBuilder->codeAppend("edgeAlpha = max(1.0 - edgeAlpha, 0.0);"); - // Add line below for smooth cubic ramp - // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);"); - break; - } - case GrClipEdgeType::kFillAA: { - fragBuilder->codeAppendf("half2 duvdx = half2(dFdx(%s.xy));", v.fsIn()); - fragBuilder->codeAppendf("half2 duvdy = half2(dFdy(%s.xy));", v.fsIn()); - fragBuilder->codeAppendf("half2 gF = half2(2.0 * %s.x * duvdx.x - duvdx.y," - " 2.0 * %s.x * duvdy.x - duvdy.y);", - v.fsIn(), v.fsIn()); - fragBuilder->codeAppendf("edgeAlpha = half(%s.x * %s.x - %s.y);", - v.fsIn(), v.fsIn(), v.fsIn()); - fragBuilder->codeAppend("edgeAlpha = edgeAlpha / sqrt(dot(gF, gF));"); - fragBuilder->codeAppend("edgeAlpha = saturate(0.5 - edgeAlpha);"); - // Add line below for smooth cubic ramp - // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);"); - break; - } - case GrClipEdgeType::kFillBW: { - fragBuilder->codeAppendf("edgeAlpha = half(%s.x * %s.x - %s.y);", - v.fsIn(), v.fsIn(), v.fsIn()); - fragBuilder->codeAppend("edgeAlpha = half(edgeAlpha < 0.0);"); - break; - } - default: - SK_ABORT("Shouldn't get here"); - } + fragBuilder->codeAppendf("half2 duvdx = half2(dFdx(%s.xy));", v.fsIn()); + fragBuilder->codeAppendf("half2 duvdy = half2(dFdy(%s.xy));", v.fsIn()); + fragBuilder->codeAppendf("half2 gF = half2(2.0 * %s.x * duvdx.x - duvdx.y," + " 2.0 * %s.x * duvdy.x - duvdy.y);", + v.fsIn(), v.fsIn()); + fragBuilder->codeAppendf("edgeAlpha = half(%s.x * %s.x - %s.y);", + v.fsIn(), v.fsIn(), v.fsIn()); + fragBuilder->codeAppend("edgeAlpha = sqrt(edgeAlpha * edgeAlpha / dot(gF, gF));"); + fragBuilder->codeAppend("edgeAlpha = max(1.0 - edgeAlpha, 0.0);"); + // Add line below for smooth cubic ramp + // fragBuilder->codeAppend("edgeAlpha = edgeAlpha*edgeAlpha*(3.0-2.0*edgeAlpha);"); if (0xff != gp.coverageScale()) { const char* coverageScale; @@ -412,8 +321,9 @@ void GrGLQuadEffect::GenKey(const GrGeometryProcessor& gp, const GrQuadEffect& ce = gp.cast<GrQuadEffect>(); uint32_t key = ce.isAntiAliased() ? (ce.isFilled() ? 0x0 : 0x1) : 0x2; key |= ce.coverageScale() != 0xff ? 0x8 : 0x0; - key |= ce.usesLocalCoords() && ce.localMatrix().hasPerspective() ? 0x10 : 0x0; - key |= ComputePosKey(ce.viewMatrix()) << 5; + key |= ce.usesLocalCoords()? 0x10 : 0x0; + key = AddMatrixKeys(key, ce.viewMatrix(), ce.usesLocalCoords() ? ce.localMatrix() + : SkMatrix::I()); b->add32(key); } @@ -433,15 +343,13 @@ GrGLSLPrimitiveProcessor* GrQuadEffect::createGLSLInstance(const GrShaderCaps&) } GrQuadEffect::GrQuadEffect(const SkPMColor4f& color, const SkMatrix& viewMatrix, uint8_t coverage, - GrClipEdgeType edgeType, const SkMatrix& localMatrix, - bool usesLocalCoords) + const SkMatrix& localMatrix, bool usesLocalCoords) : INHERITED(kGrQuadEffect_ClassID) , fColor(color) , fViewMatrix(viewMatrix) , fLocalMatrix(localMatrix) , fUsesLocalCoords(usesLocalCoords) - , fCoverageScale(coverage) - , fEdgeType(edgeType) { + , fCoverageScale(coverage) { this->setVertexAttributes(kAttributes, SK_ARRAY_COUNT(kAttributes)); } @@ -451,15 +359,9 @@ GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrQuadEffect); #if GR_TEST_UTILS GrGeometryProcessor* GrQuadEffect::TestCreate(GrProcessorTestData* d) { - GrGeometryProcessor* gp; - do { - GrClipEdgeType edgeType = static_cast<GrClipEdgeType>( - d->fRandom->nextULessThan(kGrClipEdgeTypeCnt)); - gp = GrQuadEffect::Make(d->allocator(), - SkPMColor4f::FromBytes_RGBA(GrRandomColor(d->fRandom)), - GrTest::TestMatrix(d->fRandom), edgeType, *d->caps(), - GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool()); - } while (nullptr == gp); - return gp; + return GrQuadEffect::Make(d->allocator(), + SkPMColor4f::FromBytes_RGBA(GrRandomColor(d->fRandom)), + GrTest::TestMatrix(d->fRandom), *d->caps(), + GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool()); } #endif diff --git a/chromium/third_party/skia/src/gpu/effects/GrBezierEffect.h b/chromium/third_party/skia/src/gpu/effects/GrBezierEffect.h index c59faebc5b3..87d3721a120 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrBezierEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/GrBezierEffect.h @@ -61,25 +61,15 @@ public: static GrGeometryProcessor* Make(SkArenaAlloc* arena, const SkPMColor4f& color, const SkMatrix& viewMatrix, - const GrClipEdgeType edgeType, const GrCaps& caps, const SkMatrix& localMatrix, bool usesLocalCoords, uint8_t coverage = 0xff) { - switch (edgeType) { - case GrClipEdgeType::kFillAA: // fall through - case GrClipEdgeType::kHairlineAA: - if (!caps.shaderCaps()->shaderDerivativeSupport()) { - return nullptr; - } - break; - case GrClipEdgeType::kFillBW: - break; - default: // kInverseFillBW or kInverseFillAA - return nullptr; + if (!caps.shaderCaps()->shaderDerivativeSupport()) { + return nullptr; } - return arena->make<GrConicEffect>(color, viewMatrix, coverage, edgeType, localMatrix, + return arena->make<GrConicEffect>(color, viewMatrix, coverage, localMatrix, usesLocalCoords); } @@ -89,9 +79,8 @@ public: inline const Attribute& inPosition() const { return kAttributes[0]; } inline const Attribute& inConicCoeffs() const { return kAttributes[1]; } - inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); } - inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); } - inline GrClipEdgeType getEdgeType() const { return fEdgeType; } + inline bool isAntiAliased() const { return true; } + inline bool isFilled() const { return false; } const SkPMColor4f& color() const { return fColor; } const SkMatrix& viewMatrix() const { return fViewMatrix; } const SkMatrix& localMatrix() const { return fLocalMatrix; } @@ -105,7 +94,7 @@ public: private: friend class ::SkArenaAlloc; // for access to ctor - GrConicEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage, GrClipEdgeType, + GrConicEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage, const SkMatrix& localMatrix, bool usesLocalCoords); SkPMColor4f fColor; @@ -113,7 +102,6 @@ private: SkMatrix fLocalMatrix; bool fUsesLocalCoords; uint8_t fCoverageScale; - GrClipEdgeType fEdgeType; static constexpr Attribute kAttributes[] = { {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType}, {"inConicCoeffs", kFloat4_GrVertexAttribType, kHalf4_GrSLType} @@ -140,26 +128,15 @@ public: static GrGeometryProcessor* Make(SkArenaAlloc* arena, const SkPMColor4f& color, const SkMatrix& viewMatrix, - const GrClipEdgeType edgeType, const GrCaps& caps, const SkMatrix& localMatrix, bool usesLocalCoords, uint8_t coverage = 0xff) { - switch (edgeType) { - case GrClipEdgeType::kFillAA: // fall through - case GrClipEdgeType::kHairlineAA: - if (!caps.shaderCaps()->shaderDerivativeSupport()) { - return nullptr; - } - break; - case GrClipEdgeType::kFillBW: - break; - default: // kInverseFillBW and kInverseFillAA - return nullptr; + if (!caps.shaderCaps()->shaderDerivativeSupport()) { + return nullptr; } - return arena->make<GrQuadEffect>(color, viewMatrix, coverage, edgeType, - localMatrix, usesLocalCoords); + return arena->make<GrQuadEffect>(color, viewMatrix, coverage, localMatrix, usesLocalCoords); } ~GrQuadEffect() override; @@ -168,9 +145,8 @@ public: inline const Attribute& inPosition() const { return kAttributes[0]; } inline const Attribute& inHairQuadEdge() const { return kAttributes[1]; } - inline bool isAntiAliased() const { return GrProcessorEdgeTypeIsAA(fEdgeType); } - inline bool isFilled() const { return GrProcessorEdgeTypeIsFill(fEdgeType); } - inline GrClipEdgeType getEdgeType() const { return fEdgeType; } + inline bool isAntiAliased() const { return true; } + inline bool isFilled() const { return false; } const SkPMColor4f& color() const { return fColor; } const SkMatrix& viewMatrix() const { return fViewMatrix; } const SkMatrix& localMatrix() const { return fLocalMatrix; } @@ -184,7 +160,7 @@ public: private: friend class ::SkArenaAlloc; // for access to ctor - GrQuadEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage, GrClipEdgeType, + GrQuadEffect(const SkPMColor4f&, const SkMatrix& viewMatrix, uint8_t coverage, const SkMatrix& localMatrix, bool usesLocalCoords); SkPMColor4f fColor; @@ -192,7 +168,6 @@ private: SkMatrix fLocalMatrix; bool fUsesLocalCoords; uint8_t fCoverageScale; - GrClipEdgeType fEdgeType; static constexpr Attribute kAttributes[] = { {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType}, diff --git a/chromium/third_party/skia/src/gpu/effects/GrBicubicEffect.cpp b/chromium/third_party/skia/src/gpu/effects/GrBicubicEffect.cpp index ef9560e57e8..d575668ba49 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrBicubicEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrBicubicEffect.cpp @@ -176,9 +176,8 @@ GrBicubicEffect::GrBicubicEffect(std::unique_ptr<GrFragmentProcessor> fp, , fCoordTransform(matrix) , fDirection(direction) , fClamp(clamp) { - fp->setSampledWithExplicitCoords(); this->addCoordTransform(&fCoordTransform); - this->registerChildProcessor(std::move(fp)); + this->registerExplicitlySampledChild(std::move(fp)); } GrBicubicEffect::GrBicubicEffect(const GrBicubicEffect& that) @@ -187,9 +186,7 @@ GrBicubicEffect::GrBicubicEffect(const GrBicubicEffect& that) , fDirection(that.fDirection) , fClamp(that.fClamp) { this->addCoordTransform(&fCoordTransform); - auto child = that.childProcessor(0).clone(); - child->setSampledWithExplicitCoords(); - this->registerChildProcessor(std::move(child)); + this->cloneAndRegisterAllChildProcessors(that); } void GrBicubicEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, diff --git a/chromium/third_party/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp b/chromium/third_party/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp index 87612127b20..4a9f94e52cd 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrBitmapTextGeoProc.cpp @@ -20,7 +20,10 @@ class GrGLBitmapTextGeoProc : public GrGLSLGeometryProcessor { public: - GrGLBitmapTextGeoProc() : fColor(SK_PMColor4fILLEGAL), fAtlasDimensions{0,0} {} + GrGLBitmapTextGeoProc() + : fColor(SK_PMColor4fILLEGAL) + , fAtlasDimensions{0,0} + , fLocalMatrix(SkMatrix::InvalidMatrix()) {} void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const GrBitmapTextGeoProc& btgp = args.fGP.cast<GrBitmapTextGeoProc>(); @@ -53,14 +56,8 @@ public: // Setup position gpArgs->fPositionVar = btgp.inPosition().asShaderVar(); - - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - btgp.inPosition().asShaderVar(), - btgp.localMatrix(), - args.fFPCoordTransformHandler); + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, btgp.inPosition().asShaderVar(), + btgp.localMatrix(), &fLocalMatrixUniform); fragBuilder->codeAppend("half4 texColor;"); append_multitexture_lookup(args, btgp.numTextureSamplers(), @@ -92,7 +89,9 @@ public: 1.0f / atlasDimensions.fHeight); fAtlasDimensions = atlasDimensions; } - this->setTransformDataHelper(btgp.localMatrix(), pdman, transformRange); + + this->setTransform(pdman, fLocalMatrixUniform, btgp.localMatrix(), &fLocalMatrix); + this->setTransformDataHelper(pdman, transformRange); } static inline void GenKey(const GrGeometryProcessor& proc, @@ -102,6 +101,7 @@ public: uint32_t key = 0; key |= btgp.usesW() ? 0x1 : 0x0; key |= btgp.maskFormat() << 1; + key |= ComputeMatrixKey(btgp.localMatrix()) << 2; b->add32(key); b->add32(btgp.numTextureSamplers()); } @@ -113,6 +113,9 @@ private: SkISize fAtlasDimensions; UniformHandle fAtlasDimensionsInvUniform; + SkMatrix fLocalMatrix; + UniformHandle fLocalMatrixUniform; + typedef GrGLSLGeometryProcessor INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/effects/GrBlurredEdgeFragmentProcessor.fp b/chromium/third_party/skia/src/gpu/effects/GrBlurredEdgeFragmentProcessor.fp index 6126c7d5f6e..f5fde018544 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrBlurredEdgeFragmentProcessor.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrBlurredEdgeFragmentProcessor.fp @@ -10,10 +10,12 @@ enum class Mode { kSmoothStep = 1 }; +in fragmentProcessor? inputFP; layout(key) in Mode mode; void main() { - half factor = 1.0 - sk_InColor.a; + half inputAlpha = sample(inputFP, sk_InColor).a; + half factor = 1.0 - inputAlpha; @switch (mode) { case Mode::kGaussian: factor = half(exp(-factor * factor * 4.0) - 0.018); diff --git a/chromium/third_party/skia/src/gpu/effects/GrCircleBlurFragmentProcessor.fp b/chromium/third_party/skia/src/gpu/effects/GrCircleBlurFragmentProcessor.fp index 12eaeb6e24a..458431cefc0 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrCircleBlurFragmentProcessor.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrCircleBlurFragmentProcessor.fp @@ -5,10 +5,15 @@ * found in the LICENSE file. */ +in fragmentProcessor? inputFP; in half4 circleRect; -in half textureRadius; in half solidRadius; -in uniform sampler2D blurProfileSampler; +in half textureRadius; +in fragmentProcessor blurProfile; + +@header { + #include "src/gpu/effects/GrTextureEffect.h" +}; // The data is formatted as: // x, y - the center of the circle @@ -17,12 +22,14 @@ in uniform sampler2D blurProfileSampler; uniform half4 circleData; @optimizationFlags { + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & kCompatibleWithCoverageAsAlpha_OptimizationFlag } @make { - static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext*, - const SkRect& circle, float sigma); + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrRecordingContext*, const SkRect& circle, + float sigma); } @setData(data) { @@ -188,13 +195,14 @@ uniform half4 circleData; profile[profileWidth - 1] = 0; } - static GrSurfaceProxyView create_profile_texture(GrRecordingContext* context, + static std::unique_ptr<GrFragmentProcessor> create_profile_effect(GrRecordingContext* context, const SkRect& circle, float sigma, - float* solidRadius, float* textureRadius) { + float* solidRadius, + float* textureRadius) { float circleR = circle.width() / 2.0f; if (circleR < SK_ScalarNearlyZero) { - return {}; + return nullptr; } // Profile textures are cached by the ratio of sigma to circle radius and by the size of the // profile texture (binned by powers of 2). @@ -224,6 +232,12 @@ uniform half4 circleData; *textureRadius = circleR + 3 * sigma; } + static constexpr int kProfileTextureWidth = 512; + // This would be kProfileTextureWidth/textureRadius if it weren't for the fact that we do + // the calculation of the profile coord in a coord space that has already been scaled by + // 1 / textureRadius. This is done to avoid overflow in length(). + SkMatrix texM = SkMatrix::Scale(kProfileTextureWidth, 1.f); + static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey key; GrUniqueKey::Builder builder(&key, kDomain, 1, "1-D Circular Blur"); @@ -234,14 +248,14 @@ uniform half4 circleData; if (sk_sp<GrTextureProxy> blurProfile = proxyProvider->findOrCreateProxyByUniqueKey(key)) { GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(blurProfile->backendFormat(), GrColorType::kAlpha_8); - return {std::move(blurProfile), kTopLeft_GrSurfaceOrigin, swizzle}; + GrSurfaceProxyView profileView{std::move(blurProfile), kTopLeft_GrSurfaceOrigin, + swizzle}; + return GrTextureEffect::Make(std::move(profileView), kPremul_SkAlphaType, texM); } - static constexpr int kProfileTextureWidth = 512; - SkBitmap bm; if (!bm.tryAllocPixels(SkImageInfo::MakeA8(kProfileTextureWidth, 1))) { - return {}; + return nullptr; } if (useHalfPlaneApprox) { @@ -256,40 +270,42 @@ uniform half4 circleData; bm.setImmutable(); GrBitmapTextureMaker maker(context, bm, GrImageTexGenPolicy::kNew_Uncached_Budgeted); - auto blurView = maker.view(GrMipMapped::kNo); - if (!blurView) { - return {}; + auto profileView = maker.view(GrMipMapped::kNo); + if (!profileView) { + return nullptr; } - proxyProvider->assignUniqueKeyToProxy(key, blurView.asTextureProxy()); - return blurView; + proxyProvider->assignUniqueKeyToProxy(key, profileView.asTextureProxy()); + return GrTextureEffect::Make(std::move(profileView), kPremul_SkAlphaType, texM); } std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::Make( - GrRecordingContext* context, const SkRect& circle, float sigma) { + std::unique_ptr<GrFragmentProcessor> inputFP, GrRecordingContext* context, + const SkRect& circle, float sigma) { float solidRadius; float textureRadius; - GrSurfaceProxyView profile = create_profile_texture(context, circle, sigma, + std::unique_ptr<GrFragmentProcessor> profile = create_profile_effect(context, circle, sigma, &solidRadius, &textureRadius); if (!profile) { return nullptr; } return std::unique_ptr<GrFragmentProcessor>(new GrCircleBlurFragmentProcessor( - circle, textureRadius, solidRadius, std::move(profile))); + std::move(inputFP), circle, solidRadius, textureRadius, std::move(profile))); } } void main() { // We just want to compute "(length(vec) - circleData.z + 0.5) * circleData.w" but need to - // rearrange for precision. - half2 vec = half2(half((sk_FragCoord.x - circleData.x) * circleData.w), - half((sk_FragCoord.y - circleData.y) * circleData.w)); + // rearrange to avoid passing large values to length() that would overflow. + half2 vec = half2((sk_FragCoord.xy - circleData.xy) * circleData.w); half dist = length(vec) + (0.5 - circleData.z) * circleData.w; - sk_OutColor = sk_InColor * sample(blurProfileSampler, half2(dist, 0.5)).a; + half4 inputColor = sample(inputFP, sk_InColor); + sk_OutColor = inputColor * sample(blurProfile, half2(dist, 0.5)).a; } @test(testData) { SkScalar wh = testData->fRandom->nextRangeScalar(100.f, 1000.f); - SkScalar sigma = testData->fRandom->nextRangeF(1.f,10.f); + SkScalar sigma = testData->fRandom->nextRangeF(1.f, 10.f); SkRect circle = SkRect::MakeWH(wh, wh); - return GrCircleBlurFragmentProcessor::Make(testData->context(), circle, sigma); + return GrCircleBlurFragmentProcessor::Make(/*inputFP=*/nullptr, testData->context(), + circle, sigma); } diff --git a/chromium/third_party/skia/src/gpu/effects/GrCircleEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrCircleEffect.fp index ac06c7c47ba..00c6733a713 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrCircleEffect.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrCircleEffect.fp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +in fragmentProcessor? inputFP; layout(key) in GrClipEdgeType edgeType; in float2 center; in float radius; @@ -16,18 +17,22 @@ float prevRadius = -1; uniform float4 circle; @make { - static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkPoint center, - float radius) { + static GrFPResult Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, SkPoint center, float radius) { // A radius below half causes the implicit insetting done by this processor to become // inverted. We could handle this case by making the processor code more complicated. if (radius < .5f && GrProcessorEdgeTypeIsInverseFill(edgeType)) { - return nullptr; + return GrFPFailure(std::move(inputFP)); } - return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(edgeType, center, radius)); + return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>( + new GrCircleEffect(std::move(inputFP), edgeType, center, radius))); } } -@optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag } +@optimizationFlags { + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag +} @setData(pdman) { if (radius != prevRadius || center != prevCenter) { @@ -57,12 +62,12 @@ void main() { } else { d = half((1.0 - length((circle.xy - sk_FragCoord.xy) * circle.w)) * circle.z); } + half4 inputColor = sample(inputFP, sk_InColor); @if (edgeType == GrClipEdgeType::kFillAA || - edgeType == GrClipEdgeType::kInverseFillAA || - edgeType == GrClipEdgeType::kHairlineAA) { - sk_OutColor = sk_InColor * saturate(d); + edgeType == GrClipEdgeType::kInverseFillAA) { + sk_OutColor = inputColor * saturate(d); } else { - sk_OutColor = d > 0.5 ? sk_InColor : half4(0); + sk_OutColor = d > 0.5 ? inputColor : half4(0); } } @@ -71,9 +76,11 @@ void main() { center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f); center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f); SkScalar radius = testData->fRandom->nextRangeF(1.f, 1000.f); - GrClipEdgeType et; + bool success; + std::unique_ptr<GrFragmentProcessor> fp; do { - et = (GrClipEdgeType) testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt); - } while (GrClipEdgeType::kHairlineAA == et); - return GrCircleEffect::Make(et, center, radius); + GrClipEdgeType et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt); + std::tie(success, fp) = GrCircleEffect::Make(/*inputFP=*/nullptr, et, center, radius); + } while (!success); + return fp; } diff --git a/chromium/third_party/skia/src/gpu/effects/GrClampFragmentProcessor.fp b/chromium/third_party/skia/src/gpu/effects/GrClampFragmentProcessor.fp index f81fe08de7e..ed6771cbb5d 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrClampFragmentProcessor.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrClampFragmentProcessor.fp @@ -5,24 +5,30 @@ * found in the LICENSE file. */ +in fragmentProcessor? inputFP; layout(key) in bool clampToPremul; @optimizationFlags { - kConstantOutputForConstantInput_OptimizationFlag | - kPreservesOpaqueInput_OptimizationFlag + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & + (kConstantOutputForConstantInput_OptimizationFlag | + kPreservesOpaqueInput_OptimizationFlag) } void main() { + half4 inputColor = sample(inputFP, sk_InColor); @if (clampToPremul) { - half alpha = saturate(sk_InColor.a); - sk_OutColor = half4(clamp(sk_InColor.rgb, 0, alpha), alpha); + half alpha = saturate(inputColor.a); + sk_OutColor = half4(clamp(inputColor.rgb, 0, alpha), alpha); } else { - sk_OutColor = saturate(sk_InColor); + sk_OutColor = saturate(inputColor); } } @class { - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { + SkPMColor4f input = this->numChildProcessors() + ? ConstantOutputForConstantInput(this->childProcessor(0), inColor) + : inColor; float clampedAlpha = SkTPin(input.fA, 0.f, 1.f); float clampVal = clampToPremul ? clampedAlpha : 1.f; return {SkTPin(input.fR, 0.f, clampVal), @@ -33,5 +39,5 @@ void main() { } @test(d) { - return GrClampFragmentProcessor::Make(d->fRandom->nextBool()); + return GrClampFragmentProcessor::Make(/*inputFP=*/nullptr, d->fRandom->nextBool()); } diff --git a/chromium/third_party/skia/src/gpu/effects/GrColorMatrixFragmentProcessor.fp b/chromium/third_party/skia/src/gpu/effects/GrColorMatrixFragmentProcessor.fp index ee73b89f035..5e07a148595 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrColorMatrixFragmentProcessor.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrColorMatrixFragmentProcessor.fp @@ -5,6 +5,7 @@ * found in the LICENSE file. */ +in fragmentProcessor? inputFP; layout(ctype=SkM44, tracked) in uniform half4x4 m; layout(ctype=SkV4, tracked) in uniform half4 v; layout(key) in bool unpremulInput; @@ -12,16 +13,14 @@ layout(key) in bool clampRGBOutput; layout(key) in bool premulOutput; @optimizationFlags { + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & kConstantOutputForConstantInput_OptimizationFlag } void main() { - half4 inputColor = sk_InColor; + half4 inputColor = sample(inputFP, sk_InColor); @if (unpremulInput) { - // The max() is to guard against 0 / 0 during unpremul when the incoming color is - // transparent black. - half nonZeroAlpha = max(inputColor.a, 0.0001); - inputColor = half4(inputColor.rgb / nonZeroAlpha, inputColor.a); + inputColor = unpremul(inputColor); } sk_OutColor = m * inputColor + v; @if (clampRGBOutput) { @@ -35,7 +34,10 @@ void main() { } @class { - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { + SkPMColor4f input = this->numChildProcessors() + ? ConstantOutputForConstantInput(this->childProcessor(0), inColor) + : inColor; SkColor4f color; if (unpremulInput) { color = input.unpremul(); @@ -62,7 +64,9 @@ void main() { } @make { - static std::unique_ptr<GrFragmentProcessor> Make(const float matrix[20], bool unpremulInput, bool clampRGBOutput, bool premulOutput) { + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + const float matrix[20], bool unpremulInput, + bool clampRGBOutput, bool premulOutput) { SkM44 m44( matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3], matrix[ 5], matrix[ 6], matrix[ 7], matrix[ 8], @@ -70,7 +74,8 @@ void main() { matrix[15], matrix[16], matrix[17], matrix[18] ); SkV4 v4 = {matrix[4], matrix[9], matrix[14], matrix[19]}; - return std::unique_ptr<GrFragmentProcessor>(new GrColorMatrixFragmentProcessor(m44, v4, unpremulInput, clampRGBOutput, premulOutput)); + return std::unique_ptr<GrFragmentProcessor>(new GrColorMatrixFragmentProcessor( + std::move(inputFP), m44, v4, unpremulInput, clampRGBOutput, premulOutput)); } } @@ -82,5 +87,5 @@ void main() { bool unpremul = d->fRandom->nextBool(); bool clampRGB = d->fRandom->nextBool(); bool premul = d->fRandom->nextBool(); - return Make(m, unpremul, clampRGB, premul); + return Make(/*inputFP=*/nullptr, m, unpremul, clampRGB, premul); } diff --git a/chromium/third_party/skia/src/gpu/effects/GrConfigConversionEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrConfigConversionEffect.fp index 6e08ad3daea..c66f283801b 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrConfigConversionEffect.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrConfigConversionEffect.fp @@ -8,7 +8,6 @@ @header { #include "include/gpu/GrContext.h" #include "src/gpu/GrBitmapTextureMaker.h" - #include "src/gpu/GrClip.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrImageInfo.h" #include "src/gpu/GrRenderTargetContext.h" @@ -84,8 +83,7 @@ paint1.addColorFragmentProcessor(pmToUPM->clone()); paint1.setPorterDuffXPFactory(SkBlendMode::kSrc); - readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect, - kRect); + readRTC->fillRectToRect(nullptr, std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect, kRect); if (!readRTC->readPixels(ii, firstRead, 0, {0, 0})) { return false; } @@ -99,16 +97,14 @@ paint2.addColorFragmentProcessor(std::move(upmToPM)); paint2.setPorterDuffXPFactory(SkBlendMode::kSrc); - tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect, - kRect); + tempRTC->fillRectToRect(nullptr, std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect, kRect); paint3.addColorFragmentProcessor(GrTextureEffect::Make(tempRTC->readSurfaceView(), kPremul_SkAlphaType)); paint3.addColorFragmentProcessor(std::move(pmToUPM)); paint3.setPorterDuffXPFactory(SkBlendMode::kSrc); - readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect, - kRect); + readRTC->fillRectToRect(nullptr, std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect, kRect); if (!readRTC->readPixels(ii, secondRead, 0, {0, 0})) { return false; diff --git a/chromium/third_party/skia/src/gpu/effects/GrConstColorProcessor.fp b/chromium/third_party/skia/src/gpu/effects/GrConstColorProcessor.fp index 18cc91a4b12..950705c4f0a 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrConstColorProcessor.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrConstColorProcessor.fp @@ -13,51 +13,60 @@ enum class InputMode { kLast = kModulateA }; +in fragmentProcessor? inputFP; layout(ctype=SkPMColor4f, tracked) in uniform half4 color; layout(key) in InputMode mode; @optimizationFlags { - OptFlags(color, mode) + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & + (kConstantOutputForConstantInput_OptimizationFlag | + ((mode != InputMode::kIgnore) ? kCompatibleWithCoverageAsAlpha_OptimizationFlag + : kNone_OptimizationFlags) | + ((color.isOpaque()) ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags)) } void main() { @switch (mode) { - case InputMode::kIgnore: + case InputMode::kIgnore: { sk_OutColor = color; break; - case InputMode::kModulateRGBA: - sk_OutColor = sk_InColor * color; + } + case InputMode::kModulateRGBA: { + half4 inputColor = sample(inputFP, sk_InColor); + sk_OutColor = inputColor * color; break; - case InputMode::kModulateA: - sk_OutColor = sk_InColor.a * color; + } + case InputMode::kModulateA: { + half inputAlpha = sample(inputFP, sk_InColor).a; + sk_OutColor = inputAlpha * color; break; + } } } @class { static const int kInputModeCnt = (int) InputMode::kLast + 1; - static OptimizationFlags OptFlags(const SkPMColor4f& color, InputMode mode) { - OptimizationFlags flags = kConstantOutputForConstantInput_OptimizationFlag; - if (mode != InputMode::kIgnore) { - flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag; - } - if (color.isOpaque()) { - flags |= kPreservesOpaqueInput_OptimizationFlag; - } - return flags; - } - - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { switch (mode) { - case InputMode::kIgnore: + case InputMode::kIgnore: { return color; - case InputMode::kModulateA: + } + case InputMode::kModulateA: { + SkPMColor4f input = this->numChildProcessors() + ? ConstantOutputForConstantInput(this->childProcessor(inputFP_index), inColor) + : inColor; return color * input.fA; - case InputMode::kModulateRGBA: + } + case InputMode::kModulateRGBA: { + SkPMColor4f input = this->numChildProcessors() + ? ConstantOutputForConstantInput(this->childProcessor(inputFP_index), inColor) + : inColor; return color * input; + } } - SK_ABORT("Unexpected mode"); + SkUNREACHABLE; } } @@ -82,5 +91,5 @@ void main() { break; } InputMode mode = static_cast<InputMode>(d->fRandom->nextULessThan(kInputModeCnt)); - return GrConstColorProcessor::Make(color, mode); + return GrConstColorProcessor::Make(/*inputFP=*/nullptr, color, mode); } diff --git a/chromium/third_party/skia/src/gpu/effects/GrConvexPolyEffect.cpp b/chromium/third_party/skia/src/gpu/effects/GrConvexPolyEffect.cpp index 82de90ec6db..70f2fe443f2 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrConvexPolyEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrConvexPolyEffect.cpp @@ -66,7 +66,12 @@ void GrGLConvexPolyEffect::emitCode(EmitArgs& args) { if (GrProcessorEdgeTypeIsInverseFill(cpe.getEdgeType())) { fragBuilder->codeAppend("\talpha = 1.0 - alpha;\n"); } - fragBuilder->codeAppendf("\t%s = %s * alpha;\n", args.fOutputColor, args.fInputColor); + + SkString inputSample = cpe.hasInputFP() + ? this->invokeChild(/*childIndex=*/0, args.fInputColor, args) + : SkString(args.fInputColor); + + fragBuilder->codeAppendf("\t%s = %s * alpha;\n", args.fOutputColor, inputSample.c_str()); } void GrGLConvexPolyEffect::onSetData(const GrGLSLProgramDataManager& pdman, @@ -89,14 +94,10 @@ void GrGLConvexPolyEffect::GenKey(const GrProcessor& processor, const GrShaderCa ////////////////////////////////////////////////////////////////////////////// -std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(GrClipEdgeType type, - const SkPath& path) { - if (GrClipEdgeType::kHairlineAA == type) { - return nullptr; - } - if (path.getSegmentMasks() != SkPath::kLine_SegmentMask || - !path.isConvex()) { - return nullptr; +GrFPResult GrConvexPolyEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType type, const SkPath& path) { + if (path.getSegmentMasks() != SkPath::kLine_SegmentMask || !path.isConvex()) { + return GrFPFailure(std::move(inputFP)); } SkPathPriv::FirstDirection dir; @@ -105,15 +106,17 @@ std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(GrClipEdgeType typ // skip the draw or omit the clip element. if (!SkPathPriv::CheapComputeFirstDirection(path, &dir)) { if (GrProcessorEdgeTypeIsInverseFill(type)) { - return GrConstColorProcessor::Make(SK_PMColor4fWHITE, - GrConstColorProcessor::InputMode::kModulateRGBA); + return GrFPSuccess( + GrConstColorProcessor::Make(std::move(inputFP), SK_PMColor4fWHITE, + GrConstColorProcessor::InputMode::kModulateRGBA)); } // This could use kIgnore instead of kModulateRGBA but it would trigger a debug print // about a coverage processor not being compatible with the alpha-as-coverage optimization. // We don't really care about this unlikely case so we just use kModulateRGBA to suppress // the print. - return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT, - GrConstColorProcessor::InputMode::kModulateRGBA); + return GrFPSuccess( + GrConstColorProcessor::Make(std::move(inputFP), SK_PMColor4fTRANSPARENT, + GrConstColorProcessor::InputMode::kModulateRGBA)); } SkScalar edges[3 * kMaxEdges]; @@ -130,11 +133,12 @@ std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(GrClipEdgeType typ switch (verb) { case SkPath::kMove_Verb: SkASSERT(n == 0); + break; case SkPath::kClose_Verb: break; case SkPath::kLine_Verb: { if (n >= kMaxEdges) { - return nullptr; + return GrFPFailure(std::move(inputFP)); } if (pts[0] != pts[1]) { SkVector v = pts[1] - pts[0]; @@ -152,22 +156,20 @@ std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(GrClipEdgeType typ break; } default: - return nullptr; + return GrFPFailure(std::move(inputFP)); } } if (path.isInverseFillType()) { type = GrInvertProcessorEdgeType(type); } - return Make(type, n, edges); + return GrConvexPolyEffect::Make(std::move(inputFP), type, n, edges); } -std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::Make(GrClipEdgeType edgeType, - const SkRect& rect) { - if (GrClipEdgeType::kHairlineAA == edgeType){ - return nullptr; - } - return GrAARectEffect::Make(edgeType, rect); +GrFPResult GrConvexPolyEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, const SkRect& rect) { + // TODO: Replace calls to this method with calling GrAARectEffect::Make directly + return GrFPSuccess(GrAARectEffect::Make(std::move(inputFP), edgeType, rect)); } GrConvexPolyEffect::~GrConvexPolyEffect() {} @@ -181,7 +183,8 @@ GrGLSLFragmentProcessor* GrConvexPolyEffect::onCreateGLSLInstance() const { return new GrGLConvexPolyEffect; } -GrConvexPolyEffect::GrConvexPolyEffect(GrClipEdgeType edgeType, int n, const SkScalar edges[]) +GrConvexPolyEffect::GrConvexPolyEffect(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, int n, const SkScalar edges[]) : INHERITED(kGrConvexPolyEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag) , fEdgeType(edgeType) , fEdgeCount(n) { @@ -193,12 +196,17 @@ GrConvexPolyEffect::GrConvexPolyEffect(GrClipEdgeType edgeType, int n, const SkS for (int i = 0; i < n; ++i) { fEdges[3 * i + 2] += SK_ScalarHalf; } + + if (inputFP != nullptr) { + this->registerChild(std::move(inputFP)); + } } GrConvexPolyEffect::GrConvexPolyEffect(const GrConvexPolyEffect& that) : INHERITED(kGrConvexPolyEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag) , fEdgeType(that.fEdgeType) , fEdgeCount(that.fEdgeCount) { + this->cloneAndRegisterAllChildProcessors(that); memcpy(fEdges, that.fEdges, 3 * that.fEdgeCount * sizeof(SkScalar)); } @@ -229,7 +237,11 @@ std::unique_ptr<GrFragmentProcessor> GrConvexPolyEffect::TestCreate(GrProcessorT do { GrClipEdgeType edgeType = static_cast<GrClipEdgeType>( d->fRandom->nextULessThan(kGrClipEdgeTypeCnt)); - fp = GrConvexPolyEffect::Make(edgeType, count, edges); + auto [success, convexPolyFP] = GrConvexPolyEffect::Make(/*inputFP=*/nullptr, edgeType, + count, edges); + if (success) { + fp = std::move(convexPolyFP); + } } while (nullptr == fp); return fp; } diff --git a/chromium/third_party/skia/src/gpu/effects/GrConvexPolyEffect.h b/chromium/third_party/skia/src/gpu/effects/GrConvexPolyEffect.h index 2bb33736f81..36fbc73f0e0 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrConvexPolyEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/GrConvexPolyEffect.h @@ -23,9 +23,7 @@ class SkPath; */ class GrConvexPolyEffect : public GrFragmentProcessor { public: - enum { - kMaxEdges = 8, - }; + static constexpr int kMaxEdges = 8; /** * edges is a set of n edge equations where n is limited to kMaxEdges. It contains 3*n values. @@ -38,24 +36,26 @@ public: * have to modify the effect/shaderbuilder interface to make it possible (e.g. give access * to the view matrix or untransformed positions in the fragment shader). */ - static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, int n, - const SkScalar edges[]) { - if (n <= 0 || n > kMaxEdges || GrClipEdgeType::kHairlineAA == edgeType) { - return nullptr; + static GrFPResult Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, int n, const SkScalar edges[]) { + if (n <= 0 || n > kMaxEdges) { + return GrFPFailure(std::move(inputFP)); } - return std::unique_ptr<GrFragmentProcessor>(new GrConvexPolyEffect(edgeType, n, edges)); + + return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>( + new GrConvexPolyEffect(std::move(inputFP), edgeType, n, edges))); } /** * Creates an effect that clips against the path. If the path is not a convex polygon, is - * inverse filled, or has too many edges, this will return nullptr. + * inverse filled, or has too many edges, creation will fail. */ - static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkPath&); + static GrFPResult Make(std::unique_ptr<GrFragmentProcessor>, GrClipEdgeType, const SkPath&); /** * Creates an effect that fills inside the rect with AA edges.. */ - static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRect&); + static GrFPResult Make(std::unique_ptr<GrFragmentProcessor>, GrClipEdgeType, const SkRect&); ~GrConvexPolyEffect() override; @@ -69,8 +69,12 @@ public: const SkScalar* getEdges() const { return fEdges; } + bool hasInputFP() const { return numChildProcessors() > 0; } + private: - GrConvexPolyEffect(GrClipEdgeType edgeType, int n, const SkScalar edges[]); + GrConvexPolyEffect(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, + int n, const SkScalar edges[]); GrConvexPolyEffect(const GrConvexPolyEffect&); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; diff --git a/chromium/third_party/skia/src/gpu/effects/GrDeviceSpaceEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrDeviceSpaceEffect.fp index 879c7c4d7c3..8dfb2c4dbda 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrDeviceSpaceEffect.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrDeviceSpaceEffect.fp @@ -7,8 +7,18 @@ in fragmentProcessor fp; +in uniform float3x3 matrix; + void main() { - sk_OutColor = sample(fp, sk_InColor, sk_FragCoord.xy); + float3 p = matrix * (sk_FragCoord.xy1); + sk_OutColor = sample(fp, sk_InColor, p.xy / p.z); +} + +@make{ + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp, + const SkMatrix& matrix = SkMatrix::I()) { + return std::unique_ptr<GrFragmentProcessor>(new GrDeviceSpaceEffect(std::move(fp), matrix)); + } } @test(d) { diff --git a/chromium/third_party/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp b/chromium/third_party/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp index 3bf74e11fba..19c75f332f3 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrDistanceFieldGeoProc.cpp @@ -57,14 +57,8 @@ public: // Setup position gpArgs->fPositionVar = dfTexEffect.inPosition().asShaderVar(); - - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - dfTexEffect.inPosition().asShaderVar(), - dfTexEffect.localMatrix(), - args.fFPCoordTransformHandler); + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, gpArgs->fPositionVar, + dfTexEffect.localMatrix(), &fLocalMatrixUniform); // add varyings GrGLSLVarying uv(kFloat2_GrSLType); @@ -185,7 +179,8 @@ public: 1.0f / atlasDimensions.fHeight); fAtlasDimensions = atlasDimensions; } - this->setTransformDataHelper(dfa8gp.localMatrix(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); + this->setTransform(pdman, fLocalMatrixUniform, dfa8gp.localMatrix(), &fLocalMatrix); } static inline void GenKey(const GrGeometryProcessor& gp, @@ -193,6 +188,7 @@ public: GrProcessorKeyBuilder* b) { const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldA8TextGeoProc>(); uint32_t key = dfTexEffect.getFlags(); + key |= ComputeMatrixKey(dfTexEffect.localMatrix()) << 16; b->add32(key); b->add32(dfTexEffect.numTextureSamplers()); } @@ -202,9 +198,12 @@ private: float fDistanceAdjust = -1.f; UniformHandle fDistanceAdjustUni; #endif - SkISize fAtlasDimensions = {0, 0}; + SkISize fAtlasDimensions = {0, 0}; UniformHandle fAtlasDimensionsInvUniform; + SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix(); + UniformHandle fLocalMatrixUniform; + typedef GrGLSLGeometryProcessor INHERITED; }; @@ -354,31 +353,20 @@ public: varyingHandler->addPassThroughAttribute(dfPathEffect.inColor(), args.fOutputColor); if (dfPathEffect.matrix().hasPerspective()) { - // Setup position + // Setup position (output position is transformed, local coords are pass through) this->writeOutputPosition(vertBuilder, uniformHandler, gpArgs, dfPathEffect.inPosition().name(), dfPathEffect.matrix(), &fMatrixUniform); - - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - dfPathEffect.inPosition().asShaderVar(), - args.fFPCoordTransformHandler); + gpArgs->fLocalCoordVar = dfPathEffect.inPosition().asShaderVar(); } else { - // Setup position + // Setup position (output position is pass through, local coords are transformed) this->writeOutputPosition(vertBuilder, gpArgs, dfPathEffect.inPosition().name()); - - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - dfPathEffect.inPosition().asShaderVar(), - dfPathEffect.matrix(), - args.fFPCoordTransformHandler); + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, + dfPathEffect.inPosition().asShaderVar(), dfPathEffect.matrix(), + &fMatrixUniform); } // Use highp to work around aliasing issues @@ -463,10 +451,9 @@ public: const CoordTransformRange& transformRange) override { const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>(); - if (dfpgp.matrix().hasPerspective() && !SkMatrixPriv::CheapEqual(fMatrix, dfpgp.matrix())) { - fMatrix = dfpgp.matrix(); - pdman.setSkMatrix(fMatrixUniform, fMatrix); - } + // We always set the matrix uniform; it's either used to transform from local to device + // for the output position, or from device to local for the local coord variable. + this->setTransform(pdman, fMatrixUniform, dfpgp.matrix(), &fMatrix); const SkISize& atlasDimensions = dfpgp.atlasDimensions(); SkASSERT(SkIsPow2(atlasDimensions.fWidth) && SkIsPow2(atlasDimensions.fHeight)); @@ -477,11 +464,7 @@ public: fAtlasDimensions = atlasDimensions; } - if (dfpgp.matrix().hasPerspective()) { - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); - } else { - this->setTransformDataHelper(dfpgp.matrix(), pdman, transformRange); - } + this->setTransformDataHelper(pdman, transformRange); } static inline void GenKey(const GrGeometryProcessor& gp, @@ -490,7 +473,7 @@ public: const GrDistanceFieldPathGeoProc& dfTexEffect = gp.cast<GrDistanceFieldPathGeoProc>(); uint32_t key = dfTexEffect.getFlags(); - key |= ComputePosKey(dfTexEffect.matrix()) << 16; + key |= ComputeMatrixKey(dfTexEffect.matrix()) << 16; b->add32(key); b->add32(dfTexEffect.matrix().hasPerspective()); b->add32(dfTexEffect.numTextureSamplers()); @@ -605,7 +588,9 @@ GrGeometryProcessor* GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTestData* class GrGLDistanceFieldLCDTextGeoProc : public GrGLSLGeometryProcessor { public: - GrGLDistanceFieldLCDTextGeoProc() : fAtlasDimensions({0, 0}) { + GrGLDistanceFieldLCDTextGeoProc() + : fAtlasDimensions({0, 0}) + , fLocalMatrix(SkMatrix::InvalidMatrix()) { fDistanceAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(1.0f, 1.0f, 1.0f); } @@ -634,14 +619,9 @@ public: // Setup position gpArgs->fPositionVar = dfTexEffect.inPosition().asShaderVar(); - - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - dfTexEffect.inPosition().asShaderVar(), - dfTexEffect.localMatrix(), - args.fFPCoordTransformHandler); + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, + dfTexEffect.inPosition().asShaderVar(), dfTexEffect.localMatrix(), + &fLocalMatrixUniform); // set up varyings GrGLSLVarying uv(kFloat2_GrSLType); @@ -801,7 +781,8 @@ public: 1.0f / atlasDimensions.fHeight); fAtlasDimensions = atlasDimensions; } - this->setTransformDataHelper(dflcd.localMatrix(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); + this->setTransform(pdman, fLocalMatrixUniform, dflcd.localMatrix(), &fLocalMatrix); } static inline void GenKey(const GrGeometryProcessor& gp, @@ -809,7 +790,8 @@ public: GrProcessorKeyBuilder* b) { const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldLCDTextGeoProc>(); - uint32_t key = dfTexEffect.getFlags(); + uint32_t key = (dfTexEffect.getFlags() << 16) | + ComputeMatrixKey(dfTexEffect.localMatrix()); b->add32(key); b->add32(dfTexEffect.numTextureSamplers()); } @@ -821,6 +803,9 @@ private: SkISize fAtlasDimensions; UniformHandle fAtlasDimensionsInvUniform; + SkMatrix fLocalMatrix; + UniformHandle fLocalMatrixUniform; + typedef GrGLSLGeometryProcessor INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/effects/GrEllipseEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrEllipseEffect.fp index 8e8c766d0f2..918dcbece1d 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrEllipseEffect.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrEllipseEffect.fp @@ -9,6 +9,7 @@ #include "src/gpu/GrShaderCaps.h" } +in fragmentProcessor? inputFP; layout(key) in GrClipEdgeType edgeType; in float2 center; in float2 radii; @@ -23,25 +24,29 @@ bool medPrecision = !sk_Caps.floatIs32Bits; layout(when=medPrecision) uniform float2 scale; @make { - static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkPoint center, - SkPoint radii, const GrShaderCaps& caps) { + static GrFPResult Make(std::unique_ptr<GrFragmentProcessor> inputFP, GrClipEdgeType edgeType, + SkPoint center, SkPoint radii, const GrShaderCaps& caps) { // Small radii produce bad results on devices without full float. if (!caps.floatIs32Bits() && (radii.fX < 0.5f || radii.fY < 0.5f)) { - return nullptr; + return GrFPFailure(std::move(inputFP)); } // Very narrow ellipses produce bad results on devices without full float if (!caps.floatIs32Bits() && (radii.fX > 255*radii.fY || radii.fY > 255*radii.fX)) { - return nullptr; + return GrFPFailure(std::move(inputFP)); } // Very large ellipses produce bad results on devices without full float if (!caps.floatIs32Bits() && (radii.fX > 16384 || radii.fY > 16384)) { - return nullptr; + return GrFPFailure(std::move(inputFP)); } - return std::unique_ptr<GrFragmentProcessor>(new GrEllipseEffect(edgeType, center, radii)); + return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>( + new GrEllipseEffect(std::move(inputFP), edgeType, center, radii))); } } -@optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag } +@optimizationFlags { + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag +} @setData(pdman) { if (radii != prevRadii || center != prevCenter) { @@ -114,7 +119,8 @@ void main() { // hairline not supported discard; } - sk_OutColor = sk_InColor * alpha; + half4 inputColor = sample(inputFP, sk_InColor); + sk_OutColor = inputColor * alpha; } @test(testData) { @@ -123,10 +129,13 @@ void main() { center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f); SkScalar rx = testData->fRandom->nextRangeF(0.f, 1000.f); SkScalar ry = testData->fRandom->nextRangeF(0.f, 1000.f); - GrClipEdgeType et; + bool success; + std::unique_ptr<GrFragmentProcessor> fp; do { - et = (GrClipEdgeType) testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt); - } while (GrClipEdgeType::kHairlineAA == et); - return GrEllipseEffect::Make(et, center, SkPoint::Make(rx, ry), - *testData->caps()->shaderCaps()); + GrClipEdgeType et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt); + std::tie(success, fp) = GrEllipseEffect::Make(/*inputFP=*/nullptr, et, center, + SkPoint::Make(rx, ry), + *testData->caps()->shaderCaps()); + } while (!success); + return fp; } diff --git a/chromium/third_party/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp b/chromium/third_party/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp index da7d950609a..3c8db3455a8 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.cpp @@ -140,29 +140,23 @@ std::unique_ptr<GrFragmentProcessor> GrGaussianConvolutionFragmentProcessor::Mak int halfWidth, float gaussianSigma, GrSamplerState::WrapMode wm, - const int bounds[2], + const SkIRect& subset, + const SkIRect* pixelDomain, const GrCaps& caps) { std::unique_ptr<GrFragmentProcessor> child; - GrSamplerState sampler; - switch (dir) { - case Direction::kX: sampler.setWrapModeX(wm); break; - case Direction::kY: sampler.setWrapModeY(wm); break; - } - if (bounds) { - SkASSERT(bounds[0] < bounds[1]); - SkRect subset; + GrSamplerState sampler(wm, GrSamplerState::Filter::kNearest); + if (pixelDomain) { + // Inset because we expect to be invoked at pixel centers. + SkRect domain = SkRect::Make(*pixelDomain).makeInset(0.5, 0.5f); switch (dir) { - case Direction::kX: - subset = SkRect::MakeLTRB(bounds[0], 0, bounds[1], view.height()); - break; - case Direction::kY: - subset = SkRect::MakeLTRB(0, bounds[0], view.width(), bounds[1]); - break; + case Direction::kX: domain.outset(halfWidth, 0); break; + case Direction::kY: domain.outset(0, halfWidth); break; } child = GrTextureEffect::MakeSubset(std::move(view), alphaType, SkMatrix::I(), sampler, - subset, caps); + SkRect::Make(subset), domain, caps); } else { - child = GrTextureEffect::Make(std::move(view), alphaType, SkMatrix::I(), sampler, caps); + child = GrTextureEffect::MakeSubset(std::move(view), alphaType, SkMatrix::I(), sampler, + SkRect::Make(subset), caps); } return std::unique_ptr<GrFragmentProcessor>(new GrGaussianConvolutionFragmentProcessor( std::move(child), dir, halfWidth, gaussianSigma)); @@ -177,8 +171,7 @@ GrGaussianConvolutionFragmentProcessor::GrGaussianConvolutionFragmentProcessor( ProcessorOptimizationFlags(child.get())) , fRadius(radius) , fDirection(direction) { - child->setSampledWithExplicitCoords(); - this->registerChildProcessor(std::move(child)); + this->registerExplicitlySampledChild(std::move(child)); SkASSERT(radius <= kMaxKernelRadius); fill_in_1D_gaussian_kernel(fKernel, gaussianSigma, fRadius); this->addCoordTransform(&fCoordTransform); @@ -189,9 +182,7 @@ GrGaussianConvolutionFragmentProcessor::GrGaussianConvolutionFragmentProcessor( : INHERITED(kGrGaussianConvolutionFragmentProcessor_ClassID, that.optimizationFlags()) , fRadius(that.fRadius) , fDirection(that.fDirection) { - auto child = that.childProcessor(0).clone(); - child->setSampledWithExplicitCoords(); - this->registerChildProcessor(std::move(child)); + this->cloneAndRegisterAllChildProcessors(that); memcpy(fKernel, that.fKernel, radius_to_width(fRadius) * sizeof(float)); this->addCoordTransform(&fCoordTransform); } @@ -220,27 +211,33 @@ std::unique_ptr<GrFragmentProcessor> GrGaussianConvolutionFragmentProcessor::Tes GrProcessorTestData* d) { auto [view, ct, at] = d->randomView(); - Direction dir; - int bounds[2]; - do { - if (d->fRandom->nextBool()) { - dir = Direction::kX; - bounds[0] = d->fRandom->nextRangeU(0, view.width() - 1); - bounds[1] = d->fRandom->nextRangeU(0, view.width() - 1); - } else { - dir = Direction::kY; - bounds[0] = d->fRandom->nextRangeU(0, view.height() - 1); - bounds[1] = d->fRandom->nextRangeU(0, view.height() - 1); - } - } while (bounds[0] == bounds[1]); - std::sort(bounds, bounds + 2); + Direction dir = d->fRandom->nextBool() ? Direction::kY : Direction::kX; + SkIRect subset{ + static_cast<int>(d->fRandom->nextRangeU(0, view.width() - 1)), + static_cast<int>(d->fRandom->nextRangeU(0, view.height() - 1)), + static_cast<int>(d->fRandom->nextRangeU(0, view.width() - 1)), + static_cast<int>(d->fRandom->nextRangeU(0, view.height() - 1)), + }; + subset.sort(); auto wm = static_cast<GrSamplerState::WrapMode>( d->fRandom->nextULessThan(GrSamplerState::kWrapModeCount)); int radius = d->fRandom->nextRangeU(1, kMaxKernelRadius); float sigma = radius / 3.f; + SkIRect temp; + SkIRect* domain = nullptr; + if (d->fRandom->nextBool()) { + temp = { + static_cast<int>(d->fRandom->nextRangeU(0, view.width() - 1)), + static_cast<int>(d->fRandom->nextRangeU(0, view.height() - 1)), + static_cast<int>(d->fRandom->nextRangeU(0, view.width() - 1)), + static_cast<int>(d->fRandom->nextRangeU(0, view.height() - 1)), + }; + temp.sort(); + domain = &temp; + } return GrGaussianConvolutionFragmentProcessor::Make(std::move(view), at, dir, radius, sigma, wm, - bounds, *d->caps()); + subset, domain, *d->caps()); } #endif diff --git a/chromium/third_party/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h b/chromium/third_party/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h index 70fa89bbdae..61f6e4e3231 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h +++ b/chromium/third_party/skia/src/gpu/effects/GrGaussianConvolutionFragmentProcessor.h @@ -22,17 +22,22 @@ public: /** * Convolve with a Gaussian kernel. Bounds limits the coords sampled by the effect along the - * axis indicated by Direction. The WrapMode is applied to the bounds interval. If bounds is - * nullptr then the full proxy width/height is used. + * axis indicated by Direction. The WrapMode is applied to the subset. If present, the + * pixelDomain indicates the domain of pixels that this effect will be called with. It should + * not account for outsetting due to the filter radius, this effect will handle that. It is + * assumed that the effect is only invoked at pixel centers within the pixelDomain, the + * effect will optimize for that, and may produce incorrect results if it is not the case. If + * pixelDomain is null then the effect will work correctly with any sample coordinates. */ - static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView view, - SkAlphaType alphaType, - Direction dir, + static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView, + SkAlphaType, + Direction, int halfWidth, float gaussianSigma, GrSamplerState::WrapMode, - const int bounds[2], - const GrCaps& caps); + const SkIRect& subset, + const SkIRect* pixelDomain, + const GrCaps&); const char* name() const override { return "GaussianConvolution"; } diff --git a/chromium/third_party/skia/src/gpu/effects/GrHSLToRGBFilterEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrHSLToRGBFilterEffect.fp index 02125f8e709..029f7b2adf7 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrHSLToRGBFilterEffect.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrHSLToRGBFilterEffect.fp @@ -13,19 +13,23 @@ // [2] http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl // [3] http://www.chilliant.com/rgb2hsv.html +in fragmentProcessor? inputFP; + void main() { - half3 hsl = sk_InColor.rgb; + half4 inputColor = sample(inputFP, sk_InColor); + half3 hsl = inputColor.rgb; half C = (1 - abs(2 * hsl.z - 1)) * hsl.y; half3 p = hsl.xxx + half3(0, 2/3.0, 1/3.0); half3 q = saturate(abs(fract(p) * 6 - 3) - 1); half3 rgb = (q - 0.5) * C + hsl.z; - sk_OutColor = saturate(half4(rgb, sk_InColor.a)); + sk_OutColor = saturate(half4(rgb, inputColor.a)); sk_OutColor.rgb *= sk_OutColor.a; } @optimizationFlags { + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & (kConstantOutputForConstantInput_OptimizationFlag | kPreservesOpaqueInput_OptimizationFlag) } @@ -33,7 +37,10 @@ void main() { #include "include/private/SkColorData.h" #include "include/private/SkNx.h" - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& c) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { + SkPMColor4f c = this->numChildProcessors() + ? ConstantOutputForConstantInput(this->childProcessor(0), inColor) + : inColor; const auto H = c[0], S = c[1], L = c[2], diff --git a/chromium/third_party/skia/src/gpu/effects/GrLumaColorFilterEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrLumaColorFilterEffect.fp index 1548b26e0bf..67188459df8 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrLumaColorFilterEffect.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrLumaColorFilterEffect.fp @@ -5,14 +5,20 @@ * found in the LICENSE file. */ +in fragmentProcessor? inputFP; + @optimizationFlags { - kConstantOutputForConstantInput_OptimizationFlag + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & + kConstantOutputForConstantInput_OptimizationFlag } @class { #include "include/private/SkColorData.h" - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { + SkPMColor4f input = this->numChildProcessors() + ? ConstantOutputForConstantInput(this->childProcessor(inputFP_index), inColor) + : inColor; float luma = SK_ITU_BT709_LUM_COEFF_R * input.fR + SK_ITU_BT709_LUM_COEFF_G * input.fG + SK_ITU_BT709_LUM_COEFF_B * input.fB; @@ -21,7 +27,8 @@ } void main() { + half4 inputColor = sample(inputFP, sk_InColor); const half3 SK_ITU_BT709_LUM_COEFF = half3(0.2126, 0.7152, 0.0722); - half luma = saturate(dot(SK_ITU_BT709_LUM_COEFF, sk_InColor.rgb)); + half luma = saturate(dot(SK_ITU_BT709_LUM_COEFF, inputColor.rgb)); sk_OutColor = half4(0, 0, 0, luma); } diff --git a/chromium/third_party/skia/src/gpu/effects/GrMagnifierEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrMagnifierEffect.fp index 582fc4bb298..b4af4c4804b 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrMagnifierEffect.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrMagnifierEffect.fp @@ -5,7 +5,7 @@ * found in the LICENSE file. */ -in uniform sampler2D src; +in fragmentProcessor src; layout(ctype=SkIRect) in int4 bounds; uniform float4 boundsUniform; layout(ctype=SkRect) in float4 srcRect; @@ -16,9 +16,7 @@ in uniform float yInvInset; uniform half2 offset; -@coordTransform(src) { - SkMatrix::I() -} +@coordTransform { SkMatrix::I() } void main() { float2 coord = sk_TransformedCoords2D[0]; @@ -42,36 +40,11 @@ void main() { } @setData(pdman) { - SkScalar invW = 1.0f / src.width(); - SkScalar invH = 1.0f / src.height(); - - { - SkScalar y = srcRect.y() * invH; - if (srcView.origin() != kTopLeft_GrSurfaceOrigin) { - y = 1.0f - (srcRect.height() / bounds.height()) - y; - } - - pdman.set2f(offset, srcRect.x() * invW, y); - } - - { - SkScalar y = bounds.y() * invH; - SkScalar hSign = 1.f; - if (srcView.origin() != kTopLeft_GrSurfaceOrigin) { - y = 1.0f - bounds.y() * invH; - hSign = -1.f; - } - - pdman.set4f(boundsUniform, - bounds.x() * invW, - y, - SkIntToScalar(src.width()) / bounds.width(), - hSign * SkIntToScalar(src.height()) / bounds.height()); - } + pdman.set2f(offset, srcRect.x(), srcRect.y()); + pdman.set4f(boundsUniform, bounds.x(), bounds.y(), 1.f/ bounds.width(), 1.f / bounds.height()); } @test(d) { - auto [view, ct, at] = d->randomView(); const int kMaxWidth = 200; const int kMaxHeight = 200; const SkScalar kMaxInset = 20.0f; @@ -82,7 +55,8 @@ void main() { SkIRect bounds = SkIRect::MakeWH(SkIntToScalar(kMaxWidth), SkIntToScalar(kMaxHeight)); SkRect srcRect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); - auto effect = GrMagnifierEffect::Make(std::move(view), + auto src = GrProcessorUnitTest::MakeChildFP(d); + auto effect = GrMagnifierEffect::Make(std::move(src), bounds, srcRect, srcRect.width() / bounds.width(), diff --git a/chromium/third_party/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp b/chromium/third_party/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp index 8de8deefce0..04036d03ded 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrMatrixConvolutionEffect.cpp @@ -42,9 +42,12 @@ private: typedef GrGLSLFragmentProcessor INHERITED; }; -GrMatrixConvolutionEffect::KernelWrapper GrMatrixConvolutionEffect::KernelWrapper::Make( - GrRecordingContext* context, SkISize size, const GrCaps& caps, const SkScalar* values) { - if (nullptr == context || nullptr == values || size.isEmpty()) { +GrMatrixConvolutionEffect::KernelWrapper::MakeResult +GrMatrixConvolutionEffect::KernelWrapper::Make(GrRecordingContext* context, + SkISize size, + const GrCaps& caps, + const SkScalar* values) { + if (!context || !values || size.isEmpty()) { return {}; } const int length = size.area(); @@ -54,10 +57,10 @@ GrMatrixConvolutionEffect::KernelWrapper GrMatrixConvolutionEffect::KernelWrappe for (int i = 0; i < length; i++) { result.fArray[i] = SkScalarToFloat(values[i]); } - return result; + return {result, nullptr}; } - ScalableSampler& scalableSampler = result.fScalableSampler; + BiasAndGain& scalableSampler = result.fBiasAndGain; bool useA16 = context->defaultBackendFormat(kA16_float_SkColorType, GrRenderable::kNo).isValid(); SkScalar min = values[0]; @@ -108,8 +111,7 @@ GrMatrixConvolutionEffect::KernelWrapper GrMatrixConvolutionEffect::KernelWrappe view = {std::move(cachedKernel), kTopLeft_GrSurfaceOrigin, swizzle}; } else { SkBitmap bm; - auto info = SkImageInfo::Make({(int)GrNextPow2(length), 1}, colorType, - kPremul_SkAlphaType, nullptr); + auto info = SkImageInfo::Make({length, 1}, colorType, kPremul_SkAlphaType, nullptr); if (!bm.tryAllocPixels(info)) { return {}; } @@ -131,23 +133,23 @@ GrMatrixConvolutionEffect::KernelWrapper GrMatrixConvolutionEffect::KernelWrappe proxyProvider->assignUniqueKeyToProxy(key, view.asTextureProxy()); } } - scalableSampler.fSampler = { std::move(view) }; - return result; + auto kernelFP = GrTextureEffect::Make(std::move(view), kUnknown_SkAlphaType); + return {result, std::move(kernelFP)}; } bool GrMatrixConvolutionEffect::KernelWrapper::operator==(const KernelWrapper& k) const { if (fSize != k.fSize) { return false; } else if (this->isSampled()) { - return fScalableSampler == k.fScalableSampler; + return fBiasAndGain == k.fBiasAndGain; } else { return std::equal(fArray.begin(), fArray.begin() + fSize.area(), k.fArray.begin()); } } -bool GrMatrixConvolutionEffect::KernelWrapper::ScalableSampler::operator==( - const ScalableSampler& k) const { - return fSampler == k.fSampler && fGain == k.fGain && fBias == k.fBias; +bool GrMatrixConvolutionEffect::KernelWrapper::BiasAndGain::operator==( + const BiasAndGain& k) const { + return fGain == k.fGain && fBias == k.fBias; } // For sampled kernels, emit a for loop that does all the kernel accumulation. @@ -162,7 +164,6 @@ void GrGLMatrixConvolutionEffect::emitKernelBlock(EmitArgs& args, SkIPoint loc) int kernelArea = kernelWidth * kernelHeight; if (mce.kernelIsSampled()) { - fragBuilder->codeAppendf("half2 kernelCoord = half2(0, 0);"); fragBuilder->codeAppendf("for (int i = 0; i < %d; ++i)", (int)kernelArea); } @@ -172,13 +173,11 @@ void GrGLMatrixConvolutionEffect::emitKernelBlock(EmitArgs& args, SkIPoint loc) fragBuilder->codeAppend("half2 sourceOffset;"); if (mce.kernelIsSampled()) { const char* kernelBias = uniformHandler->getUniformCStr(fKernelBiasUni); - fragBuilder->codeAppend("k = "); - fragBuilder->appendTextureLookup(args.fTexSamplers[0], "kernelCoord"); - fragBuilder->codeAppendf(".w + %s;", kernelBias); + SkString kernelCoord = SkStringPrintf("float2(float(i) + 0.5, 0.5)"); + SkString kernelSample = this->invokeChild(1, args, kernelCoord.c_str()); + fragBuilder->codeAppendf("k = %s.w + %s;", kernelSample.c_str(), kernelBias); fragBuilder->codeAppendf("sourceOffset.y = floor(i / %d);", kernelWidth); fragBuilder->codeAppendf("sourceOffset.x = i - sourceOffset.y * %d;", kernelWidth); - float kernelStride = 1.0f / (float)GrNextPow2(kernelArea); - fragBuilder->codeAppendf("kernelCoord.x += %f;", kernelStride); } else { fragBuilder->codeAppendf("sourceOffset = half2(%d, %d);", loc.x(), loc.y()); int offset = loc.y() * kernelWidth + loc.x(); @@ -191,7 +190,7 @@ void GrGLMatrixConvolutionEffect::emitKernelBlock(EmitArgs& args, SkIPoint loc) auto sample = this->invokeChild(0, args, "coord + sourceOffset"); fragBuilder->codeAppendf("half4 c = %s;", sample.c_str()); if (!mce.convolveAlpha()) { - fragBuilder->codeAppend("c.rgb /= max(c.a, 0.0001);"); + fragBuilder->codeAppend("c = unpremul(c);"); fragBuilder->codeAppend("c.rgb = saturate(c.rgb);"); } fragBuilder->codeAppend("sum += c * k;"); @@ -282,7 +281,8 @@ void GrGLMatrixConvolutionEffect::onSetData(const GrGLSLProgramDataManager& pdma } GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(std::unique_ptr<GrFragmentProcessor> child, - KernelWrapper kernel, + const KernelWrapper& kernel, + std::unique_ptr<GrFragmentProcessor> kernelFP, SkScalar gain, SkScalar bias, const SkIPoint& kernelOffset, @@ -290,14 +290,13 @@ GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(std::unique_ptr<GrFragmentP // To advertise either the modulation or opaqueness optimizations we'd have to examine the // parameters. : INHERITED(kGrMatrixConvolutionEffect_ClassID, kNone_OptimizationFlags) - , fKernel(std::move(kernel)) + , fKernel(kernel) , fGain(SkScalarToFloat(gain)) , fBias(SkScalarToFloat(bias) / 255.0f) , fConvolveAlpha(convolveAlpha) { - child->setSampledWithExplicitCoords(); - this->registerChildProcessor(std::move(child)); - if (fKernel.isSampled()) { - this->setTextureSamplerCnt(1); + this->registerExplicitlySampledChild(std::move(child)); + if (kernelFP) { + this->registerExplicitlySampledChild(std::move(kernelFP)); } fKernelOffset = {static_cast<float>(kernelOffset.x()), static_cast<float>(kernelOffset.y())}; @@ -311,12 +310,7 @@ GrMatrixConvolutionEffect::GrMatrixConvolutionEffect(const GrMatrixConvolutionEf , fBias(that.fBias) , fKernelOffset(that.fKernelOffset) , fConvolveAlpha(that.fConvolveAlpha) { - auto child = that.childProcessor(0).clone(); - child->setSampledWithExplicitCoords(); - this->registerChildProcessor(std::move(child)); - if (fKernel.isSampled()) { - this->setTextureSamplerCnt(1); - } + this->cloneAndRegisterAllChildProcessors(that); this->addCoordTransform(&fCoordTransform); } @@ -342,11 +336,6 @@ bool GrMatrixConvolutionEffect::onIsEqual(const GrFragmentProcessor& sBase) cons fConvolveAlpha == s.convolveAlpha(); } -const GrFragmentProcessor::TextureSampler& GrMatrixConvolutionEffect::onTextureSampler( - int index) const { - return IthTextureSampler(index, fKernel.scalableSampler().fSampler); -} - static void fill_in_1D_gaussian_kernel_with_stride(float* kernel, int size, int stride, float twoSigmaSqrd) { SkASSERT(!SkScalarNearlyZero(twoSigmaSqrd, SK_ScalarNearlyZero)); @@ -437,15 +426,16 @@ std::unique_ptr<GrFragmentProcessor> GrMatrixConvolutionEffect::Make(GrRecording GrSamplerState::WrapMode wm, bool convolveAlpha, const GrCaps& caps) { - auto kw = KernelWrapper::Make(context, kernelSize, caps, kernel); - if (!kw.isValid()) { + auto [kernelWrapper, kernelFP] = KernelWrapper::Make(context, kernelSize, caps, kernel); + if (!kernelWrapper.isValid()) { return nullptr; } GrSamplerState sampler(wm, GrSamplerState::Filter::kNearest); auto child = GrTextureEffect::MakeSubset(std::move(srcView), kPremul_SkAlphaType, SkMatrix::I(), sampler, SkRect::Make(srcBounds), caps); - return std::unique_ptr<GrFragmentProcessor>(new GrMatrixConvolutionEffect( - std::move(child), std::move(kw), gain, bias, kernelOffset, convolveAlpha)); + return std::unique_ptr<GrFragmentProcessor>( + new GrMatrixConvolutionEffect(std::move(child), kernelWrapper, std::move(kernelFP), + gain, bias, kernelOffset, convolveAlpha)); } std::unique_ptr<GrFragmentProcessor> GrMatrixConvolutionEffect::MakeGaussian( diff --git a/chromium/third_party/skia/src/gpu/effects/GrMatrixConvolutionEffect.h b/chromium/third_party/skia/src/gpu/effects/GrMatrixConvolutionEffect.h index 4a5627bdec3..e28cb957484 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrMatrixConvolutionEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/GrMatrixConvolutionEffect.h @@ -49,8 +49,8 @@ public: const SkV2 kernelOffset() const { return fKernelOffset; } bool kernelIsSampled() const { return fKernel.isSampled(); } const float *kernel() const { return fKernel.array().data(); } - float kernelSampleGain() const { return fKernel.scalableSampler().fGain; } - float kernelSampleBias() const { return fKernel.scalableSampler().fBias; } + float kernelSampleGain() const { return fKernel.biasAndGain().fGain; } + float kernelSampleBias() const { return fKernel.biasAndGain().fBias; } float gain() const { return fGain; } float bias() const { return fBias; } bool convolveAlpha() const { return fConvolveAlpha; } @@ -67,36 +67,24 @@ private: */ class KernelWrapper { public: - struct ScalableSampler { - TextureSampler fSampler; + struct BiasAndGain { // Only used in A8 mode. Applied before any other math. - float fBias = 0.0f; + float fBias; // Only used in A8 mode. Premultiplied in with user gain to save time. - float fGain = 1.0f; - bool operator==(const ScalableSampler&) const; + float fGain; + bool operator==(const BiasAndGain&) const; }; - static KernelWrapper Make(GrRecordingContext*, SkISize, - const GrCaps&, const float* values); + using MakeResult = std::tuple<KernelWrapper, std::unique_ptr<GrFragmentProcessor>>; + static MakeResult Make(GrRecordingContext*, SkISize, const GrCaps&, const float* values); - KernelWrapper(KernelWrapper&& that) : fSize(that.fSize) { - if (that.isSampled()) { - new (&fScalableSampler) ScalableSampler(std::move(that.fScalableSampler)); - } else { - new (&fArray) std::array<float, kMaxUniformSize>(std::move(that.fArray)); - } - } + KernelWrapper() = default; KernelWrapper(const KernelWrapper& that) : fSize(that.fSize) { if (that.isSampled()) { - new (&fScalableSampler) ScalableSampler(that.fScalableSampler); + fBiasAndGain = that.fBiasAndGain; } else { new (&fArray) std::array<float, kMaxUniformSize>(that.fArray); } } - ~KernelWrapper() { - if (this->isSampled()) { - fScalableSampler.~ScalableSampler(); - } - } bool isValid() const { return !fSize.isEmpty(); } SkISize size() const { return fSize; } @@ -105,29 +93,29 @@ private: SkASSERT(!this->isSampled()); return fArray; } - const ScalableSampler& scalableSampler() const { + const BiasAndGain& biasAndGain() const { SkASSERT(this->isSampled()); - return fScalableSampler; + return fBiasAndGain; } bool operator==(const KernelWrapper&) const; private: - KernelWrapper() : fSize({}) {} KernelWrapper(SkISize size) : fSize(size) { if (this->isSampled()) { - new (&fScalableSampler) ScalableSampler; + fBiasAndGain = {0.f , 1.f}; } } - SkISize fSize; + SkISize fSize = {}; union { std::array<float, kMaxUniformSize> fArray; - ScalableSampler fScalableSampler; + BiasAndGain fBiasAndGain; }; }; GrMatrixConvolutionEffect(std::unique_ptr<GrFragmentProcessor> child, - KernelWrapper kernel, + const KernelWrapper& kernel, + std::unique_ptr<GrFragmentProcessor> kernelFP, SkScalar gain, SkScalar bias, const SkIPoint& kernelOffset, @@ -141,8 +129,6 @@ private: bool onIsEqual(const GrFragmentProcessor&) const override; - const GrFragmentProcessor::TextureSampler& onTextureSampler(int index) const override; - // We really just want the unaltered local coords, but the only way to get that right now is // an identity coord transform. GrCoordTransform fCoordTransform = {}; diff --git a/chromium/third_party/skia/src/gpu/effects/GrMatrixEffect.cpp b/chromium/third_party/skia/src/gpu/effects/GrMatrixEffect.cpp new file mode 100644 index 00000000000..aa5cd3cd888 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/effects/GrMatrixEffect.cpp @@ -0,0 +1,59 @@ +/* + * Copyright 2020 Google LLC + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/gpu/effects/GrMatrixEffect.h" + +#include "src/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 GrGLSLMatrixEffect : public GrGLSLFragmentProcessor { +public: + GrGLSLMatrixEffect() {} + + void emitCode(EmitArgs& args) override { + fMatrixVar = args.fUniformHandler->addUniform(&args.fFp, kFragment_GrShaderFlag, + kFloat3x3_GrSLType, "matrix"); + SkString child = this->invokeChild(0, args.fInputColor, args); + args.fFragBuilder->codeAppendf("%s = %s;\n", args.fOutputColor, child.c_str()); + } + +private: + void onSetData(const GrGLSLProgramDataManager& pdman, + const GrFragmentProcessor& proc) override { + const GrMatrixEffect& mtx = proc.cast<GrMatrixEffect>(); + pdman.setSkMatrix(fMatrixVar, mtx.matrix()); + } + + UniformHandle fMatrixVar; +}; + +GrGLSLFragmentProcessor* GrMatrixEffect::onCreateGLSLInstance() const { + return new GrGLSLMatrixEffect(); +} + +void GrMatrixEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, + GrProcessorKeyBuilder* b) const {} + +bool GrMatrixEffect::onIsEqual(const GrFragmentProcessor& other) const { + const GrMatrixEffect& that = other.cast<GrMatrixEffect>(); + if (fMatrix != that.fMatrix) return false; + return true; +} + +GrMatrixEffect::GrMatrixEffect(const GrMatrixEffect& src) + : INHERITED(kGrMatrixEffect_ClassID, src.optimizationFlags()) + , fMatrix(src.fMatrix) { + this->cloneAndRegisterAllChildProcessors(src); +} + +std::unique_ptr<GrFragmentProcessor> GrMatrixEffect::clone() const { + return std::unique_ptr<GrFragmentProcessor>(new GrMatrixEffect(*this)); +} diff --git a/chromium/third_party/skia/src/gpu/effects/GrMatrixEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrMatrixEffect.fp deleted file mode 100644 index d325c7b73e3..00000000000 --- a/chromium/third_party/skia/src/gpu/effects/GrMatrixEffect.fp +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2020 Google LLC - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -in uniform float3x3 matrix; -in fragmentProcessor child; - -@class { - static std::unique_ptr<GrFragmentProcessor> Apply(const SkMatrix& matrix, - std::unique_ptr<GrFragmentProcessor> processor) { - if (matrix.isIdentity()) { - return processor; - } - SkASSERT(!processor->isSampledWithExplicitCoords()); - SkASSERT(processor->sampleMatrix().fKind == SkSL::SampleMatrix::Kind::kNone); - return Make(matrix, std::move(processor)); - } -} - -void main() { - sk_OutColor = sample(child, sk_InColor, matrix); -} diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrMatrixEffect.h b/chromium/third_party/skia/src/gpu/effects/GrMatrixEffect.h index 75a2dbc32ff..69fd1be37e1 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrMatrixEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/GrMatrixEffect.h @@ -5,49 +5,48 @@ * found in the LICENSE file. */ -/************************************************************************************************** - *** This file was autogenerated from GrMatrixEffect.fp; do not modify. - **************************************************************************************************/ #ifndef GrMatrixEffect_DEFINED #define GrMatrixEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrMatrixEffect : public GrFragmentProcessor { public: - static std::unique_ptr<GrFragmentProcessor> Apply( - const SkMatrix& matrix, std::unique_ptr<GrFragmentProcessor> processor) { + static std::unique_ptr<GrFragmentProcessor> Make( + const SkMatrix& matrix, std::unique_ptr<GrFragmentProcessor> child) { if (matrix.isIdentity()) { - return processor; + return child; } - SkASSERT(!processor->isSampledWithExplicitCoords()); - SkASSERT(processor->sampleMatrix().fKind == SkSL::SampleMatrix::Kind::kNone); - return Make(matrix, std::move(processor)); - } - static std::unique_ptr<GrFragmentProcessor> Make(SkMatrix matrix, - std::unique_ptr<GrFragmentProcessor> child) { - return std::unique_ptr<GrFragmentProcessor>(new GrMatrixEffect(matrix, std::move(child))); + SkASSERT(!child->isSampledWithExplicitCoords()); + SkASSERT(child->sampleMatrix().fKind == SkSL::SampleMatrix::Kind::kNone); + return std::unique_ptr<GrFragmentProcessor>( + new GrMatrixEffect(matrix, std::move(child))); } - GrMatrixEffect(const GrMatrixEffect& src); + std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "MatrixEffect"; } - SkMatrix matrix; - int child_index = -1; + const SkMatrix& matrix() const { return fMatrix; } private: + GrMatrixEffect(const GrMatrixEffect& src); + GrMatrixEffect(SkMatrix matrix, std::unique_ptr<GrFragmentProcessor> child) - : INHERITED(kGrMatrixEffect_ClassID, kNone_OptimizationFlags), matrix(matrix) { + : INHERITED(kGrMatrixEffect_ClassID, kNone_OptimizationFlags) + , fMatrix(matrix) { SkASSERT(child); - child_index = this->numChildProcessors(); - child->setSampleMatrix( - SkSL::SampleMatrix(SkSL::SampleMatrix::Kind::kConstantOrUniform, this, "matrix")); - this->registerChildProcessor(std::move(child)); + this->registerChild(std::move(child), SkSL::SampleMatrix::MakeConstUniform("matrix")); } + GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; + + SkMatrix fMatrix; + GR_DECLARE_FRAGMENT_PROCESSOR_TEST typedef GrFragmentProcessor INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/effects/GrOvalEffect.cpp b/chromium/third_party/skia/src/gpu/effects/GrOvalEffect.cpp index b7c001cd54b..a84e6c2c737 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrOvalEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrOvalEffect.cpp @@ -11,23 +11,20 @@ #include "src/gpu/effects/generated/GrCircleEffect.h" #include "src/gpu/effects/generated/GrEllipseEffect.h" -std::unique_ptr<GrFragmentProcessor> GrOvalEffect::Make(GrClipEdgeType edgeType, const SkRect& oval, - const GrShaderCaps& caps) { - if (GrClipEdgeType::kHairlineAA == edgeType) { - return nullptr; - } +GrFPResult GrOvalEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, GrClipEdgeType edgeType, + const SkRect& oval, const GrShaderCaps& caps) { SkScalar w = oval.width(); SkScalar h = oval.height(); if (SkScalarNearlyEqual(w, h)) { w /= 2; - return GrCircleEffect::Make(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + w), - w); + return GrCircleEffect::Make(std::move(inputFP), edgeType, + SkPoint::Make(oval.fLeft + w, oval.fTop + w), w); } else { w /= 2; h /= 2; - return GrEllipseEffect::Make(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h), + return GrEllipseEffect::Make(std::move(inputFP), edgeType, + SkPoint::Make(oval.fLeft + w, oval.fTop + h), SkPoint::Make(w, h), caps); } - - return nullptr; + SkUNREACHABLE; } diff --git a/chromium/third_party/skia/src/gpu/effects/GrOvalEffect.h b/chromium/third_party/skia/src/gpu/effects/GrOvalEffect.h index 8b4c95d71b1..955c1949566 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrOvalEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/GrOvalEffect.h @@ -11,8 +11,8 @@ #include "include/core/SkRefCnt.h" #include "include/gpu/GrTypes.h" #include "include/private/GrTypesPriv.h" +#include "src/gpu/GrFragmentProcessor.h" -class GrFragmentProcessor; class GrShaderCaps; struct SkRect; @@ -21,7 +21,8 @@ namespace GrOvalEffect { /** * Creates an effect that performs clipping against an oval. */ -std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRect&, const GrShaderCaps&); +GrFPResult Make(std::unique_ptr<GrFragmentProcessor>, GrClipEdgeType, const SkRect&, + const GrShaderCaps&); }; #endif diff --git a/chromium/third_party/skia/src/gpu/effects/GrPremulInputFragmentProcessor.fp b/chromium/third_party/skia/src/gpu/effects/GrPremulInputFragmentProcessor.fp deleted file mode 100644 index cbba6070740..00000000000 --- a/chromium/third_party/skia/src/gpu/effects/GrPremulInputFragmentProcessor.fp +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -@optimizationFlags { - kPreservesOpaqueInput_OptimizationFlag | kConstantOutputForConstantInput_OptimizationFlag -} - -void main() { - sk_OutColor = sk_InColor; - sk_OutColor.rgb *= sk_InColor.a; -} - -@class { - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { - return SkColor4f { input.fR, input.fG, input.fB, input.fA }.premul(); - } -} diff --git a/chromium/third_party/skia/src/gpu/effects/GrRGBToHSLFilterEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrRGBToHSLFilterEffect.fp index 443fd1ae395..b30d798ebbb 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrRGBToHSLFilterEffect.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrRGBToHSLFilterEffect.fp @@ -25,8 +25,10 @@ // [2] http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl // [3] http://www.chilliant.com/rgb2hsv.html +in fragmentProcessor? inputFP; + void main() { - half4 c = sk_InColor; + half4 c = sample(inputFP, sk_InColor); half4 p = (c.g < c.b) ? half4(c.bg, -1, 2/3.0) : half4(c.gb, 0, -1/3.0); half4 q = (c.r < p.x) ? half4(p.x, c.r, p.yw) @@ -48,13 +50,17 @@ void main() { } @optimizationFlags { + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & (kConstantOutputForConstantInput_OptimizationFlag | kPreservesOpaqueInput_OptimizationFlag) } @class { #include "include/private/SkColorData.h" - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& c) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { + SkPMColor4f c = this->numChildProcessors() + ? ConstantOutputForConstantInput(this->childProcessor(0), inColor) + : inColor; const auto p = (c.fG < c.fB) ? SkPMColor4f{ c.fB, c.fG, -1, 2/3.f } : SkPMColor4f{ c.fG, c.fB, 0, -1/3.f }, q = (c.fR < p[0]) ? SkPMColor4f{ p[0], c.fR, p[1], p[3] } diff --git a/chromium/third_party/skia/src/gpu/effects/GrRRectBlurEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrRRectBlurEffect.fp index 02a8743c166..e8cb928439d 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrRRectBlurEffect.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrRRectBlurEffect.fp @@ -5,10 +5,11 @@ * found in the LICENSE file. */ +in fragmentProcessor? inputFP; in float sigma; layout(ctype=SkRect) in float4 rect; in uniform half cornerRadius; -in uniform sampler2D ninePatchSampler; +in fragmentProcessor ninePatchFP; layout(ctype=SkRect) uniform float4 proxyRect; uniform half blurRadius; @@ -19,19 +20,20 @@ uniform half blurRadius; #include "src/core/SkGpuBlurUtils.h" #include "src/core/SkRRectPriv.h" #include "src/gpu/GrCaps.h" - #include "src/gpu/GrClip.h" #include "src/gpu/GrPaint.h" #include "src/gpu/GrProxyProvider.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/GrStyle.h" + #include "src/gpu/effects/GrTextureEffect.h" } @class { - static GrSurfaceProxyView find_or_create_rrect_blur_mask(GrRecordingContext* context, - const SkRRect& rrectToDraw, - const SkISize& dimensions, - float xformedSigma) { + static std::unique_ptr<GrFragmentProcessor> find_or_create_rrect_blur_mask_fp( + GrRecordingContext* context, + const SkRRect& rrectToDraw, + const SkISize& dimensions, + float xformedSigma) { static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey key; GrUniqueKey::Builder builder(&key, kDomain, 9, "RoundRect Blur Mask"); @@ -47,31 +49,37 @@ uniform half blurRadius; } builder.finish(); + // It seems like we could omit this matrix and modify the shader code to not normalize + // the coords used to sample the texture effect. However, the "proxyDims" value in the + // shader is not always the actual the proxy dimensions. This is because 'dimensions' here + // was computed using integer corner radii as determined in + // SkComputeBlurredRRectParams whereas the shader code uses the float radius to compute + // 'proxyDims'. Why it draws correctly with these unequal values is a mystery for the ages. + auto m = SkMatrix::Scale(dimensions.width(), dimensions.height()); static constexpr auto kMaskOrigin = kBottomLeft_GrSurfaceOrigin; GrProxyProvider* proxyProvider = context->priv().proxyProvider(); if (auto view = proxyProvider->findCachedProxyWithColorTypeFallback( key, kMaskOrigin, GrColorType::kAlpha_8, 1)) { - return view; + return GrTextureEffect::Make(std::move(view), kPremul_SkAlphaType, m); } auto rtc = GrRenderTargetContext::MakeWithFallback( context, GrColorType::kAlpha_8, nullptr, SkBackingFit::kExact, dimensions, 1, GrMipMapped::kNo, GrProtected::kNo, kMaskOrigin); if (!rtc) { - return {}; + return nullptr; } GrPaint paint; - rtc->clear(nullptr, SK_PMColor4fTRANSPARENT, - GrRenderTargetContext::CanClearFullscreen::kYes); - rtc->drawRRect(GrNoClip(), std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw, + rtc->clear(SK_PMColor4fTRANSPARENT); + rtc->drawRRect(nullptr, std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw, GrStyle::SimpleFill()); GrSurfaceProxyView srcView = rtc->readSurfaceView(); if (!srcView) { - return {}; + return nullptr; } SkASSERT(srcView.asTextureProxy()); auto rtc2 = SkGpuBlurUtils::GaussianBlur(context, @@ -86,27 +94,28 @@ uniform half blurRadius; SkTileMode::kClamp, SkBackingFit::kExact); if (!rtc2) { - return {}; + return nullptr; } GrSurfaceProxyView mask = rtc2->readSurfaceView(); if (!mask) { - return {}; + return nullptr; } SkASSERT(mask.asTextureProxy()); - SkASSERT(mask.origin() == kBottomLeft_GrSurfaceOrigin); + SkASSERT(mask.origin() == kMaskOrigin); proxyProvider->assignUniqueKeyToProxy(key, mask.asTextureProxy()); - - return mask; + return GrTextureEffect::Make(std::move(mask), kPremul_SkAlphaType, m); } } @optimizationFlags { - kCompatibleWithCoverageAsAlpha_OptimizationFlag + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag } @make { - static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext* context, + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrRecordingContext* context, float sigma, float xformedSigma, const SkRRect& srcRRect, @@ -114,11 +123,13 @@ uniform half blurRadius; } @cpp { - std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::Make(GrRecordingContext* context, - float sigma, - float xformedSigma, - const SkRRect& srcRRect, - const SkRRect& devRRect) { + std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::Make( + std::unique_ptr<GrFragmentProcessor> inputFP, + GrRecordingContext* context, + float sigma, + float xformedSigma, + const SkRRect& srcRRect, + const SkRRect& devRRect) { SkASSERT(!SkRRectPriv::IsCircle(devRRect) && !devRRect.isRect()); // Should've been caught up-stream // TODO: loosen this up @@ -147,15 +158,15 @@ uniform half blurRadius; return nullptr; } - GrSurfaceProxyView mask = find_or_create_rrect_blur_mask(context, rrectToDraw, dimensions, - xformedSigma); - if (!mask) { + std::unique_ptr<GrFragmentProcessor> maskFP = find_or_create_rrect_blur_mask_fp( + context, rrectToDraw, dimensions, xformedSigma); + if (!maskFP) { return nullptr; } return std::unique_ptr<GrFragmentProcessor>( - new GrRRectBlurEffect(xformedSigma, devRRect.getBounds(), - SkRRectPriv::GetSimpleRadii(devRRect).fX, std::move(mask))); + new GrRRectBlurEffect(std::move(inputFP), xformedSigma, devRRect.getBounds(), + SkRRectPriv::GetSimpleRadii(devRRect).fX, std::move(maskFP))); } } @@ -166,33 +177,46 @@ uniform half blurRadius; SkScalar sigma = d->fRandom->nextRangeF(1.f,10.f); SkRRect rrect; rrect.setRectXY(SkRect::MakeWH(w, h), r, r); - return GrRRectBlurEffect::Make(d->context(), sigma, sigma, rrect, rrect); + return GrRRectBlurEffect::Make(/*inputFP=*/nullptr, d->context(), sigma, sigma, rrect, rrect); } void main() { - // warp the fragment position to the appropriate part of the 9patch blur texture - - half2 rectCenter = half2((proxyRect.xy + proxyRect.zw) / 2.0); - half2 translatedFragPos = half2(sk_FragCoord.xy - proxyRect.xy); - half threshold = cornerRadius + 2.0 * blurRadius; - half2 middle = half2(proxyRect.zw - proxyRect.xy - 2.0 * threshold); - - if (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x + threshold)) { - translatedFragPos.x = threshold; - } else if (translatedFragPos.x >= (middle.x + threshold)) { - translatedFragPos.x -= middle.x - 1.0; - } - - if (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) { - translatedFragPos.y = threshold; - } else if (translatedFragPos.y >= (middle.y + threshold)) { - translatedFragPos.y -= middle.y - 1.0; - } - - half2 proxyDims = half2(2.0 * threshold + 1.0); + // Warp the fragment position to the appropriate part of the 9-patch blur texture by snipping + // out the middle section of the proxy rect. + half2 translatedFragPos = half2(sk_FragCoord.xy - proxyRect.LT); + half2 proxyCenter = half2((proxyRect.RB - proxyRect.LT) * 0.5); + half edgeSize = 2.0 * blurRadius + cornerRadius + 0.5; + + // Position the fragment so that (0, 0) marks the center of the proxy rectangle. + // Negative coordinates are on the left/top side and positive numbers are on the right/bottom. + translatedFragPos -= proxyCenter; + + // Temporarily strip off the fragment's sign. x/y are now strictly increasing as we move away + // from the center. + half2 fragDirection = sign(translatedFragPos); + translatedFragPos = abs(translatedFragPos); + + // Our goal is to snip out the "middle section" of the proxy rect (everything but the edge). + // We've repositioned our fragment position so that (0, 0) is the centerpoint and x/y are always + // positive, so we can subtract here and interpret negative results as being within the middle + // section. + translatedFragPos -= proxyCenter - edgeSize; + + // Remove the middle section by clamping to zero. + translatedFragPos = max(translatedFragPos, 0); + + // Reapply the fragment's sign, so that negative coordinates once again mean left/top side and + // positive means bottom/right side. + translatedFragPos *= fragDirection; + + // Offset the fragment so that (0, 0) marks the upper-left again, instead of the center point. + translatedFragPos += half2(edgeSize); + + half2 proxyDims = half2(2.0 * edgeSize); half2 texCoord = translatedFragPos / proxyDims; - sk_OutColor = sk_InColor * sample(ninePatchSampler, texCoord); + half4 inputColor = sample(inputFP, sk_InColor); + sk_OutColor = inputColor * sample(ninePatchFP, texCoord); } @setData(pdman) { diff --git a/chromium/third_party/skia/src/gpu/effects/GrRRectEffect.cpp b/chromium/third_party/skia/src/gpu/effects/GrRRectEffect.cpp index f444034e426..a5f8538f86a 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrRRectEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrRRectEffect.cpp @@ -45,8 +45,8 @@ public: // The flags are used to indicate which corners are circluar (unflagged corners are assumed to // be square). - static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, - uint32_t circularCornerFlags, const SkRRect&); + static GrFPResult Make(std::unique_ptr<GrFragmentProcessor>, GrClipEdgeType, + uint32_t circularCornerFlags, const SkRRect&); ~CircularRRectEffect() override {} @@ -60,8 +60,14 @@ public: GrClipEdgeType getEdgeType() const { return fEdgeType; } + bool hasInputFP() const { + return this->numChildProcessors() > 0; + } + private: - CircularRRectEffect(GrClipEdgeType, uint32_t circularCornerFlags, const SkRRect&); + CircularRRectEffect(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType, uint32_t circularCornerFlags, const SkRRect&); + CircularRRectEffect(const CircularRRectEffect& that); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; @@ -69,36 +75,50 @@ private: bool onIsEqual(const GrFragmentProcessor& other) const override; - SkRRect fRRect; + SkRRect fRRect; GrClipEdgeType fEdgeType; - uint32_t fCircularCornerFlags; + uint32_t fCircularCornerFlags; GR_DECLARE_FRAGMENT_PROCESSOR_TEST typedef GrFragmentProcessor INHERITED; }; -std::unique_ptr<GrFragmentProcessor> CircularRRectEffect::Make(GrClipEdgeType edgeType, - uint32_t circularCornerFlags, - const SkRRect& rrect) { +GrFPResult CircularRRectEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, + uint32_t circularCornerFlags, const SkRRect& rrect) { if (GrClipEdgeType::kFillAA != edgeType && GrClipEdgeType::kInverseFillAA != edgeType) { - return nullptr; + return GrFPFailure(std::move(inputFP)); } - return std::unique_ptr<GrFragmentProcessor>( - new CircularRRectEffect(edgeType, circularCornerFlags, rrect)); + return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>( + new CircularRRectEffect(std::move(inputFP), edgeType, circularCornerFlags, rrect))); } -CircularRRectEffect::CircularRRectEffect(GrClipEdgeType edgeType, uint32_t circularCornerFlags, +CircularRRectEffect::CircularRRectEffect(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, uint32_t circularCornerFlags, const SkRRect& rrect) - : INHERITED(kCircularRRectEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag) + : INHERITED( + kCircularRRectEffect_ClassID, + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag) , fRRect(rrect) , fEdgeType(edgeType) , fCircularCornerFlags(circularCornerFlags) { + if (inputFP != nullptr) { + this->registerChild(std::move(inputFP)); + } +} + +CircularRRectEffect::CircularRRectEffect(const CircularRRectEffect& that) + : INHERITED(kCircularRRectEffect_ClassID, that.optimizationFlags()) + , fRRect(that.fRRect) + , fEdgeType(that.fEdgeType) + , fCircularCornerFlags(that.fCircularCornerFlags) { + this->cloneAndRegisterAllChildProcessors(that); } std::unique_ptr<GrFragmentProcessor> CircularRRectEffect::clone() const { - return std::unique_ptr<GrFragmentProcessor>( - new CircularRRectEffect(fEdgeType, fCircularCornerFlags, fRRect)); + return std::unique_ptr<GrFragmentProcessor>(new CircularRRectEffect(*this)); } bool CircularRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { @@ -119,11 +139,13 @@ std::unique_ptr<GrFragmentProcessor> CircularRRectEffect::TestCreate(GrProcessor SkRRect rrect; rrect.setRectXY(SkRect::MakeWH(w, h), r, r); std::unique_ptr<GrFragmentProcessor> fp; + bool success; do { GrClipEdgeType et = (GrClipEdgeType)d->fRandom->nextULessThan(kGrClipEdgeTypeCnt); - fp = GrRRectEffect::Make(et, rrect, *d->caps()->shaderCaps()); - } while (nullptr == fp); + std::tie(success, fp) = GrRRectEffect::Make(/*inputFP=*/nullptr, et, rrect, + *d->caps()->shaderCaps()); + } while (!success); return fp; } #endif @@ -191,85 +213,85 @@ void GLCircularRRectEffect::emitCode(EmitArgs& args) { // alphas together. switch (crre.getCircularCornerFlags()) { case CircularRRectEffect::kAll_CornerFlags: - fragBuilder->codeAppendf("float2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); - fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); + fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName); + fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName); fragBuilder->codeAppend("float2 dxy = max(max(dxy0, dxy1), 0.0);"); fragBuilder->codeAppendf("half alpha = half(%s);", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kTopLeft_CornerFlag: - fragBuilder->codeAppendf("float2 dxy = max(%s.xy - sk_FragCoord.xy, 0.0);", + fragBuilder->codeAppendf("float2 dxy = max(%s.LT - sk_FragCoord.xy, 0.0);", rectName); - fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.z - sk_FragCoord.x));", + fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.R - sk_FragCoord.x));", rectName); - fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.w - sk_FragCoord.y));", + fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.B - sk_FragCoord.y));", rectName); fragBuilder->codeAppendf("half alpha = bottomAlpha * rightAlpha * half(%s);", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kTopRight_CornerFlag: - fragBuilder->codeAppendf("float2 dxy = max(float2(sk_FragCoord.x - %s.z, " - "%s.y - sk_FragCoord.y), 0.0);", + fragBuilder->codeAppendf("float2 dxy = max(float2(sk_FragCoord.x - %s.R, " + "%s.T - sk_FragCoord.y), 0.0);", rectName, rectName); - fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.x));", + fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.L));", rectName); - fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.w - sk_FragCoord.y));", + fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.B - sk_FragCoord.y));", rectName); fragBuilder->codeAppendf("half alpha = bottomAlpha * leftAlpha * half(%s);", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kBottomRight_CornerFlag: - fragBuilder->codeAppendf("float2 dxy = max(sk_FragCoord.xy - %s.zw, 0.0);", + fragBuilder->codeAppendf("float2 dxy = max(sk_FragCoord.xy - %s.RB, 0.0);", rectName); - fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.x));", + fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.L));", rectName); - fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.y));", + fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.T));", rectName); fragBuilder->codeAppendf("half alpha = topAlpha * leftAlpha * half(%s);", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kBottomLeft_CornerFlag: - fragBuilder->codeAppendf("float2 dxy = max(float2(%s.x - sk_FragCoord.x, " - "sk_FragCoord.y - %s.w), 0.0);", + fragBuilder->codeAppendf("float2 dxy = max(float2(%s.L - sk_FragCoord.x, " + "sk_FragCoord.y - %s.B), 0.0);", rectName, rectName); - fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.z - sk_FragCoord.x));", + fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.R - sk_FragCoord.x));", rectName); - fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.y));", + fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.T));", rectName); fragBuilder->codeAppendf("half alpha = topAlpha * rightAlpha * half(%s);", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kLeft_CornerFlags: - fragBuilder->codeAppendf("float2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); - fragBuilder->codeAppendf("float dy1 = sk_FragCoord.y - %s.w;", rectName); + fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName); + fragBuilder->codeAppendf("float dy1 = sk_FragCoord.y - %s.B;", rectName); fragBuilder->codeAppend("float2 dxy = max(float2(dxy0.x, max(dxy0.y, dy1)), 0.0);"); - fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.z - sk_FragCoord.x));", + fragBuilder->codeAppendf("half rightAlpha = half(saturate(%s.R - sk_FragCoord.x));", rectName); fragBuilder->codeAppendf("half alpha = rightAlpha * half(%s);", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kTop_CornerFlags: - fragBuilder->codeAppendf("float2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); - fragBuilder->codeAppendf("float dx1 = sk_FragCoord.x - %s.z;", rectName); + fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName); + fragBuilder->codeAppendf("float dx1 = sk_FragCoord.x - %s.R;", rectName); fragBuilder->codeAppend("float2 dxy = max(float2(max(dxy0.x, dx1), dxy0.y), 0.0);"); - fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.w - sk_FragCoord.y));", + fragBuilder->codeAppendf("half bottomAlpha = half(saturate(%s.B - sk_FragCoord.y));", rectName); fragBuilder->codeAppendf("half alpha = bottomAlpha * half(%s);", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kRight_CornerFlags: - fragBuilder->codeAppendf("float dy0 = %s.y - sk_FragCoord.y;", rectName); - fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); + fragBuilder->codeAppendf("float dy0 = %s.T - sk_FragCoord.y;", rectName); + fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName); fragBuilder->codeAppend("float2 dxy = max(float2(dxy1.x, max(dy0, dxy1.y)), 0.0);"); - fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.x));", + fragBuilder->codeAppendf("half leftAlpha = half(saturate(sk_FragCoord.x - %s.L));", rectName); fragBuilder->codeAppendf("half alpha = leftAlpha * half(%s);", clampedCircleDistance.c_str()); break; case CircularRRectEffect::kBottom_CornerFlags: - fragBuilder->codeAppendf("float dx0 = %s.x - sk_FragCoord.x;", rectName); - fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); + fragBuilder->codeAppendf("float dx0 = %s.L - sk_FragCoord.x;", rectName); + fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName); fragBuilder->codeAppend("float2 dxy = max(float2(max(dx0, dxy1.x), dxy1.y), 0.0);"); - fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.y));", + fragBuilder->codeAppendf("half topAlpha = half(saturate(sk_FragCoord.y - %s.T));", rectName); fragBuilder->codeAppendf("half alpha = topAlpha * half(%s);", clampedCircleDistance.c_str()); @@ -280,7 +302,11 @@ void GLCircularRRectEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppend("alpha = 1.0 - alpha;"); } - fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor); + SkString inputSample = crre.hasInputFP() + ? this->invokeChild(/*childIndex=*/0, args.fInputColor, args) + : SkString(args.fInputColor); + + fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, inputSample.c_str()); } void GLCircularRRectEffect::GenKey(const GrProcessor& processor, const GrShaderCaps&, @@ -385,7 +411,7 @@ GrGLSLFragmentProcessor* CircularRRectEffect::onCreateGLSLInstance() const { class EllipticalRRectEffect : public GrFragmentProcessor { public: - static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRRect&); + static GrFPResult Make(std::unique_ptr<GrFragmentProcessor>, GrClipEdgeType, const SkRRect&); ~EllipticalRRectEffect() override {} @@ -397,8 +423,13 @@ public: GrClipEdgeType getEdgeType() const { return fEdgeType; } + bool hasInputFP() const { + return this->numChildProcessors() > 0; + } + private: - EllipticalRRectEffect(GrClipEdgeType, const SkRRect&); + EllipticalRRectEffect(std::unique_ptr<GrFragmentProcessor>, GrClipEdgeType, const SkRRect&); + EllipticalRRectEffect(const EllipticalRRectEffect& that); GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; @@ -414,22 +445,37 @@ private: typedef GrFragmentProcessor INHERITED; }; -std::unique_ptr<GrFragmentProcessor> EllipticalRRectEffect::Make(GrClipEdgeType edgeType, - const SkRRect& rrect) { +GrFPResult EllipticalRRectEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, const SkRRect& rrect) { if (GrClipEdgeType::kFillAA != edgeType && GrClipEdgeType::kInverseFillAA != edgeType) { - return nullptr; + return GrFPFailure(std::move(inputFP)); } - return std::unique_ptr<GrFragmentProcessor>(new EllipticalRRectEffect(edgeType, rrect)); + return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>( + new EllipticalRRectEffect(std::move(inputFP), edgeType, rrect))); } -EllipticalRRectEffect::EllipticalRRectEffect(GrClipEdgeType edgeType, const SkRRect& rrect) - : INHERITED(kEllipticalRRectEffect_ClassID, kCompatibleWithCoverageAsAlpha_OptimizationFlag) +EllipticalRRectEffect::EllipticalRRectEffect(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, const SkRRect& rrect) + : INHERITED( + kEllipticalRRectEffect_ClassID, + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag) , fRRect(rrect) , fEdgeType(edgeType) { + if (inputFP != nullptr) { + this->registerChild(std::move(inputFP)); + } +} + +EllipticalRRectEffect::EllipticalRRectEffect(const EllipticalRRectEffect& that) + : INHERITED(kEllipticalRRectEffect_ClassID, that.optimizationFlags()) + , fRRect(that.fRRect) + , fEdgeType(that.fEdgeType) { + this->cloneAndRegisterAllChildProcessors(that); } std::unique_ptr<GrFragmentProcessor> EllipticalRRectEffect::clone() const { - return std::unique_ptr<GrFragmentProcessor>(new EllipticalRRectEffect(fEdgeType, fRRect)); + return std::unique_ptr<GrFragmentProcessor>(new EllipticalRRectEffect(*this)); } bool EllipticalRRectEffect::onIsEqual(const GrFragmentProcessor& other) const { @@ -470,10 +516,12 @@ std::unique_ptr<GrFragmentProcessor> EllipticalRRectEffect::TestCreate(GrProcess r[SkRRect::kUpperLeft_Corner].fY); } std::unique_ptr<GrFragmentProcessor> fp; + bool success; do { GrClipEdgeType et = (GrClipEdgeType)d->fRandom->nextULessThan(kGrClipEdgeTypeCnt); - fp = GrRRectEffect::Make(et, rrect, *d->caps()->shaderCaps()); - } while (nullptr == fp); + std::tie(success, fp) = GrRRectEffect::Make(/*inputFP=*/nullptr, et, rrect, + *d->caps()->shaderCaps()); + } while (!success); return fp; } #endif @@ -520,8 +568,8 @@ void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { // The code below is a simplified version of the above that performs maxs on the vector // components before computing distances and alpha values so that only one distance computation // need be computed to determine the min alpha. - fragBuilder->codeAppendf("float2 dxy0 = %s.xy - sk_FragCoord.xy;", rectName); - fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.zw;", rectName); + fragBuilder->codeAppendf("float2 dxy0 = %s.LT - sk_FragCoord.xy;", rectName); + fragBuilder->codeAppendf("float2 dxy1 = sk_FragCoord.xy - %s.RB;", rectName); // If we're on a device where float != fp32 then we'll do the distance computation in a space // that is normalized by the largest radius. The scale uniform will be scale, 1/scale. The @@ -589,7 +637,11 @@ void GLEllipticalRRectEffect::emitCode(EmitArgs& args) { fragBuilder->codeAppend("half alpha = clamp(0.5 + approx_dist, 0.0, 1.0);"); } - fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor); + SkString inputSample = erre.hasInputFP() + ? this->invokeChild(/*childIndex=*/0, args.fInputColor, args) + : SkString(args.fInputColor); + + fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, inputSample.c_str()); } void GLEllipticalRRectEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&, @@ -671,15 +723,15 @@ GrGLSLFragmentProcessor* EllipticalRRectEffect::onCreateGLSLInstance() const { ////////////////////////////////////////////////////////////////////////////// -std::unique_ptr<GrFragmentProcessor> GrRRectEffect::Make(GrClipEdgeType edgeType, - const SkRRect& rrect, - const GrShaderCaps& caps) { +GrFPResult GrRRectEffect::Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, const SkRRect& rrect, + const GrShaderCaps& caps) { if (rrect.isRect()) { - return GrConvexPolyEffect::Make(edgeType, rrect.getBounds()); + return GrConvexPolyEffect::Make(std::move(inputFP), edgeType, rrect.getBounds()); } if (rrect.isOval()) { - return GrOvalEffect::Make(edgeType, rrect.getBounds(), caps); + return GrOvalEffect::Make(std::move(inputFP), edgeType, rrect.getBounds(), caps); } if (rrect.isSimple()) { @@ -687,13 +739,13 @@ std::unique_ptr<GrFragmentProcessor> GrRRectEffect::Make(GrClipEdgeType edgeType SkRRectPriv::GetSimpleRadii(rrect).fY < kRadiusMin) { // In this case the corners are extremely close to rectangular and we collapse the // clip to a rectangular clip. - return GrConvexPolyEffect::Make(edgeType, rrect.getBounds()); + return GrConvexPolyEffect::Make(std::move(inputFP), edgeType, rrect.getBounds()); } if (SkRRectPriv::GetSimpleRadii(rrect).fX == SkRRectPriv::GetSimpleRadii(rrect).fY) { - return CircularRRectEffect::Make(edgeType, CircularRRectEffect::kAll_CornerFlags, - rrect); + return CircularRRectEffect::Make(std::move(inputFP), edgeType, + CircularRRectEffect::kAll_CornerFlags, rrect); } else { - return EllipticalRRectEffect::Make(edgeType, rrect); + return EllipticalRRectEffect::Make(std::move(inputFP), edgeType, rrect); } } @@ -737,6 +789,7 @@ std::unique_ptr<GrFragmentProcessor> GrRRectEffect::Make(GrClipEdgeType edgeType // This rrect should have been caught in the simple case above. Though, it would // be correctly handled in the fallthrough code. SkASSERT(false); + [[fallthrough]]; case CircularRRectEffect::kTopLeft_CornerFlag: case CircularRRectEffect::kTopRight_CornerFlag: case CircularRRectEffect::kBottomRight_CornerFlag: @@ -749,24 +802,24 @@ std::unique_ptr<GrFragmentProcessor> GrRRectEffect::Make(GrClipEdgeType edgeType if (squashedRadii) { rr.writable()->setRectRadii(rrect.getBounds(), radii); } - return CircularRRectEffect::Make(edgeType, cornerFlags, *rr); + return CircularRRectEffect::Make(std::move(inputFP), edgeType, cornerFlags, *rr); + } + case CircularRRectEffect::kNone_CornerFlags: { + return GrConvexPolyEffect::Make(std::move(inputFP), edgeType, rrect.getBounds()); } - case CircularRRectEffect::kNone_CornerFlags: - return GrConvexPolyEffect::Make(edgeType, rrect.getBounds()); default: { if (squashedRadii) { // If we got here then we squashed some but not all the radii to zero. (If all // had been squashed cornerFlags would be 0.) The elliptical effect doesn't // support some rounded and some square corners. - return nullptr; + return GrFPFailure(std::move(inputFP)); } if (rrect.isNinePatch()) { - return EllipticalRRectEffect::Make(edgeType, rrect); + return EllipticalRRectEffect::Make(std::move(inputFP), edgeType, rrect); } - return nullptr; + return GrFPFailure(std::move(inputFP)); } } } - - return nullptr; + return GrFPFailure(std::move(inputFP)); } diff --git a/chromium/third_party/skia/src/gpu/effects/GrRRectEffect.h b/chromium/third_party/skia/src/gpu/effects/GrRRectEffect.h index 426cb8f3c2c..e61246fdd94 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrRRectEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/GrRRectEffect.h @@ -11,8 +11,8 @@ #include "include/core/SkRefCnt.h" #include "include/gpu/GrTypes.h" #include "include/private/GrTypesPriv.h" +#include "src/gpu/GrFragmentProcessor.h" -class GrFragmentProcessor; class GrShaderCaps; class GrProcessor; class SkRRect; @@ -21,9 +21,11 @@ namespace GrRRectEffect { /** * Creates an effect that performs anti-aliased clipping against a SkRRect. It doesn't support - * all varieties of SkRRect so the caller must check for a nullptr return. + * all varieties of SkRRect, so the caller must check `success` in the GrFPResult. */ -std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType, const SkRRect&, const GrShaderCaps&); +GrFPResult Make(std::unique_ptr<GrFragmentProcessor>, GrClipEdgeType, const SkRRect&, + const GrShaderCaps&); + }; #endif diff --git a/chromium/third_party/skia/src/gpu/effects/GrRectBlurEffect.fp b/chromium/third_party/skia/src/gpu/effects/GrRectBlurEffect.fp index ec11611dda9..56cd64fcb7d 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrRectBlurEffect.fp +++ b/chromium/third_party/skia/src/gpu/effects/GrRectBlurEffect.fp @@ -17,8 +17,10 @@ #include "src/gpu/GrProxyProvider.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrShaderCaps.h" +#include "src/gpu/effects/GrTextureEffect.h" } +in fragmentProcessor? inputFP; in float4 rect; layout(key) bool highp = abs(rect.x) > 16000 || abs(rect.y) > 16000 || @@ -27,17 +29,20 @@ layout(key) bool highp = abs(rect.x) > 16000 || abs(rect.y) > 16000 || layout(when= highp) uniform float4 rectF; layout(when=!highp) uniform half4 rectH; -// Texture that is a LUT for integral of normal distribution. The value at x (where x is a texture -// coord between 0 and 1) is the integral from -inf to (3 * sigma * (-2 * x - 1)). I.e. x is mapped -// 0 3*sigma to -3 sigma. The flip saves a reversal in the shader. -in uniform sampler2D integral; -// Used to produce normalized texture coords for lookups in 'integral' -in uniform half invSixSigma; +// Effect that is a LUT for integral of normal distribution. The value at x:[0,6*sigma] is the +// integral from -inf to (3*sigma - x). I.e. x is mapped from [0, 6*sigma] to [3*sigma to -3*sigma]. +// The flip saves a reversal in the shader. +in fragmentProcessor integral; // There is a fast variant of the effect that does 2 texture lookups and a more general one for // wider blurs relative to rect sizes that does 4. layout(key) in bool isFast; +@optimizationFlags { + (inputFP ? ProcessorOptimizationFlags(inputFP.get()) : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag +} + @constructorParams { GrSamplerState samplerParams } @@ -45,8 +50,10 @@ layout(key) in bool isFast; @samplerParams(integral) { samplerParams } + @class { -static GrSurfaceProxyView CreateIntegralTexture(GrRecordingContext* context, float sixSigma) { +static std::unique_ptr<GrFragmentProcessor> MakeIntegralFP(GrRecordingContext* context, + float sixSigma) { // The texture we're producing represents the integral of a normal distribution over a six-sigma // range centered at zero. We want enough resolution so that the linear interpolation done in // texture lookup doesn't introduce noticeable artifacts. We conservatively choose to have 2 @@ -61,11 +68,15 @@ static GrSurfaceProxyView CreateIntegralTexture(GrRecordingContext* context, flo builder[0] = width; builder.finish(); + SkMatrix m = SkMatrix::Scale(width/sixSigma, 1.f); + GrProxyProvider* proxyProvider = context->priv().proxyProvider(); if (sk_sp<GrTextureProxy> proxy = proxyProvider->findOrCreateProxyByUniqueKey(key)) { GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(proxy->backendFormat(), GrColorType::kAlpha_8); - return {std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}; + GrSurfaceProxyView view{std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}; + return GrTextureEffect::Make( + std::move(view), kPremul_SkAlphaType, m, GrSamplerState::Filter::kBilerp); } SkBitmap bitmap; @@ -90,12 +101,14 @@ static GrSurfaceProxyView CreateIntegralTexture(GrRecordingContext* context, flo } SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin); proxyProvider->assignUniqueKeyToProxy(key, view.asTextureProxy()); - return view; + return GrTextureEffect::Make( + std::move(view), kPremul_SkAlphaType, m, GrSamplerState::Filter::kBilerp); } } @make { - static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext* context, + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrRecordingContext* context, const GrShaderCaps& caps, const SkRect& rect, float sigma) { SkASSERT(rect.isSorted()); @@ -110,7 +123,7 @@ static GrSurfaceProxyView CreateIntegralTexture(GrRecordingContext* context, flo } const float sixSigma = 6 * sigma; - GrSurfaceProxyView integral = CreateIntegralTexture(context, sixSigma); + std::unique_ptr<GrFragmentProcessor> integral = MakeIntegralFP(context, sixSigma); if (!integral) { return nullptr; } @@ -130,71 +143,61 @@ static GrSurfaceProxyView CreateIntegralTexture(GrRecordingContext* context, flo // less than 6 sigma wide then things aren't so simple and we have to consider both the // left and right edge of the rectangle (and similar in y). bool isFast = insetRect.isSorted(); - // 1 / (6 * sigma) is the domain of the integral texture. We use the inverse to produce - // normalized texture coords from frag coord distances. - float invSixSigma = 1.f / sixSigma; - return std::unique_ptr<GrFragmentProcessor>(new GrRectBlurEffect(insetRect, - std::move(integral), invSixSigma, isFast, GrSamplerState::Filter::kBilerp)); + return std::unique_ptr<GrFragmentProcessor>(new GrRectBlurEffect( + std::move(inputFP), insetRect, std::move(integral), + isFast, GrSamplerState::Filter::kBilerp)); } } void main() { - half xCoverage, yCoverage; - @if (isFast) { - // Get the smaller of the signed distance from the frag coord to the left and right - // edges and similar for y. - // The integral texture goes "backwards" (from 3*sigma to -3*sigma), So, the below - // computations align the left edge of the integral texture with the inset rect's edge - // extending outward 6 * sigma from the inset rect. - half x, y; - @if (highp) { - x = max(half(rectF.x - sk_FragCoord.x), half(sk_FragCoord.x - rectF.z)); - y = max(half(rectF.y - sk_FragCoord.y), half(sk_FragCoord.y - rectF.w)); - } else { - x = max(half(rectH.x - sk_FragCoord.x), half(sk_FragCoord.x - rectH.z)); - y = max(half(rectH.y - sk_FragCoord.y), half(sk_FragCoord.y - rectH.w)); - } - xCoverage = sample(integral, half2(x * invSixSigma, 0.5)).a; - yCoverage = sample(integral, half2(y * invSixSigma, 0.5)).a; - sk_OutColor = sk_InColor * xCoverage * yCoverage; + half xCoverage, yCoverage; + @if (isFast) { + // Get the smaller of the signed distance from the frag coord to the left and right + // edges and similar for y. + // The integral texture goes "backwards" (from 3*sigma to -3*sigma), So, the below + // computations align the left edge of the integral texture with the inset rect's edge + // extending outward 6 * sigma from the inset rect. + half2 xy; + @if (highp) { + xy = max(half2(rectF.LT - sk_FragCoord.xy), + half2(sk_FragCoord.xy - rectF.RB)); + } else { + xy = max(half2(rectH.LT - sk_FragCoord.xy), + half2(sk_FragCoord.xy - rectH.RB)); + } + xCoverage = sample(integral, half2(xy.x, 0.5)).a; + yCoverage = sample(integral, half2(xy.y, 0.5)).a; + } else { + // We just consider just the x direction here. In practice we compute x and y separately + // and multiply them together. + // We define our coord system so that the point at which we're evaluating a kernel + // defined by the normal distribution (K) at 0. In this coord system let L be left + // edge and R be the right edge of the rectangle. + // We can calculate C by integrating K with the half infinite ranges outside the L to R + // range and subtracting from 1: + // C = 1 - <integral of K from from -inf to L> - <integral of K from R to inf> + // K is symmetric about x=0 so: + // C = 1 - <integral of K from from -inf to L> - <integral of K from -inf to -R> + + // The integral texture goes "backwards" (from 3*sigma to -3*sigma) which is factored + // in to the below calculations. + // Also, our rect uniform was pre-inset by 3 sigma from the actual rect being blurred, + // also factored in. + half4 rect; + @if (highp) { + rect.LT = half2(rectF.LT - sk_FragCoord.xy); + rect.RB = half2(sk_FragCoord.xy - rectF.RB); } else { - // We just consider just the x direction here. In practice we compute x and y separately - // and multiply them together. - // We define our coord system so that the point at which we're evaluating a kernel - // defined by the normal distribution (K) as 0. In this coord system let L be left - // edge and R be the right edge of the rectangle. - // We can calculate C by integrating K with the half infinite ranges outside the L to R - // range and subtracting from 1: - // C = 1 - <integral of K from from -inf to L> - <integral of K from R to inf> - // K is symmetric about x=0 so: - // C = 1 - <integral of K from from -inf to L> - <integral of K from -inf to -R> - - // The integral texture goes "backwards" (from 3*sigma to -3*sigma) which is factored - // in to the below calculations. - // Also, our rect uniform was pre-inset by 3 sigma from the actual rect being blurred, - // also factored in. - half l, r, t, b; - @if (highp) { - l = half(sk_FragCoord.x - rectF.x); - r = half(rectF.z - sk_FragCoord.x); - t = half(sk_FragCoord.y - rectF.y); - b = half(rectF.w - sk_FragCoord.y); - } else { - l = half(sk_FragCoord.x - rectH.x); - r = half(rectH.z - sk_FragCoord.x); - t = half(sk_FragCoord.y - rectH.y); - b = half(rectH.w - sk_FragCoord.y); - } - half il = 1 + l * invSixSigma; - half ir = 1 + r * invSixSigma; - half it = 1 + t * invSixSigma; - half ib = 1 + b * invSixSigma; - xCoverage = 1 - sample(integral, half2(il, 0.5)).a - - sample(integral, half2(ir, 0.5)).a; - yCoverage = 1 - sample(integral, half2(it, 0.5)).a - - sample(integral, half2(ib, 0.5)).a; + rect.LT = half2(rectH.LT - sk_FragCoord.xy); + rect.RB = half2(sk_FragCoord.xy - rectH.RB); } - sk_OutColor = sk_InColor * xCoverage * yCoverage; + xCoverage = 1 - sample(integral, half2(rect.L, 0.5)).a + - sample(integral, half2(rect.R, 0.5)).a; + yCoverage = 1 - sample(integral, half2(rect.T, 0.5)).a + - sample(integral, half2(rect.B, 0.5)).a; + } + half4 inputColor = sample(inputFP, sk_InColor); + sk_OutColor = inputColor * xCoverage * yCoverage; } @setData(pdman) { @@ -202,12 +205,10 @@ void main() { pdman.set4fv(highp ? rectF : rectH, 1, r); } -@optimizationFlags { kCompatibleWithCoverageAsAlpha_OptimizationFlag } - @test(data) { float sigma = data->fRandom->nextRangeF(3,8); float width = data->fRandom->nextRangeF(200,300); float height = data->fRandom->nextRangeF(200,300); - return GrRectBlurEffect::Make(data->context(), *data->caps()->shaderCaps(), + return GrRectBlurEffect::Make(/*inputFP=*/nullptr, data->context(), *data->caps()->shaderCaps(), SkRect::MakeWH(width, height), sigma); } diff --git a/chromium/third_party/skia/src/gpu/effects/GrShadowGeoProc.cpp b/chromium/third_party/skia/src/gpu/effects/GrShadowGeoProc.cpp index de6db266441..d129a7d2ff0 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrShadowGeoProc.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrShadowGeoProc.cpp @@ -22,7 +22,6 @@ public: const GrRRectShadowGeoProc& rsgp = args.fGP.cast<GrRRectShadowGeoProc>(); GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; - GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; // emit attributes @@ -35,13 +34,7 @@ public: // Setup position this->writeOutputPosition(vertBuilder, gpArgs, rsgp.inPosition().name()); - - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - rsgp.inPosition().asShaderVar(), - args.fFPCoordTransformHandler); + // No need for local coordinates, this GP does not combine with fragment processors fragBuilder->codeAppend("half d = length(shadowParams.xy);"); fragBuilder->codeAppend("float2 uv = float2(shadowParams.z * (1.0 - d), 0.5);"); @@ -53,7 +46,7 @@ public: void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc, const CoordTransformRange& transformRange) override { - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); } private: diff --git a/chromium/third_party/skia/src/gpu/effects/GrSkSLFP.cpp b/chromium/third_party/skia/src/gpu/effects/GrSkSLFP.cpp index a2e9b465d64..b2ed34f653c 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrSkSLFP.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrSkSLFP.cpp @@ -198,8 +198,7 @@ const char* GrSkSLFP::name() const { } void GrSkSLFP::addChild(std::unique_ptr<GrFragmentProcessor> child) { - child->setSampledWithExplicitCoords(); - this->registerChildProcessor(std::move(child)); + this->registerExplicitlySampledChild(std::move(child)); } GrGLSLFragmentProcessor* GrSkSLFP::onCreateGLSLInstance() const { @@ -259,6 +258,7 @@ GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrSkSLFP); #include "include/effects/SkArithmeticImageFilter.h" #include "include/effects/SkOverdrawColorFilter.h" #include "include/gpu/GrContext.h" +#include "src/core/SkColorFilterBase.h" #include "src/gpu/effects/generated/GrConstColorProcessor.h" extern const char* SKSL_ARITHMETIC_SRC; @@ -284,7 +284,7 @@ std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d auto result = GrSkSLFP::Make(d->context(), effect, "Arithmetic", SkData::MakeWithCopy(&inputs, sizeof(inputs))); result->addChild(GrConstColorProcessor::Make( - SK_PMColor4fWHITE, GrConstColorProcessor::InputMode::kIgnore)); + /*inputFP=*/nullptr, SK_PMColor4fWHITE, GrConstColorProcessor::InputMode::kIgnore)); return std::unique_ptr<GrFragmentProcessor>(result.release()); } case 2: { @@ -292,8 +292,8 @@ std::unique_ptr<GrFragmentProcessor> GrSkSLFP::TestCreate(GrProcessorTestData* d for (SkColor& c : colors) { c = d->fRandom->nextU(); } - return SkOverdrawColorFilter::MakeWithSkColors(colors) - ->asFragmentProcessor(d->context(), GrColorInfo{}); + auto filter = SkOverdrawColorFilter::MakeWithSkColors(colors); + return as_CFB(filter)->asFragmentProcessor(d->context(), GrColorInfo{}); } } SK_ABORT("unreachable"); diff --git a/chromium/third_party/skia/src/gpu/effects/GrTextureEffect.cpp b/chromium/third_party/skia/src/gpu/effects/GrTextureEffect.cpp index b2ed99eea71..5113cbf8137 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrTextureEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrTextureEffect.cpp @@ -9,7 +9,7 @@ #include "src/gpu/GrTexture.h" #include "src/gpu/GrTexturePriv.h" -#include "src/gpu/effects/generated/GrMatrixEffect.h" +#include "src/gpu/effects/GrMatrixEffect.h" #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" #include "src/gpu/glsl/GrGLSLProgramBuilder.h" @@ -110,7 +110,7 @@ GrTextureEffect::Sampling::Sampling(const GrSurfaceProxy& proxy, r.fShaderSubset = r.fShaderClamp = {0, 0}; return r; } - r.fShaderMode = static_cast<ShaderMode>(mode); + r.fShaderMode = GetShaderMode(mode, filter); r.fHWMode = Mode::kClamp; return r; }; @@ -142,8 +142,7 @@ bool GrTextureEffect::Sampling::hasBorderAlpha() const { fHWSampler.wrapModeY() == GrSamplerState::WrapMode::kClampToBorder) { return true; } - if (fShaderModes[0] == ShaderMode::kClampToBorder || - fShaderModes[1] == ShaderMode::kClampToBorder) { + if (ShaderModeIsClampToBorder(fShaderModes[0]) || ShaderModeIsClampToBorder(fShaderModes[1])) { return fBorder[3] < 1.f; } return false; @@ -196,7 +195,7 @@ std::unique_ptr<GrFragmentProcessor> GrTextureEffect::Make(GrSurfaceProxyView vi SkMatrix final; bool lazyProxyNormalization; get_matrix(matrix, view, &final, &lazyProxyNormalization); - return GrMatrixEffect::Apply(final, std::unique_ptr<GrFragmentProcessor>( + return GrMatrixEffect::Make(final, std::unique_ptr<GrFragmentProcessor>( new GrTextureEffect(std::move(view), alphaType, Sampling(filter), @@ -214,7 +213,7 @@ std::unique_ptr<GrFragmentProcessor> GrTextureEffect::Make(GrSurfaceProxyView vi SkMatrix final; bool lazyProxyNormalization; get_matrix(matrix, view, &final, &lazyProxyNormalization); - return GrMatrixEffect::Apply(final, std::unique_ptr<GrFragmentProcessor>( + return GrMatrixEffect::Make(final, std::unique_ptr<GrFragmentProcessor>( new GrTextureEffect(std::move(view), alphaType, sampling, @@ -232,7 +231,7 @@ std::unique_ptr<GrFragmentProcessor> GrTextureEffect::MakeSubset(GrSurfaceProxyV SkMatrix final; bool lazyProxyNormalization; get_matrix(matrix, view, &final, &lazyProxyNormalization); - return GrMatrixEffect::Apply(final, std::unique_ptr<GrFragmentProcessor>( + return GrMatrixEffect::Make(final, std::unique_ptr<GrFragmentProcessor>( new GrTextureEffect(std::move(view), alphaType, sampling, @@ -251,37 +250,41 @@ std::unique_ptr<GrFragmentProcessor> GrTextureEffect::MakeSubset(GrSurfaceProxyV SkMatrix final; bool lazyProxyNormalization; get_matrix(matrix, view, &final, &lazyProxyNormalization); - return GrMatrixEffect::Apply(final, std::unique_ptr<GrFragmentProcessor>( + return GrMatrixEffect::Make(final, std::unique_ptr<GrFragmentProcessor>( new GrTextureEffect(std::move(view), alphaType, sampling, lazyProxyNormalization))); } -GrTextureEffect::FilterLogic GrTextureEffect::GetFilterLogic(ShaderMode mode, - GrSamplerState::Filter filter) { +GrTextureEffect::ShaderMode GrTextureEffect::GetShaderMode(GrSamplerState::WrapMode mode, + GrSamplerState::Filter filter) { switch (mode) { - case ShaderMode::kMirrorRepeat: - case ShaderMode::kNone: - case ShaderMode::kClamp: - return FilterLogic::kNone; - case ShaderMode::kRepeat: + case GrSamplerState::WrapMode::kMirrorRepeat: + return ShaderMode::kMirrorRepeat; + case GrSamplerState::WrapMode::kClamp: + return ShaderMode::kClamp; + case GrSamplerState::WrapMode::kRepeat: switch (filter) { case GrSamplerState::Filter::kNearest: - return FilterLogic::kNone; + return ShaderMode::kRepeatNearest; case GrSamplerState::Filter::kBilerp: - return FilterLogic::kRepeatBilerp; + return ShaderMode::kRepeatBilerp; case GrSamplerState::Filter::kMipMap: - return FilterLogic::kRepeatMipMap; + return ShaderMode::kRepeatMipMap; } SkUNREACHABLE; - case ShaderMode::kClampToBorder: - return filter > GrSamplerState::Filter::kNearest ? FilterLogic::kClampToBorderFilter - : FilterLogic::kClampToBorderNearest; + case GrSamplerState::WrapMode::kClampToBorder: + return filter == GrSamplerState::Filter::kNearest ? ShaderMode::kClampToBorderNearest + : ShaderMode::kClampToBorderFilter; } SkUNREACHABLE; } +inline bool GrTextureEffect::ShaderModeIsClampToBorder(ShaderMode m) { + return m == ShaderMode::kClampToBorderNearest || m == ShaderMode::kClampToBorderFilter; +} + GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { class Impl : public GrGLSLFragmentProcessor { UniformHandle fSubsetUni; @@ -300,10 +303,18 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { } auto* fb = args.fFragBuilder; if (te.sampleMatrix().fKind == SkSL::SampleMatrix::Kind::kMixed) { + // FIXME this is very similar to the extra logic in + // GrGLSLFragmentShaderBuilder::ensureCoords2D args.fUniformHandler->writeUniformMappings(te.sampleMatrix().fOwner, fb); - coords = SkStringPrintf("(%s * _matrix * float3(%s, 1)).xy", - te.sampleMatrix().fExpression.c_str(), - coords.c_str()); + SkString coords2D; + coords2D.printf("%s_teSample", coords.c_str()); + + fb->codeAppendf("float3 %s_3d = %s * _matrix * %s.xy1;\n", + coords2D.c_str(), te.sampleMatrix().fExpression.c_str(), + coords.c_str()); + fb->codeAppendf("float2 %s = %s_3d.xy / %s_3d.z;\n", + coords2D.c_str(), coords2D.c_str(), coords2D.c_str()); + coords = coords2D; } if (te.fShaderModes[0] == ShaderMode::kNone && te.fShaderModes[1] == ShaderMode::kNone) { @@ -354,24 +365,55 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { const auto& m = te.fShaderModes; GrTextureType textureType = te.fSampler.proxy()->backendFormat().textureType(); bool normCoords = textureType != GrTextureType::kRectangle; - auto filter = te.fSampler.samplerState().filter(); - FilterLogic filterLogic[2] = {GetFilterLogic(m[0], filter), - GetFilterLogic(m[1], filter)}; const char* borderName = nullptr; - if (te.fShaderModes[0] == ShaderMode::kClampToBorder || - te.fShaderModes[1] == ShaderMode::kClampToBorder) { + if (te.hasClampToBorderShaderMode()) { fBorderUni = args.fUniformHandler->addUniform( &te, kFragment_GrShaderFlag, kHalf4_GrSLType, "border", &borderName); } auto modeUsesSubset = [](ShaderMode m) { - return m == ShaderMode::kRepeat || m == ShaderMode::kMirrorRepeat || - m == ShaderMode::kClampToBorder; + switch (m) { + case ShaderMode::kNone: return false; + case ShaderMode::kClamp: return false; + case ShaderMode::kRepeatNearest: return true; + case ShaderMode::kRepeatBilerp: return true; + case ShaderMode::kRepeatMipMap: return true; + case ShaderMode::kMirrorRepeat: return true; + case ShaderMode::kClampToBorderNearest: return true; + case ShaderMode::kClampToBorderFilter: return true; + } + SkUNREACHABLE; + }; + + auto modeUsesClamp = [](ShaderMode m) { + switch (m) { + case ShaderMode::kNone: return false; + case ShaderMode::kClamp: return true; + case ShaderMode::kRepeatNearest: return true; + case ShaderMode::kRepeatBilerp: return true; + case ShaderMode::kRepeatMipMap: return true; + case ShaderMode::kMirrorRepeat: return true; + case ShaderMode::kClampToBorderNearest: return false; + case ShaderMode::kClampToBorderFilter: return true; + } + SkUNREACHABLE; }; - auto modeUsesClamp = [filter](ShaderMode m) { - return m != ShaderMode::kNone && - (m != ShaderMode::kClampToBorder || filter > Filter::kNearest); + // To keep things a little simpler, when we have filtering logic in the shader we + // operate on unnormalized texture coordinates. We will add a uniform that stores + // {w, h, 1/w, 1/h} in a float4 below. + auto modeRequiresUnormCoords = [](ShaderMode m) { + switch (m) { + case ShaderMode::kNone: return false; + case ShaderMode::kClamp: return false; + case ShaderMode::kRepeatNearest: return false; + case ShaderMode::kRepeatBilerp: return true; + case ShaderMode::kRepeatMipMap: return true; + case ShaderMode::kMirrorRepeat: return false; + case ShaderMode::kClampToBorderNearest: return true; + case ShaderMode::kClampToBorderFilter: return true; + } + SkUNREACHABLE; }; bool useSubset[2] = {modeUsesSubset(m[0]), modeUsesSubset(m[1])}; @@ -389,12 +431,9 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { &te, kFragment_GrShaderFlag, kFloat4_GrSLType, "clamp", &clampName); } - // To keep things a little simpler, when we have filtering logic in the shader we - // operate on unnormalized texture coordinates. We add a uniform that stores - // {w, h, 1/w, 1/h} in a float4. const char* norm = nullptr; - if (normCoords && (filterLogic[0] != FilterLogic::kNone || - filterLogic[1] != FilterLogic::kNone)) { + if (normCoords && (modeRequiresUnormCoords(m[0]) || + modeRequiresUnormCoords(m[1]))) { // TODO: Detect support for textureSize() or polyfill textureSize() in SkSL and // always use? fNormUni = args.fUniformHandler->addUniform(&te, kFragment_GrShaderFlag, @@ -428,55 +467,56 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { // These modes either don't use the subset rect or don't need to map the // coords to be within the subset. case ShaderMode::kNone: - case ShaderMode::kClampToBorder: + case ShaderMode::kClampToBorderNearest: + case ShaderMode::kClampToBorderFilter: case ShaderMode::kClamp: fb->codeAppendf("subsetCoord.%s = inCoord.%s;", coordSwizzle, coordSwizzle); break; - case ShaderMode::kRepeat: - if (filter == Filter::kMipMap) { - // The approach here is to generate two sets of texture coords that - // are both "moving" at the same speed (if not direction) as - // inCoords. We accomplish that by using two out of phase mirror - // repeat coords. We will always sample using both coords but the - // read from the upward sloping one is selected using a weight - // that transitions from one set to the other near the reflection - // point. Like the coords, the weight is a saw-tooth function, - // phase-shifted, vertically translated, and then clamped to 0..1. - // TODO: Skip this and use textureGrad() when available. - SkASSERT(extraCoord); - SkASSERT(coordWeight); - fb->codeAppend("{"); - fb->codeAppendf("float w = %s.%s - %s.%s;", subsetName, - subsetStopSwizzle, subsetName, subsetStartSwizzle); - fb->codeAppendf("float w2 = 2 * w;"); - fb->codeAppendf("float d = inCoord.%s - %s.%s;", coordSwizzle, - subsetName, subsetStartSwizzle); - fb->codeAppend("float m = mod(d, w2);"); - fb->codeAppend("float o = mix(m, w2 - m, step(w, m));"); - fb->codeAppendf("subsetCoord.%s = o + %s.%s;", coordSwizzle, - subsetName, subsetStartSwizzle); - fb->codeAppendf("%s = w - o + %s.%s;", extraCoord, subsetName, - subsetStartSwizzle); - // coordWeight is used as the third param of mix() to blend between a - // sample taken using subsetCoord and a sample at extraCoord. - fb->codeAppend("float hw = w/2;"); - fb->codeAppend("float n = mod(d - hw, w2);"); - fb->codeAppendf( - "%s = saturate(half(mix(n, w2 - n, step(w, n)) - hw + " - "0.5));", - coordWeight); - fb->codeAppend("}"); - } else { - fb->codeAppendf( - "subsetCoord.%s = mod(inCoord.%s - %s.%s, %s.%s - %s.%s) + " - "%s.%s;", - coordSwizzle, coordSwizzle, subsetName, subsetStartSwizzle, - subsetName, subsetStopSwizzle, subsetName, - subsetStartSwizzle, subsetName, subsetStartSwizzle); - } + case ShaderMode::kRepeatNearest: + case ShaderMode::kRepeatBilerp: + fb->codeAppendf( + "subsetCoord.%s = mod(inCoord.%s - %s.%s, %s.%s - %s.%s) + " + "%s.%s;", + coordSwizzle, coordSwizzle, subsetName, subsetStartSwizzle, + subsetName, subsetStopSwizzle, subsetName, subsetStartSwizzle, + subsetName, subsetStartSwizzle); + break; + case ShaderMode::kRepeatMipMap: + // The approach here is to generate two sets of texture coords that + // are both "moving" at the same speed (if not direction) as + // inCoords. We accomplish that by using two out of phase mirror + // repeat coords. We will always sample using both coords but the + // read from the upward sloping one is selected using a weight + // that transitions from one set to the other near the reflection + // point. Like the coords, the weight is a saw-tooth function, + // phase-shifted, vertically translated, and then clamped to 0..1. + // TODO: Skip this and use textureGrad() when available. + SkASSERT(extraCoord); + SkASSERT(coordWeight); + fb->codeAppend("{"); + fb->codeAppendf("float w = %s.%s - %s.%s;", subsetName, + subsetStopSwizzle, subsetName, subsetStartSwizzle); + fb->codeAppendf("float w2 = 2 * w;"); + fb->codeAppendf("float d = inCoord.%s - %s.%s;", coordSwizzle, + subsetName, subsetStartSwizzle); + fb->codeAppend("float m = mod(d, w2);"); + fb->codeAppend("float o = mix(m, w2 - m, step(w, m));"); + fb->codeAppendf("subsetCoord.%s = o + %s.%s;", coordSwizzle, subsetName, + subsetStartSwizzle); + fb->codeAppendf("%s = w - o + %s.%s;", extraCoord, subsetName, + subsetStartSwizzle); + // coordWeight is used as the third param of mix() to blend between a + // sample taken using subsetCoord and a sample at extraCoord. + fb->codeAppend("float hw = w/2;"); + fb->codeAppend("float n = mod(d - hw, w2);"); + fb->codeAppendf( + "%s = saturate(half(mix(n, w2 - n, step(w, n)) - hw + " + "0.5));", + coordWeight); + fb->codeAppend("}"); break; - case ShaderMode::kMirrorRepeat: { + case ShaderMode::kMirrorRepeat: fb->codeAppend("{"); fb->codeAppendf("float w = %s.%s - %s.%s;", subsetName, subsetStopSwizzle, subsetName, subsetStartSwizzle); @@ -487,7 +527,6 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { coordSwizzle, subsetName, subsetStartSwizzle); fb->codeAppend("}"); break; - } } }; @@ -510,12 +549,12 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { const char* repeatCoordWeightX = nullptr; const char* extraRepeatCoordY = nullptr; const char* repeatCoordWeightY = nullptr; - if (filterLogic[0] == FilterLogic::kRepeatMipMap) { + if (m[0] == ShaderMode::kRepeatMipMap) { fb->codeAppend("float extraRepeatCoordX; half repeatCoordWeightX;"); extraRepeatCoordX = "extraRepeatCoordX"; repeatCoordWeightX = "repeatCoordWeightX"; } - if (filterLogic[1] == FilterLogic::kRepeatMipMap) { + if (m[1] == ShaderMode::kRepeatMipMap) { fb->codeAppend("float extraRepeatCoordY; half repeatCoordWeightY;"); extraRepeatCoordY = "extraRepeatCoordY"; repeatCoordWeightY = "repeatCoordWeightY"; @@ -532,11 +571,11 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { clampCoord(useClamp[1], "y", "y", "w"); // Additional clamping for the extra coords for kRepeatMipMap. - if (filterLogic[0] == FilterLogic::kRepeatMipMap) { + if (m[0] == ShaderMode::kRepeatMipMap) { fb->codeAppendf("extraRepeatCoordX = clamp(extraRepeatCoordX, %s.x, %s.z);", clampName, clampName); } - if (filterLogic[1] == FilterLogic::kRepeatMipMap) { + if (m[1] == ShaderMode::kRepeatMipMap) { fb->codeAppendf("extraRepeatCoordY = clamp(extraRepeatCoordY, %s.y, %s.w);", clampName, clampName); } @@ -544,8 +583,7 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { // Do the 2 or 4 texture reads for kRepeatMipMap and then apply the weight(s) // to blend between them. If neither direction is kRepeatMipMap do a single // read at clampedCoord. - if (filterLogic[0] == FilterLogic::kRepeatMipMap && - filterLogic[1] == FilterLogic::kRepeatMipMap) { + if (m[0] == ShaderMode::kRepeatMipMap && m[1] == ShaderMode::kRepeatMipMap) { fb->codeAppendf( "half4 textureColor =" " mix(mix(%s, %s, repeatCoordWeightX)," @@ -556,11 +594,11 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { read("float2(clampedCoord.x, extraRepeatCoordY)").c_str(), read("float2(extraRepeatCoordX, extraRepeatCoordY)").c_str()); - } else if (filterLogic[0] == FilterLogic::kRepeatMipMap) { + } else if (m[0] == ShaderMode::kRepeatMipMap) { fb->codeAppendf("half4 textureColor = mix(%s, %s, repeatCoordWeightX);", read("clampedCoord").c_str(), read("float2(extraRepeatCoordX, clampedCoord.y)").c_str()); - } else if (filterLogic[1] == FilterLogic::kRepeatMipMap) { + } else if (m[1] == ShaderMode::kRepeatMipMap) { fb->codeAppendf("half4 textureColor = mix(%s, %s, repeatCoordWeightY);", read("clampedCoord").c_str(), read("float2(clampedCoord.x, extraRepeatCoordY)").c_str()); @@ -575,15 +613,13 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { // Calculate the amount the coord moved for clamping. This will be used // to implement shader-based filtering for kClampToBorder and kRepeat. - if (filterLogic[0] == FilterLogic::kRepeatBilerp || - filterLogic[0] == FilterLogic::kClampToBorderFilter) { + if (m[0] == ShaderMode::kRepeatBilerp || m[0] == ShaderMode::kClampToBorderFilter) { fb->codeAppend("half errX = half(subsetCoord.x - clampedCoord.x);"); fb->codeAppendf("float repeatCoordX = errX > 0 ? %s.x : %s.z;", clampName, clampName); repeatBilerpReadX = read("float2(repeatCoordX, clampedCoord.y)"); } - if (filterLogic[1] == FilterLogic::kRepeatBilerp || - filterLogic[1] == FilterLogic::kClampToBorderFilter) { + if (m[1] == ShaderMode::kRepeatBilerp || m[1] == ShaderMode::kClampToBorderFilter) { fb->codeAppend("half errY = half(subsetCoord.y - clampedCoord.y);"); fb->codeAppendf("float repeatCoordY = errY > 0 ? %s.y : %s.w;", clampName, clampName); @@ -595,8 +631,7 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { // or a corner. Then blend the multiple reads using the err values calculated // above. const char* ifStr = "if"; - if (filterLogic[0] == FilterLogic::kRepeatBilerp && - filterLogic[1] == FilterLogic::kRepeatBilerp) { + if (m[0] == ShaderMode::kRepeatBilerp && m[1] == ShaderMode::kRepeatBilerp) { auto repeatBilerpReadXY = read("float2(repeatCoordX, repeatCoordY)"); fb->codeAppendf( "if (errX != 0 && errY != 0) {" @@ -609,14 +644,14 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { repeatBilerpReadXY.c_str()); ifStr = "else if"; } - if (filterLogic[0] == FilterLogic::kRepeatBilerp) { + if (m[0] == ShaderMode::kRepeatBilerp) { fb->codeAppendf( "%s (errX != 0) {" " textureColor = mix(textureColor, %s, abs(errX));" "}", ifStr, repeatBilerpReadX.c_str()); } - if (filterLogic[1] == FilterLogic::kRepeatBilerp) { + if (m[1] == ShaderMode::kRepeatBilerp) { fb->codeAppendf( "%s (errY != 0) {" " textureColor = mix(textureColor, %s, abs(errY));" @@ -626,27 +661,30 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { // Do soft edge shader filtering against border color for kClampToBorderFilter using // the err values calculated above. - if (filterLogic[0] == FilterLogic::kClampToBorderFilter) { + if (m[0] == ShaderMode::kClampToBorderFilter) { fb->codeAppendf("textureColor = mix(textureColor, %s, min(abs(errX), 1));", borderName); } - if (filterLogic[1] == FilterLogic::kClampToBorderFilter) { + if (m[1] == ShaderMode::kClampToBorderFilter) { fb->codeAppendf("textureColor = mix(textureColor, %s, min(abs(errY), 1));", borderName); } // Do hard-edge shader transition to border color for kClampToBorderNearest at the - // subset boundaries. - if (filterLogic[0] == FilterLogic::kClampToBorderNearest) { + // subset boundaries. Snap the input coordinates to nearest neighbor (with an + // epsilon) before comparing to the subset rect to avoid GPU interpolation errors + if (m[0] == ShaderMode::kClampToBorderNearest) { fb->codeAppendf( - "if (inCoord.x < %s.x || inCoord.x > %s.z) {" + "float snappedX = floor(inCoord.x + 0.001) + 0.5;" + "if (snappedX < %s.x || snappedX > %s.z) {" " textureColor = %s;" "}", subsetName, subsetName, borderName); } - if (filterLogic[1] == FilterLogic::kClampToBorderNearest) { + if (m[1] == ShaderMode::kClampToBorderNearest) { fb->codeAppendf( - "if (inCoord.y < %s.y || inCoord.y > %s.w) {" + "float snappedY = floor(inCoord.y + 0.001) + 0.5;" + "if (snappedY < %s.y || snappedY > %s.w) {" " textureColor = %s;" "}", subsetName, subsetName, borderName); @@ -708,10 +746,7 @@ GrGLSLFragmentProcessor* GrTextureEffect::onCreateGLSLInstance() const { void GrTextureEffect::onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const { auto m0 = static_cast<uint32_t>(fShaderModes[0]); auto m1 = static_cast<uint32_t>(fShaderModes[1]); - auto filter = fSampler.samplerState().filter(); - auto l0 = static_cast<uint32_t>(GetFilterLogic(fShaderModes[0], filter)); - auto l1 = static_cast<uint32_t>(GetFilterLogic(fShaderModes[1], filter)); - b->add32((l0 << 24) | (l1 << 16) | (m0 << 8) | m1); + b->add32((m0 << 16) | m1); } bool GrTextureEffect::onIsEqual(const GrFragmentProcessor& other) const { @@ -722,9 +757,7 @@ bool GrTextureEffect::onIsEqual(const GrFragmentProcessor& other) const { if (fSubset != that.fSubset) { return false; } - if ((fShaderModes[0] == ShaderMode::kClampToBorder || - fShaderModes[1] == ShaderMode::kClampToBorder) && - !std::equal(fBorder, fBorder + 4, that.fBorder)) { + if (this->hasClampToBorderShaderMode() && !std::equal(fBorder, fBorder + 4, that.fBorder)) { return false; } return true; diff --git a/chromium/third_party/skia/src/gpu/effects/GrTextureEffect.h b/chromium/third_party/skia/src/gpu/effects/GrTextureEffect.h index c808bfb3018..47acda81472 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrTextureEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/GrTextureEffect.h @@ -71,28 +71,24 @@ public: const char* name() const override { return "TextureEffect"; } private: - enum class ShaderMode : uint16_t { - kClamp = static_cast<int>(GrSamplerState::WrapMode::kClamp), - kRepeat = static_cast<int>(GrSamplerState::WrapMode::kRepeat), - kMirrorRepeat = static_cast<int>(GrSamplerState::WrapMode::kMirrorRepeat), - kClampToBorder = static_cast<int>(GrSamplerState::WrapMode::kClampToBorder), - kNone, - }; - struct Sampling; /** - * Sometimes the implementation of a ShaderMode depends on which GrSamplerState::Filter is - * used. + * Possible implementation of wrap mode in shader code. Some modes are specialized by + * filter. */ - enum class FilterLogic { - kNone, // The shader isn't specialized for the filter. + enum class ShaderMode : uint16_t { + kNone, // Using HW mode + kClamp, // Shader based clamp, no filter specialization + kRepeatNearest, // Simple repeat for nearest sampling kRepeatBilerp, // Filter across the subset boundary for kRepeat mode kRepeatMipMap, // Logic for LOD selection with kRepeat mode. - kClampToBorderFilter, // Logic for fading to border color when filtering. + kMirrorRepeat, // Mirror repeat (doesn't depend on filter)) kClampToBorderNearest, // Logic for hard transition to border color when not filtering. + kClampToBorderFilter, // Logic for fading to border color when filtering. }; - static FilterLogic GetFilterLogic(ShaderMode mode, GrSamplerState::Filter filter); + static ShaderMode GetShaderMode(GrSamplerState::WrapMode, GrSamplerState::Filter); + static bool ShaderModeIsClampToBorder(ShaderMode); GrCoordTransform fCoordTransform; TextureSampler fSampler; @@ -115,6 +111,11 @@ private: const TextureSampler& onTextureSampler(int) const override; + bool hasClampToBorderShaderMode() const { + return ShaderModeIsClampToBorder(fShaderModes[0]) || + ShaderModeIsClampToBorder(fShaderModes[1]); + } + GR_DECLARE_FRAGMENT_PROCESSOR_TEST typedef GrFragmentProcessor INHERITED; diff --git a/chromium/third_party/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp b/chromium/third_party/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp index 3d060a69fa9..fe09020845c 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrXfermodeFragmentProcessor.cpp @@ -62,8 +62,8 @@ private: SkBlendMode mode) : INHERITED(kComposeTwoFragmentProcessor_ClassID, OptFlags(src.get(), dst.get(), mode)) , fMode(mode) { - SkDEBUGCODE(int shaderAChildIndex = )this->registerChildProcessor(std::move(src)); - SkDEBUGCODE(int shaderBChildIndex = )this->registerChildProcessor(std::move(dst)); + SkDEBUGCODE(int shaderAChildIndex = )this->registerChild(std::move(src)); + SkDEBUGCODE(int shaderBChildIndex = )this->registerChild(std::move(dst)); SkASSERT(0 == shaderAChildIndex); SkASSERT(1 == shaderBChildIndex); } @@ -245,7 +245,7 @@ std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromTwoPro SkBlendMode mode) { switch (mode) { case SkBlendMode::kClear: - return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT, + return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT, GrConstColorProcessor::InputMode::kIgnore); case SkBlendMode::kSrc: return src; @@ -413,7 +413,7 @@ private: : INHERITED(kComposeOneFragmentProcessor_ClassID, OptFlags(fp.get(), mode, child)) , fMode(mode) , fChild(child) { - SkDEBUGCODE(int dstIndex =) this->registerChildProcessor(std::move(fp)); + SkDEBUGCODE(int dstIndex =) this->registerChild(std::move(fp)); SkASSERT(0 == dstIndex); } @@ -496,7 +496,7 @@ std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromDstPro std::unique_ptr<GrFragmentProcessor> dst, SkBlendMode mode) { switch (mode) { case SkBlendMode::kClear: - return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT, + return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT, GrConstColorProcessor::InputMode::kIgnore); case SkBlendMode::kSrc: return nullptr; @@ -510,7 +510,7 @@ std::unique_ptr<GrFragmentProcessor> GrXfermodeFragmentProcessor::MakeFromSrcPro std::unique_ptr<GrFragmentProcessor> src, SkBlendMode mode) { switch (mode) { case SkBlendMode::kClear: - return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT, + return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT, GrConstColorProcessor::InputMode::kIgnore); case SkBlendMode::kDst: return nullptr; diff --git a/chromium/third_party/skia/src/gpu/effects/GrYUVtoRGBEffect.cpp b/chromium/third_party/skia/src/gpu/effects/GrYUVtoRGBEffect.cpp index 114f54b2aa6..ad0584a72b3 100644 --- a/chromium/third_party/skia/src/gpu/effects/GrYUVtoRGBEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/GrYUVtoRGBEffect.cpp @@ -74,7 +74,7 @@ std::unique_ptr<GrFragmentProcessor> GrYUVtoRGBEffect::Make(GrSurfaceProxyView v dimensions.height() == yDimensions.height() / 2 + 1) { sy = 0.5f; } - *planeMatrix.writable() = SkMatrix::MakeScale(sx, sy); + *planeMatrix.writable() = SkMatrix::Scale(sx, sy); planeMatrix.writable()->preConcat(localMatrix); planeFilter = subsampledPlaneFilterMode; if (subset) { @@ -112,7 +112,7 @@ GrYUVtoRGBEffect::GrYUVtoRGBEffect(std::unique_ptr<GrFragmentProcessor> planeFPs ModulateForClampedSamplerOptFlags(alpha_type(yuvaIndices))) , fYUVColorSpace(yuvColorSpace) { for (int i = 0; i < numPlanes; ++i) { - this->registerChildProcessor(std::move(planeFPs[i])); + this->registerChild(std::move(planeFPs[i])); } std::copy_n(yuvaIndices, 4, fYUVAIndices); } @@ -251,10 +251,7 @@ bool GrYUVtoRGBEffect::onIsEqual(const GrFragmentProcessor& other) const { GrYUVtoRGBEffect::GrYUVtoRGBEffect(const GrYUVtoRGBEffect& src) : GrFragmentProcessor(kGrYUVtoRGBEffect_ClassID, src.optimizationFlags()) , fYUVColorSpace(src.fYUVColorSpace) { - int numPlanes = src.numChildProcessors(); - for (int i = 0; i < numPlanes; ++i) { - this->registerChildProcessor(this->childProcessor(i).clone()); - } + this->cloneAndRegisterAllChildProcessors(src); std::copy_n(src.fYUVAIndices, this->numChildProcessors(), fYUVAIndices); } diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrAARectEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrAARectEffect.cpp index 63f3a67364a..233c42a7d0e 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrAARectEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrAARectEffect.cpp @@ -28,34 +28,48 @@ public: auto rect = _outer.rect; (void)rect; prevRect = float4(-1.0); - rectUniformVar = args.fUniformHandler->addUniform( - &_outer, kFragment_GrShaderFlag, kFloat4_GrSLType, "rectUniform"); + rectUniformVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, + kFloat4_GrSLType, "rectUniform"); fragBuilder->codeAppendf( - "float4 prevRect = float4(%f, %f, %f, %f);\nhalf alpha;\n@switch (%d) {\n case " - "0:\n case 2:\n alpha = half(all(greaterThan(float4(sk_FragCoord.xy, " - "%s.zw), float4(%s.xy, sk_FragCoord.xy))) ? 1 : 0);\n break;\n " - "default:\n half xSub, ySub;\n xSub = min(half(sk_FragCoord.x - " - "%s.x), 0.0);\n xSub += min(half(%s.z - sk_FragCoord.x), 0.0);\n " - "ySub = min(half(sk_FragCoord.y - %s.y), 0.0);\n ySub += min(half(%s.w - " - "sk_FragCoord.y), 0.0);\n alpha = (1.0 + ", - prevRect.left(), - prevRect.top(), - prevRect.right(), - prevRect.bottom(), - (int)_outer.edgeType, - args.fUniformHandler->getUniformCStr(rectUniformVar), + R"SkSL(float4 prevRect = float4(%f, %f, %f, %f); +half alpha; +@switch (%d) { + case 0: + case 2: + alpha = half(all(greaterThan(float4(sk_FragCoord.xy, %s.zw), float4(%s.xy, sk_FragCoord.xy))) ? 1 : 0); + break; + default: + half xSub, ySub; + xSub = min(half(sk_FragCoord.x - %s.x), 0.0); + xSub += min(half(%s.z - sk_FragCoord.x), 0.0); + ySub = min(half(sk_FragCoord.y - %s.y), 0.0); + ySub += min(half(%s.w - sk_FragCoord.y), 0.0); + alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0)); +} +@if (%d == 2 || %d == 3) { + alpha = 1.0 - alpha; +})SkSL", + prevRect.left(), prevRect.top(), prevRect.right(), prevRect.bottom(), + (int)_outer.edgeType, args.fUniformHandler->getUniformCStr(rectUniformVar), args.fUniformHandler->getUniformCStr(rectUniformVar), args.fUniformHandler->getUniformCStr(rectUniformVar), args.fUniformHandler->getUniformCStr(rectUniformVar), args.fUniformHandler->getUniformCStr(rectUniformVar), - args.fUniformHandler->getUniformCStr(rectUniformVar)); + args.fUniformHandler->getUniformCStr(rectUniformVar), (int)_outer.edgeType, + (int)_outer.edgeType); + SkString _input1677(args.fInputColor); + SkString _sample1677; + if (_outer.inputFP_index >= 0) { + _sample1677 = this->invokeChild(_outer.inputFP_index, _input1677.c_str(), args); + } else { + _sample1677.swap(_input1677); + } fragBuilder->codeAppendf( - "max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));\n}\n@if (%d == 2 || %d == 3) {\n " - "alpha = 1.0 - alpha;\n}\n%s = %s * alpha;\n", - (int)_outer.edgeType, - (int)_outer.edgeType, - args.fOutputColor, - args.fInputColor); + R"SkSL( +half4 inputColor = %s; +%s = inputColor * alpha; +)SkSL", + _sample1677.c_str(), args.fOutputColor); } private: @@ -95,7 +109,11 @@ bool GrAARectEffect::onIsEqual(const GrFragmentProcessor& other) const { GrAARectEffect::GrAARectEffect(const GrAARectEffect& src) : INHERITED(kGrAARectEffect_ClassID, src.optimizationFlags()) , edgeType(src.edgeType) - , rect(src.rect) {} + , rect(src.rect) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } +} std::unique_ptr<GrFragmentProcessor> GrAARectEffect::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrAARectEffect(*this)); } @@ -111,7 +129,7 @@ std::unique_ptr<GrFragmentProcessor> GrAARectEffect::TestCreate(GrProcessorTestD GrClipEdgeType edgeType = static_cast<GrClipEdgeType>(d->fRandom->nextULessThan(kGrClipEdgeTypeCnt)); - fp = GrAARectEffect::Make(edgeType, rect); + fp = GrAARectEffect::Make(/*inputFP=*/nullptr, edgeType, rect); } while (nullptr == fp); return fp; } diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrAARectEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrAARectEffect.h index 42324b4c6dc..88891e443b5 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrAARectEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrAARectEffect.h @@ -10,28 +10,42 @@ **************************************************************************************************/ #ifndef GrAARectEffect_DEFINED #define GrAARectEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrAARectEffect : public GrFragmentProcessor { public: - static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, SkRect rect) { - return std::unique_ptr<GrFragmentProcessor>(new GrAARectEffect(edgeType, rect)); + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, + SkRect rect) { + return std::unique_ptr<GrFragmentProcessor>( + new GrAARectEffect(std::move(inputFP), edgeType, rect)); } GrAARectEffect(const GrAARectEffect& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "AARectEffect"; } + int inputFP_index = -1; GrClipEdgeType edgeType; SkRect rect; private: - GrAARectEffect(GrClipEdgeType edgeType, SkRect rect) + GrAARectEffect(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, + SkRect rect) : INHERITED(kGrAARectEffect_ClassID, - (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag) + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag) , edgeType(edgeType) - , rect(rect) {} + , rect(rect) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.cpp index 915684f1222..c9f7c7bf634 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.cpp @@ -10,15 +10,6 @@ **************************************************************************************************/ #include "GrAlphaThresholdFragmentProcessor.h" -inline GrFragmentProcessor::OptimizationFlags GrAlphaThresholdFragmentProcessor::optFlags( - float outerThreshold) { - if (outerThreshold >= 1.0) { - return kPreservesOpaqueInput_OptimizationFlag | - kCompatibleWithCoverageAsAlpha_OptimizationFlag; - } else { - return kCompatibleWithCoverageAsAlpha_OptimizationFlag; - } -} #include "src/gpu/GrTexture.h" #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" @@ -41,22 +32,34 @@ public: kHalf_GrSLType, "innerThreshold"); outerThresholdVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf_GrSLType, "outerThreshold"); - SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D( - args.fTransformedCoords[0].fVaryingPoint, _outer.sampleMatrix()); + SkString _input515(args.fInputColor); + SkString _sample515; + if (_outer.inputFP_index >= 0) { + _sample515 = this->invokeChild(_outer.inputFP_index, _input515.c_str(), args); + } else { + _sample515.swap(_input515); + } fragBuilder->codeAppendf( - "half4 color = %s;\nhalf4 mask_color = sample(%s, %s).%s;\nif (mask_color.w < 0.5) " - "{\n if (color.w > %s) {\n half scale = %s / color.w;\n color.xyz " - "*= scale;\n color.w = %s;\n }\n} else if (color.w < %s) {\n half " - "scale = %s / max(0.0010000000474974513, color.w);\n color.xyz *= scale;\n " - "color.w = %s;\n}\n%s = color;\n", - args.fInputColor, - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]), - sk_TransformedCoords2D_0.c_str(), - fragBuilder->getProgramBuilder() - ->samplerSwizzle(args.fTexSamplers[0]) - .asString() - .c_str(), - args.fUniformHandler->getUniformCStr(outerThresholdVar), + R"SkSL(half4 color = %s;)SkSL", _sample515.c_str()); + SkString _sample567; + _sample567 = this->invokeChild(_outer.maskFP_index, args); + fragBuilder->codeAppendf( + R"SkSL( +half4 mask_color = %s; +if (mask_color.w < 0.5) { + if (color.w > %s) { + half scale = %s / color.w; + color.xyz *= scale; + color.w = %s; + } +} else if (color.w < %s) { + half scale = %s / max(0.0010000000474974513, color.w); + color.xyz *= scale; + color.w = %s; +} +%s = color; +)SkSL", + _sample567.c_str(), args.fUniformHandler->getUniformCStr(outerThresholdVar), args.fUniformHandler->getUniformCStr(outerThresholdVar), args.fUniformHandler->getUniformCStr(outerThresholdVar), args.fUniformHandler->getUniformCStr(innerThresholdVar), @@ -85,7 +88,6 @@ void GrAlphaThresholdFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps bool GrAlphaThresholdFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const { const GrAlphaThresholdFragmentProcessor& that = other.cast<GrAlphaThresholdFragmentProcessor>(); (void)that; - if (mask != that.mask) return false; if (innerThreshold != that.innerThreshold) return false; if (outerThreshold != that.outerThreshold) return false; return true; @@ -93,37 +95,30 @@ bool GrAlphaThresholdFragmentProcessor::onIsEqual(const GrFragmentProcessor& oth GrAlphaThresholdFragmentProcessor::GrAlphaThresholdFragmentProcessor( const GrAlphaThresholdFragmentProcessor& src) : INHERITED(kGrAlphaThresholdFragmentProcessor_ClassID, src.optimizationFlags()) - , maskCoordTransform(src.maskCoordTransform) - , mask(src.mask) , innerThreshold(src.innerThreshold) , outerThreshold(src.outerThreshold) { - this->setTextureSamplerCnt(1); - this->addCoordTransform(&maskCoordTransform); + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } + { maskFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.maskFP_index)); } } std::unique_ptr<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrAlphaThresholdFragmentProcessor(*this)); } -const GrFragmentProcessor::TextureSampler& GrAlphaThresholdFragmentProcessor::onTextureSampler( - int index) const { - return IthTextureSampler(index, mask); -} GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrAlphaThresholdFragmentProcessor); #if GR_TEST_UTILS std::unique_ptr<GrFragmentProcessor> GrAlphaThresholdFragmentProcessor::TestCreate( GrProcessorTestData* testData) { - auto[maskView, ct, at] = testData->randomAlphaOnlyView(); - // Make the inner and outer thresholds be in (0, 1) exclusive and be sorted correctly. - float innerThresh = testData->fRandom->nextUScalar1() * .99f + 0.005f; - float outerThresh = testData->fRandom->nextUScalar1() * .99f + 0.005f; - const int kMaxWidth = 1000; - const int kMaxHeight = 1000; - uint32_t width = testData->fRandom->nextULessThan(kMaxWidth); - uint32_t height = testData->fRandom->nextULessThan(kMaxHeight); - uint32_t x = testData->fRandom->nextULessThan(kMaxWidth - width); - uint32_t y = testData->fRandom->nextULessThan(kMaxHeight - height); - SkIRect bounds = SkIRect::MakeXYWH(x, y, width, height); + // Make the inner and outer thresholds be in [0, 1]. + float outerThresh = testData->fRandom->nextUScalar1(); + float innerThresh = testData->fRandom->nextUScalar1(); + std::unique_ptr<GrFragmentProcessor> inputChild, maskChild; + if (testData->fRandom->nextBool()) { + inputChild = GrProcessorUnitTest::MakeChildFP(testData); + } + maskChild = GrProcessorUnitTest::MakeChildFP(testData); - return GrAlphaThresholdFragmentProcessor::Make(std::move(maskView), innerThresh, outerThresh, - bounds); + return GrAlphaThresholdFragmentProcessor::Make(std::move(inputChild), std::move(maskChild), + innerThresh, outerThresh); } #endif diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h b/chromium/third_party/skia/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h index c4de913733f..eeb9e9cfa51 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrAlphaThresholdFragmentProcessor.h @@ -10,50 +10,51 @@ **************************************************************************************************/ #ifndef GrAlphaThresholdFragmentProcessor_DEFINED #define GrAlphaThresholdFragmentProcessor_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrAlphaThresholdFragmentProcessor : public GrFragmentProcessor { public: - inline OptimizationFlags optFlags(float outerThreshold); - - static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView mask, + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + std::unique_ptr<GrFragmentProcessor> maskFP, float innerThreshold, - float outerThreshold, - const SkIRect& bounds) { + float outerThreshold) { return std::unique_ptr<GrFragmentProcessor>(new GrAlphaThresholdFragmentProcessor( - std::move(mask), innerThreshold, outerThreshold, bounds)); + std::move(inputFP), std::move(maskFP), innerThreshold, outerThreshold)); } GrAlphaThresholdFragmentProcessor(const GrAlphaThresholdFragmentProcessor& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "AlphaThresholdFragmentProcessor"; } - GrCoordTransform maskCoordTransform; - TextureSampler mask; + int inputFP_index = -1; + int maskFP_index = -1; float innerThreshold; float outerThreshold; private: - GrAlphaThresholdFragmentProcessor(GrSurfaceProxyView mask, + GrAlphaThresholdFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP, + std::unique_ptr<GrFragmentProcessor> maskFP, float innerThreshold, - float outerThreshold, - const SkIRect& bounds) - : INHERITED(kGrAlphaThresholdFragmentProcessor_ClassID, kNone_OptimizationFlags) - , maskCoordTransform( - SkMatrix::MakeTrans(SkIntToScalar(-bounds.x()), SkIntToScalar(-bounds.y())), - mask.proxy(), - mask.origin()) - , mask(std::move(mask)) + float outerThreshold) + : INHERITED(kGrAlphaThresholdFragmentProcessor_ClassID, + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + ((outerThreshold >= 1.0) ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags)) , innerThreshold(innerThreshold) , outerThreshold(outerThreshold) { - this->setTextureSamplerCnt(1); - this->addCoordTransform(&maskCoordTransform); + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + SkASSERT(maskFP); + maskFP_index = this->registerChild(std::move(maskFP)); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - const TextureSampler& onTextureSampler(int) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST typedef GrFragmentProcessor INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.cpp index 5c6dbc3db6f..3d5b7b12380 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.cpp @@ -26,12 +26,27 @@ public: (void)_outer; auto mode = _outer.mode; (void)mode; + SkString _input308(args.fInputColor); + SkString _sample308; + if (_outer.inputFP_index >= 0) { + _sample308 = this->invokeChild(_outer.inputFP_index, _input308.c_str(), args); + } else { + _sample308.swap(_input308); + } fragBuilder->codeAppendf( - "half factor = 1.0 - %s.w;\n@switch (%d) {\n case 0:\n factor = " - "exp((-factor * factor) * 4.0) - 0.017999999225139618;\n break;\n case " - "1:\n factor = smoothstep(1.0, 0.0, factor);\n break;\n}\n%s = " - "half4(factor);\n", - args.fInputColor, (int)_outer.mode, args.fOutputColor); + R"SkSL(half inputAlpha = %s.w; +half factor = 1.0 - inputAlpha; +@switch (%d) { + case 0: + factor = exp((-factor * factor) * 4.0) - 0.017999999225139618; + break; + case 1: + factor = smoothstep(1.0, 0.0, factor); + break; +} +%s = half4(factor); +)SkSL", + _sample308.c_str(), (int)_outer.mode, args.fOutputColor); } private: @@ -54,7 +69,11 @@ bool GrBlurredEdgeFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) GrBlurredEdgeFragmentProcessor::GrBlurredEdgeFragmentProcessor( const GrBlurredEdgeFragmentProcessor& src) : INHERITED(kGrBlurredEdgeFragmentProcessor_ClassID, src.optimizationFlags()) - , mode(src.mode) {} + , mode(src.mode) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } +} std::unique_ptr<GrFragmentProcessor> GrBlurredEdgeFragmentProcessor::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrBlurredEdgeFragmentProcessor(*this)); } diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.h b/chromium/third_party/skia/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.h index 188280327a9..d9c0c3b5516 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrBlurredEdgeFragmentProcessor.h @@ -10,26 +10,35 @@ **************************************************************************************************/ #ifndef GrBlurredEdgeFragmentProcessor_DEFINED #define GrBlurredEdgeFragmentProcessor_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrBlurredEdgeFragmentProcessor : public GrFragmentProcessor { public: enum class Mode { kGaussian = 0, kSmoothStep = 1 }; - static std::unique_ptr<GrFragmentProcessor> Make(Mode mode) { - return std::unique_ptr<GrFragmentProcessor>(new GrBlurredEdgeFragmentProcessor(mode)); + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + Mode mode) { + return std::unique_ptr<GrFragmentProcessor>( + new GrBlurredEdgeFragmentProcessor(std::move(inputFP), mode)); } GrBlurredEdgeFragmentProcessor(const GrBlurredEdgeFragmentProcessor& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "BlurredEdgeFragmentProcessor"; } + int inputFP_index = -1; Mode mode; private: - GrBlurredEdgeFragmentProcessor(Mode mode) + GrBlurredEdgeFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP, Mode mode) : INHERITED(kGrBlurredEdgeFragmentProcessor_ClassID, kNone_OptimizationFlags) - , mode(mode) {} + , mode(mode) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.cpp index 451dd98d0d4..67449dd8a54 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.cpp @@ -177,14 +177,14 @@ static void create_half_plane_profile(uint8_t* profile, int profileWidth) { profile[profileWidth - 1] = 0; } -static GrSurfaceProxyView create_profile_texture(GrRecordingContext* context, - const SkRect& circle, - float sigma, - float* solidRadius, - float* textureRadius) { +static std::unique_ptr<GrFragmentProcessor> create_profile_effect(GrRecordingContext* context, + const SkRect& circle, + float sigma, + float* solidRadius, + float* textureRadius) { float circleR = circle.width() / 2.0f; if (circleR < SK_ScalarNearlyZero) { - return {}; + return nullptr; } // Profile textures are cached by the ratio of sigma to circle radius and by the size of the // profile texture (binned by powers of 2). @@ -214,6 +214,12 @@ static GrSurfaceProxyView create_profile_texture(GrRecordingContext* context, *textureRadius = circleR + 3 * sigma; } + static constexpr int kProfileTextureWidth = 512; + // This would be kProfileTextureWidth/textureRadius if it weren't for the fact that we do + // the calculation of the profile coord in a coord space that has already been scaled by + // 1 / textureRadius. This is done to avoid overflow in length(). + SkMatrix texM = SkMatrix::Scale(kProfileTextureWidth, 1.f); + static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey key; GrUniqueKey::Builder builder(&key, kDomain, 1, "1-D Circular Blur"); @@ -224,14 +230,13 @@ static GrSurfaceProxyView create_profile_texture(GrRecordingContext* context, if (sk_sp<GrTextureProxy> blurProfile = proxyProvider->findOrCreateProxyByUniqueKey(key)) { GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(blurProfile->backendFormat(), GrColorType::kAlpha_8); - return {std::move(blurProfile), kTopLeft_GrSurfaceOrigin, swizzle}; + GrSurfaceProxyView profileView{std::move(blurProfile), kTopLeft_GrSurfaceOrigin, swizzle}; + return GrTextureEffect::Make(std::move(profileView), kPremul_SkAlphaType, texM); } - static constexpr int kProfileTextureWidth = 512; - SkBitmap bm; if (!bm.tryAllocPixels(SkImageInfo::MakeA8(kProfileTextureWidth, 1))) { - return {}; + return nullptr; } if (useHalfPlaneApprox) { @@ -246,25 +251,28 @@ static GrSurfaceProxyView create_profile_texture(GrRecordingContext* context, bm.setImmutable(); GrBitmapTextureMaker maker(context, bm, GrImageTexGenPolicy::kNew_Uncached_Budgeted); - auto blurView = maker.view(GrMipMapped::kNo); - if (!blurView) { - return {}; + auto profileView = maker.view(GrMipMapped::kNo); + if (!profileView) { + return nullptr; } - proxyProvider->assignUniqueKeyToProxy(key, blurView.asTextureProxy()); - return blurView; + proxyProvider->assignUniqueKeyToProxy(key, profileView.asTextureProxy()); + return GrTextureEffect::Make(std::move(profileView), kPremul_SkAlphaType, texM); } std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::Make( - GrRecordingContext* context, const SkRect& circle, float sigma) { + std::unique_ptr<GrFragmentProcessor> inputFP, + GrRecordingContext* context, + const SkRect& circle, + float sigma) { float solidRadius; float textureRadius; - GrSurfaceProxyView profile = - create_profile_texture(context, circle, sigma, &solidRadius, &textureRadius); + std::unique_ptr<GrFragmentProcessor> profile = + create_profile_effect(context, circle, sigma, &solidRadius, &textureRadius); if (!profile) { return nullptr; } return std::unique_ptr<GrFragmentProcessor>(new GrCircleBlurFragmentProcessor( - circle, textureRadius, solidRadius, std::move(profile))); + std::move(inputFP), circle, solidRadius, textureRadius, std::move(profile))); } #include "src/gpu/GrTexture.h" #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" @@ -282,28 +290,39 @@ public: (void)_outer; auto circleRect = _outer.circleRect; (void)circleRect; - auto textureRadius = _outer.textureRadius; - (void)textureRadius; auto solidRadius = _outer.solidRadius; (void)solidRadius; + auto textureRadius = _outer.textureRadius; + (void)textureRadius; circleDataVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf4_GrSLType, "circleData"); fragBuilder->codeAppendf( - "half2 vec = half2(half((sk_FragCoord.x - float(%s.x)) * float(%s.w)), " - "half((sk_FragCoord.y - float(%s.y)) * float(%s.w)));\nhalf dist = length(vec) + " - "(0.5 - %s.z) * %s.w;\n%s = %s * sample(%s, float2(half2(dist, 0.5))).%s.w;\n", - args.fUniformHandler->getUniformCStr(circleDataVar), - args.fUniformHandler->getUniformCStr(circleDataVar), + R"SkSL(; +half2 vec = half2((sk_FragCoord.xy - float2(%s.xy)) * float(%s.w)); +half dist = length(vec) + (0.5 - %s.z) * %s.w;)SkSL", args.fUniformHandler->getUniformCStr(circleDataVar), args.fUniformHandler->getUniformCStr(circleDataVar), args.fUniformHandler->getUniformCStr(circleDataVar), - args.fUniformHandler->getUniformCStr(circleDataVar), args.fOutputColor, - args.fInputColor, - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]), - fragBuilder->getProgramBuilder() - ->samplerSwizzle(args.fTexSamplers[0]) - .asString() - .c_str()); + args.fUniformHandler->getUniformCStr(circleDataVar)); + SkString _input13945(args.fInputColor); + SkString _sample13945; + if (_outer.inputFP_index >= 0) { + _sample13945 = this->invokeChild(_outer.inputFP_index, _input13945.c_str(), args); + } else { + _sample13945.swap(_input13945); + } + fragBuilder->codeAppendf( + R"SkSL( +half4 inputColor = %s;)SkSL", + _sample13945.c_str()); + SkString _sample14005; + SkString _coords14005("float2(half2(dist, 0.5))"); + _sample14005 = this->invokeChild(_outer.blurProfile_index, args, _coords14005.c_str()); + fragBuilder->codeAppendf( + R"SkSL( +%s = inputColor * %s.w; +)SkSL", + args.fOutputColor, _sample14005.c_str()); } private: @@ -312,13 +331,10 @@ private: const GrCircleBlurFragmentProcessor& _outer = _proc.cast<GrCircleBlurFragmentProcessor>(); auto circleRect = _outer.circleRect; (void)circleRect; - auto textureRadius = _outer.textureRadius; - (void)textureRadius; auto solidRadius = _outer.solidRadius; (void)solidRadius; - const GrSurfaceProxyView& blurProfileSamplerView = _outer.textureSampler(0).view(); - GrTexture& blurProfileSampler = *blurProfileSamplerView.proxy()->peekTexture(); - (void)blurProfileSampler; + auto textureRadius = _outer.textureRadius; + (void)textureRadius; UniformHandle& circleData = circleDataVar; (void)circleData; @@ -336,27 +352,27 @@ bool GrCircleBlurFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const GrCircleBlurFragmentProcessor& that = other.cast<GrCircleBlurFragmentProcessor>(); (void)that; if (circleRect != that.circleRect) return false; - if (textureRadius != that.textureRadius) return false; if (solidRadius != that.solidRadius) return false; - if (blurProfileSampler != that.blurProfileSampler) return false; + if (textureRadius != that.textureRadius) return false; return true; } GrCircleBlurFragmentProcessor::GrCircleBlurFragmentProcessor( const GrCircleBlurFragmentProcessor& src) : INHERITED(kGrCircleBlurFragmentProcessor_ClassID, src.optimizationFlags()) , circleRect(src.circleRect) - , textureRadius(src.textureRadius) , solidRadius(src.solidRadius) - , blurProfileSampler(src.blurProfileSampler) { - this->setTextureSamplerCnt(1); + , textureRadius(src.textureRadius) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } + { + blurProfile_index = + this->cloneAndRegisterChildProcessor(src.childProcessor(src.blurProfile_index)); + } } std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrCircleBlurFragmentProcessor(*this)); } -const GrFragmentProcessor::TextureSampler& GrCircleBlurFragmentProcessor::onTextureSampler( - int index) const { - return IthTextureSampler(index, blurProfileSampler); -} GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrCircleBlurFragmentProcessor); #if GR_TEST_UTILS std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::TestCreate( @@ -364,6 +380,7 @@ std::unique_ptr<GrFragmentProcessor> GrCircleBlurFragmentProcessor::TestCreate( SkScalar wh = testData->fRandom->nextRangeScalar(100.f, 1000.f); SkScalar sigma = testData->fRandom->nextRangeF(1.f, 10.f); SkRect circle = SkRect::MakeWH(wh, wh); - return GrCircleBlurFragmentProcessor::Make(testData->context(), circle, sigma); + return GrCircleBlurFragmentProcessor::Make(/*inputFP=*/nullptr, testData->context(), circle, + sigma); } #endif diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h b/chromium/third_party/skia/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h index b61315ac533..164ccdd8113 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrCircleBlurFragmentProcessor.h @@ -10,41 +10,52 @@ **************************************************************************************************/ #ifndef GrCircleBlurFragmentProcessor_DEFINED #define GrCircleBlurFragmentProcessor_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" + +#include "src/gpu/effects/GrTextureEffect.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrCircleBlurFragmentProcessor : public GrFragmentProcessor { public: - static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext*, + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrRecordingContext*, const SkRect& circle, float sigma); GrCircleBlurFragmentProcessor(const GrCircleBlurFragmentProcessor& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "CircleBlurFragmentProcessor"; } + int inputFP_index = -1; SkRect circleRect; - float textureRadius; float solidRadius; - TextureSampler blurProfileSampler; + float textureRadius; + int blurProfile_index = -1; private: - GrCircleBlurFragmentProcessor(SkRect circleRect, - float textureRadius, + GrCircleBlurFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP, + SkRect circleRect, float solidRadius, - GrSurfaceProxyView blurProfileSampler) + float textureRadius, + std::unique_ptr<GrFragmentProcessor> blurProfile) : INHERITED(kGrCircleBlurFragmentProcessor_ClassID, - (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag) + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag) , circleRect(circleRect) - , textureRadius(textureRadius) , solidRadius(solidRadius) - , blurProfileSampler(std::move(blurProfileSampler)) { - this->setTextureSamplerCnt(1); + , textureRadius(textureRadius) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + SkASSERT(blurProfile); + blurProfile_index = this->registerExplicitlySampledChild(std::move(blurProfile)); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - const TextureSampler& onTextureSampler(int) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST typedef GrFragmentProcessor INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrCircleEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrCircleEffect.cpp index 272d33234a5..f9df3c9fdcb 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrCircleEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrCircleEffect.cpp @@ -33,20 +33,39 @@ public: circleVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kFloat4_GrSLType, "circle"); fragBuilder->codeAppendf( - "float2 prevCenter;\nfloat prevRadius = %f;\nhalf d;\n@if (%d == 2 || %d == 3) {\n " - " d = half((length((%s.xy - sk_FragCoord.xy) * %s.w) - 1.0) * %s.z);\n} else {\n " - " d = half((1.0 - length((%s.xy - sk_FragCoord.xy) * %s.w)) * %s.z);\n}\n@if " - "((%d == 1 || %d == 3) || %d == 4) {\n %s = %s * clamp(d, 0.0, 1.0);\n} else " - "{\n %s = d > 0.5 ? %s : half4(0.0);\n}\n", + R"SkSL(float2 prevCenter; +float prevRadius = %f; +half d; +@if (%d == 2 || %d == 3) { + d = half((length((%s.xy - sk_FragCoord.xy) * %s.w) - 1.0) * %s.z); +} else { + d = half((1.0 - length((%s.xy - sk_FragCoord.xy) * %s.w)) * %s.z); +})SkSL", prevRadius, (int)_outer.edgeType, (int)_outer.edgeType, args.fUniformHandler->getUniformCStr(circleVar), args.fUniformHandler->getUniformCStr(circleVar), args.fUniformHandler->getUniformCStr(circleVar), args.fUniformHandler->getUniformCStr(circleVar), args.fUniformHandler->getUniformCStr(circleVar), - args.fUniformHandler->getUniformCStr(circleVar), (int)_outer.edgeType, - (int)_outer.edgeType, (int)_outer.edgeType, args.fOutputColor, args.fInputColor, - args.fOutputColor, args.fInputColor); + args.fUniformHandler->getUniformCStr(circleVar)); + SkString _input2509(args.fInputColor); + SkString _sample2509; + if (_outer.inputFP_index >= 0) { + _sample2509 = this->invokeChild(_outer.inputFP_index, _input2509.c_str(), args); + } else { + _sample2509.swap(_input2509); + } + fragBuilder->codeAppendf( + R"SkSL( +half4 inputColor = %s; +@if (%d == 1 || %d == 3) { + %s = inputColor * clamp(d, 0.0, 1.0); +} else { + %s = d > 0.5 ? inputColor : half4(0.0); +} +)SkSL", + _sample2509.c_str(), (int)_outer.edgeType, (int)_outer.edgeType, args.fOutputColor, + args.fOutputColor); } private: @@ -101,7 +120,11 @@ GrCircleEffect::GrCircleEffect(const GrCircleEffect& src) : INHERITED(kGrCircleEffect_ClassID, src.optimizationFlags()) , edgeType(src.edgeType) , center(src.center) - , radius(src.radius) {} + , radius(src.radius) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } +} std::unique_ptr<GrFragmentProcessor> GrCircleEffect::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(*this)); } @@ -112,10 +135,12 @@ std::unique_ptr<GrFragmentProcessor> GrCircleEffect::TestCreate(GrProcessorTestD center.fX = testData->fRandom->nextRangeScalar(0.f, 1000.f); center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f); SkScalar radius = testData->fRandom->nextRangeF(1.f, 1000.f); - GrClipEdgeType et; + bool success; + std::unique_ptr<GrFragmentProcessor> fp; do { - et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt); - } while (GrClipEdgeType::kHairlineAA == et); - return GrCircleEffect::Make(et, center, radius); + GrClipEdgeType et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt); + std::tie(success, fp) = GrCircleEffect::Make(/*inputFP=*/nullptr, et, center, radius); + } while (!success); + return fp; } #endif diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrCircleEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrCircleEffect.h index b20412c70ae..ded95ae941f 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrCircleEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrCircleEffect.h @@ -10,37 +10,51 @@ **************************************************************************************************/ #ifndef GrCircleEffect_DEFINED #define GrCircleEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrCircleEffect : public GrFragmentProcessor { public: - static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, - SkPoint center, - float radius) { + static GrFPResult Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, + SkPoint center, + float radius) { // A radius below half causes the implicit insetting done by this processor to become // inverted. We could handle this case by making the processor code more complicated. if (radius < .5f && GrProcessorEdgeTypeIsInverseFill(edgeType)) { - return nullptr; + return GrFPFailure(std::move(inputFP)); } - return std::unique_ptr<GrFragmentProcessor>(new GrCircleEffect(edgeType, center, radius)); + return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>( + new GrCircleEffect(std::move(inputFP), edgeType, center, radius))); } GrCircleEffect(const GrCircleEffect& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "CircleEffect"; } + int inputFP_index = -1; GrClipEdgeType edgeType; SkPoint center; float radius; private: - GrCircleEffect(GrClipEdgeType edgeType, SkPoint center, float radius) + GrCircleEffect(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, + SkPoint center, + float radius) : INHERITED(kGrCircleEffect_ClassID, - (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag) + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag) , edgeType(edgeType) , center(center) - , radius(radius) {} + , radius(radius) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrClampFragmentProcessor.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrClampFragmentProcessor.cpp index 7d692b52de2..f218bf889db 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrClampFragmentProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrClampFragmentProcessor.cpp @@ -25,11 +25,24 @@ public: (void)_outer; auto clampToPremul = _outer.clampToPremul; (void)clampToPremul; + SkString _input464(args.fInputColor); + SkString _sample464; + if (_outer.inputFP_index >= 0) { + _sample464 = this->invokeChild(_outer.inputFP_index, _input464.c_str(), args); + } else { + _sample464.swap(_input464); + } fragBuilder->codeAppendf( - "@if (%s) {\n half alpha = clamp(%s.w, 0.0, 1.0);\n %s = half4(clamp(%s.xyz, " - "0.0, alpha), alpha);\n} else {\n %s = clamp(%s, 0.0, 1.0);\n}\n", - (_outer.clampToPremul ? "true" : "false"), args.fInputColor, args.fOutputColor, - args.fInputColor, args.fOutputColor, args.fInputColor); + R"SkSL(half4 inputColor = %s; +@if (%s) { + half alpha = clamp(inputColor.w, 0.0, 1.0); + %s = half4(clamp(inputColor.xyz, 0.0, alpha), alpha); +} else { + %s = clamp(inputColor, 0.0, 1.0); +} +)SkSL", + _sample464.c_str(), (_outer.clampToPremul ? "true" : "false"), args.fOutputColor, + args.fOutputColor); } private: @@ -51,13 +64,17 @@ bool GrClampFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const } GrClampFragmentProcessor::GrClampFragmentProcessor(const GrClampFragmentProcessor& src) : INHERITED(kGrClampFragmentProcessor_ClassID, src.optimizationFlags()) - , clampToPremul(src.clampToPremul) {} + , clampToPremul(src.clampToPremul) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } +} std::unique_ptr<GrFragmentProcessor> GrClampFragmentProcessor::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrClampFragmentProcessor(*this)); } GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrClampFragmentProcessor); #if GR_TEST_UTILS std::unique_ptr<GrFragmentProcessor> GrClampFragmentProcessor::TestCreate(GrProcessorTestData* d) { - return GrClampFragmentProcessor::Make(d->fRandom->nextBool()); + return GrClampFragmentProcessor::Make(/*inputFP=*/nullptr, d->fRandom->nextBool()); } #endif diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrClampFragmentProcessor.h b/chromium/third_party/skia/src/gpu/effects/generated/GrClampFragmentProcessor.h index 61dc3a03d60..795555a7d18 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrClampFragmentProcessor.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrClampFragmentProcessor.h @@ -10,33 +10,47 @@ **************************************************************************************************/ #ifndef GrClampFragmentProcessor_DEFINED #define GrClampFragmentProcessor_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrClampFragmentProcessor : public GrFragmentProcessor { public: - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { + SkPMColor4f input = this->numChildProcessors() ? ConstantOutputForConstantInput( + this->childProcessor(0), inColor) + : inColor; float clampedAlpha = SkTPin(input.fA, 0.f, 1.f); float clampVal = clampToPremul ? clampedAlpha : 1.f; return {SkTPin(input.fR, 0.f, clampVal), SkTPin(input.fG, 0.f, clampVal), SkTPin(input.fB, 0.f, clampVal), clampedAlpha}; } - static std::unique_ptr<GrFragmentProcessor> Make(bool clampToPremul) { - return std::unique_ptr<GrFragmentProcessor>(new GrClampFragmentProcessor(clampToPremul)); + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + bool clampToPremul) { + return std::unique_ptr<GrFragmentProcessor>( + new GrClampFragmentProcessor(std::move(inputFP), clampToPremul)); } GrClampFragmentProcessor(const GrClampFragmentProcessor& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "ClampFragmentProcessor"; } + int inputFP_index = -1; bool clampToPremul; private: - GrClampFragmentProcessor(bool clampToPremul) + GrClampFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP, bool clampToPremul) : INHERITED(kGrClampFragmentProcessor_ClassID, - (OptimizationFlags)kConstantOutputForConstantInput_OptimizationFlag | - kPreservesOpaqueInput_OptimizationFlag) - , clampToPremul(clampToPremul) {} + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + (kConstantOutputForConstantInput_OptimizationFlag | + kPreservesOpaqueInput_OptimizationFlag)) + , clampToPremul(clampToPremul) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp index 1f3091a88dd..ad8eca849ca 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp @@ -38,13 +38,35 @@ public: "m"); vVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf4_GrSLType, "v"); + SkString _input585(args.fInputColor); + SkString _sample585; + if (_outer.inputFP_index >= 0) { + _sample585 = this->invokeChild(_outer.inputFP_index, _input585.c_str(), args); + } else { + _sample585.swap(_input585); + } fragBuilder->codeAppendf( - "half4 inputColor = %s;\n@if (%s) {\n half nonZeroAlpha = max(inputColor.w, " - "9.9999997473787516e-05);\n inputColor = half4(inputColor.xyz / nonZeroAlpha, " - "inputColor.w);\n}\n%s = %s * inputColor + %s;\n@if (%s) {\n %s = clamp(%s, " - "0.0, 1.0);\n} else {\n %s.w = clamp(%s.w, 0.0, 1.0);\n}\n@if (%s) {\n " - "%s.xyz *= %s.w;\n}\n", - args.fInputColor, (_outer.unpremulInput ? "true" : "false"), args.fOutputColor, + R"SkSL(half4 inputColor = %s; +@if (%s) { + half4 inlineResult0; + half4 inlineArg1_0 = inputColor; + { + inlineResult0 = half4(inlineArg1_0.xyz / max(inlineArg1_0.w, 9.9999997473787516e-05), inlineArg1_0.w); + } + inputColor = inlineResult0; + +} +%s = %s * inputColor + %s; +@if (%s) { + %s = clamp(%s, 0.0, 1.0); +} else { + %s.w = clamp(%s.w, 0.0, 1.0); +} +@if (%s) { + %s.xyz *= %s.w; +} +)SkSL", + _sample585.c_str(), (_outer.unpremulInput ? "true" : "false"), args.fOutputColor, args.fUniformHandler->getUniformCStr(mVar), args.fUniformHandler->getUniformCStr(vVar), (_outer.clampRGBOutput ? "true" : "false"), args.fOutputColor, args.fOutputColor, @@ -100,7 +122,11 @@ GrColorMatrixFragmentProcessor::GrColorMatrixFragmentProcessor( , v(src.v) , unpremulInput(src.unpremulInput) , clampRGBOutput(src.clampRGBOutput) - , premulOutput(src.premulOutput) {} + , premulOutput(src.premulOutput) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } +} std::unique_ptr<GrFragmentProcessor> GrColorMatrixFragmentProcessor::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrColorMatrixFragmentProcessor(*this)); } @@ -115,6 +141,6 @@ std::unique_ptr<GrFragmentProcessor> GrColorMatrixFragmentProcessor::TestCreate( bool unpremul = d->fRandom->nextBool(); bool clampRGB = d->fRandom->nextBool(); bool premul = d->fRandom->nextBool(); - return Make(m, unpremul, clampRGB, premul); + return Make(/*inputFP=*/nullptr, m, unpremul, clampRGB, premul); } #endif diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h b/chromium/third_party/skia/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h index e8fa784cabf..4160af95949 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.h @@ -10,14 +10,19 @@ **************************************************************************************************/ #ifndef GrColorMatrixFragmentProcessor_DEFINED #define GrColorMatrixFragmentProcessor_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrColorMatrixFragmentProcessor : public GrFragmentProcessor { public: - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { + SkPMColor4f input = this->numChildProcessors() ? ConstantOutputForConstantInput( + this->childProcessor(0), inColor) + : inColor; SkColor4f color; if (unpremulInput) { color = input.unpremul(); @@ -42,7 +47,8 @@ public: } } - static std::unique_ptr<GrFragmentProcessor> Make(const float matrix[20], + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + const float matrix[20], bool unpremulInput, bool clampRGBOutput, bool premulOutput) { @@ -51,11 +57,12 @@ public: matrix[17], matrix[18]); SkV4 v4 = {matrix[4], matrix[9], matrix[14], matrix[19]}; return std::unique_ptr<GrFragmentProcessor>(new GrColorMatrixFragmentProcessor( - m44, v4, unpremulInput, clampRGBOutput, premulOutput)); + std::move(inputFP), m44, v4, unpremulInput, clampRGBOutput, premulOutput)); } GrColorMatrixFragmentProcessor(const GrColorMatrixFragmentProcessor& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "ColorMatrixFragmentProcessor"; } + int inputFP_index = -1; SkM44 m; SkV4 v; bool unpremulInput; @@ -63,15 +70,25 @@ public: bool premulOutput; private: - GrColorMatrixFragmentProcessor( - SkM44 m, SkV4 v, bool unpremulInput, bool clampRGBOutput, bool premulOutput) + GrColorMatrixFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP, + SkM44 m, + SkV4 v, + bool unpremulInput, + bool clampRGBOutput, + bool premulOutput) : INHERITED(kGrColorMatrixFragmentProcessor_ClassID, - (OptimizationFlags)kConstantOutputForConstantInput_OptimizationFlag) + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + kConstantOutputForConstantInput_OptimizationFlag) , m(m) , v(v) , unpremulInput(unpremulInput) , clampRGBOutput(clampRGBOutput) - , premulOutput(premulOutput) {} + , premulOutput(premulOutput) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrComposeLerpEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrComposeLerpEffect.cpp index 78aabacb90d..3a4a323672d 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrComposeLerpEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrComposeLerpEffect.cpp @@ -39,11 +39,12 @@ public: } else { _sample358 = "half4(1)"; } - fragBuilder->codeAppendf("%s = mix(%s ? %s : %s, %s ? %s : %s, half(%s));\n", - args.fOutputColor, _outer.child1_index >= 0 ? "true" : "false", - _sample290.c_str(), args.fInputColor, - _outer.child2_index >= 0 ? "true" : "false", _sample358.c_str(), - args.fInputColor, args.fUniformHandler->getUniformCStr(weightVar)); + fragBuilder->codeAppendf( + R"SkSL(%s = mix(%s ? %s : %s, %s ? %s : %s, half(%s)); +)SkSL", + args.fOutputColor, _outer.child1_index >= 0 ? "true" : "false", _sample290.c_str(), + args.fInputColor, _outer.child2_index >= 0 ? "true" : "false", _sample358.c_str(), + args.fInputColor, args.fUniformHandler->getUniformCStr(weightVar)); } private: @@ -66,23 +67,12 @@ bool GrComposeLerpEffect::onIsEqual(const GrFragmentProcessor& other) const { return true; } GrComposeLerpEffect::GrComposeLerpEffect(const GrComposeLerpEffect& src) - : INHERITED(kGrComposeLerpEffect_ClassID, src.optimizationFlags()) - , child1_index(src.child1_index) - , child2_index(src.child2_index) - , weight(src.weight) { - if (child1_index >= 0) { - auto clone = src.childProcessor(child1_index).clone(); - if (src.childProcessor(child1_index).isSampledWithExplicitCoords()) { - clone->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(clone)); + : INHERITED(kGrComposeLerpEffect_ClassID, src.optimizationFlags()), weight(src.weight) { + if (src.child1_index >= 0) { + child1_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.child1_index)); } - if (child2_index >= 0) { - auto clone = src.childProcessor(child2_index).clone(); - if (src.childProcessor(child2_index).isSampledWithExplicitCoords()) { - clone->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(clone)); + if (src.child2_index >= 0) { + child2_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.child2_index)); } } std::unique_ptr<GrFragmentProcessor> GrComposeLerpEffect::clone() const { diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrComposeLerpEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrComposeLerpEffect.h index d1fb0ff42cb..1f9d225043f 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrComposeLerpEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrComposeLerpEffect.h @@ -10,11 +10,13 @@ **************************************************************************************************/ #ifndef GrComposeLerpEffect_DEFINED #define GrComposeLerpEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrComposeLerpEffect : public GrFragmentProcessor { public: static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> child1, @@ -36,12 +38,10 @@ private: float weight) : INHERITED(kGrComposeLerpEffect_ClassID, kNone_OptimizationFlags), weight(weight) { if (child1) { - child1_index = this->numChildProcessors(); - this->registerChildProcessor(std::move(child1)); + child1_index = this->registerChild(std::move(child1)); } if (child2) { - child2_index = this->numChildProcessors(); - this->registerChildProcessor(std::move(child2)); + child2_index = this->registerChild(std::move(child2)); } } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrConfigConversionEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrConfigConversionEffect.cpp index 9a3e9877d31..0ec66fd31d0 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrConfigConversionEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrConfigConversionEffect.cpp @@ -28,10 +28,16 @@ public: fragBuilder->forceHighPrecision(); fragBuilder->codeAppendf( - "%s = floor(%s * 255.0 + 0.5) / 255.0;\n@switch (%d) {\n case 0:\n " - "%s.xyz = floor((%s.xyz * %s.w) * 255.0 + 0.5) / 255.0;\n break;\n case " - "1:\n %s.xyz = %s.w <= 0.0 ? half3(0.0) : floor((%s.xyz / %s.w) * 255.0 + " - "0.5) / 255.0;\n break;\n}\n", + R"SkSL(%s = floor(%s * 255.0 + 0.5) / 255.0; +@switch (%d) { + case 0: + %s.xyz = floor((%s.xyz * %s.w) * 255.0 + 0.5) / 255.0; + break; + case 1: + %s.xyz = %s.w <= 0.0 ? half3(0.0) : floor((%s.xyz / %s.w) * 255.0 + 0.5) / 255.0; + break; +} +)SkSL", args.fOutputColor, args.fInputColor, (int)_outer.pmConversion, args.fOutputColor, args.fOutputColor, args.fOutputColor, args.fOutputColor, args.fOutputColor, args.fOutputColor, args.fOutputColor); diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrConfigConversionEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrConfigConversionEffect.h index f6172b9e35d..129c21dd17f 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrConfigConversionEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrConfigConversionEffect.h @@ -10,18 +10,19 @@ **************************************************************************************************/ #ifndef GrConfigConversionEffect_DEFINED #define GrConfigConversionEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "include/gpu/GrContext.h" #include "src/gpu/GrBitmapTextureMaker.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrImageInfo.h" #include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrConfigConversionEffect : public GrFragmentProcessor { public: static bool TestForPreservingPMConversions(GrContext* context) { @@ -93,8 +94,7 @@ public: paint1.addColorFragmentProcessor(pmToUPM->clone()); paint1.setPorterDuffXPFactory(SkBlendMode::kSrc); - readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect, - kRect); + readRTC->fillRectToRect(nullptr, std::move(paint1), GrAA::kNo, SkMatrix::I(), kRect, kRect); if (!readRTC->readPixels(ii, firstRead, 0, {0, 0})) { return false; } @@ -108,16 +108,14 @@ public: paint2.addColorFragmentProcessor(std::move(upmToPM)); paint2.setPorterDuffXPFactory(SkBlendMode::kSrc); - tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect, - kRect); + tempRTC->fillRectToRect(nullptr, std::move(paint2), GrAA::kNo, SkMatrix::I(), kRect, kRect); paint3.addColorFragmentProcessor( GrTextureEffect::Make(tempRTC->readSurfaceView(), kPremul_SkAlphaType)); paint3.addColorFragmentProcessor(std::move(pmToUPM)); paint3.setPorterDuffXPFactory(SkBlendMode::kSrc); - readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect, - kRect); + readRTC->fillRectToRect(nullptr, std::move(paint3), GrAA::kNo, SkMatrix::I(), kRect, kRect); if (!readRTC->readPixels(ii, secondRead, 0, {0, 0})) { return false; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrConstColorProcessor.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrConstColorProcessor.cpp index 22079b65a21..50b4b749e23 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrConstColorProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrConstColorProcessor.cpp @@ -30,12 +30,49 @@ public: colorVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf4_GrSLType, "color"); fragBuilder->codeAppendf( - "@switch (%d) {\n case 0:\n %s = %s;\n break;\n case 1:\n " - " %s = %s * %s;\n break;\n case 2:\n %s = %s.w * %s;\n " - "break;\n}\n", - (int)_outer.mode, args.fOutputColor, args.fUniformHandler->getUniformCStr(colorVar), - args.fOutputColor, args.fInputColor, args.fUniformHandler->getUniformCStr(colorVar), - args.fOutputColor, args.fInputColor, + R"SkSL(@switch (%d) { + case 0: + { + %s = %s; + break; + } + case 1: + {)SkSL", + (int)_outer.mode, args.fOutputColor, + args.fUniformHandler->getUniformCStr(colorVar)); + SkString _input1009(args.fInputColor); + SkString _sample1009; + if (_outer.inputFP_index >= 0) { + _sample1009 = this->invokeChild(_outer.inputFP_index, _input1009.c_str(), args); + } else { + _sample1009.swap(_input1009); + } + fragBuilder->codeAppendf( + R"SkSL( + half4 inputColor = %s; + %s = inputColor * %s; + break; + } + case 2: + {)SkSL", + _sample1009.c_str(), args.fOutputColor, + args.fUniformHandler->getUniformCStr(colorVar)); + SkString _input1181(args.fInputColor); + SkString _sample1181; + if (_outer.inputFP_index >= 0) { + _sample1181 = this->invokeChild(_outer.inputFP_index, _input1181.c_str(), args); + } else { + _sample1181.swap(_input1181); + } + fragBuilder->codeAppendf( + R"SkSL( + half inputAlpha = %s.w; + %s = inputAlpha * %s; + break; + } +} +)SkSL", + _sample1181.c_str(), args.fOutputColor, args.fUniformHandler->getUniformCStr(colorVar)); } @@ -71,7 +108,11 @@ bool GrConstColorProcessor::onIsEqual(const GrFragmentProcessor& other) const { GrConstColorProcessor::GrConstColorProcessor(const GrConstColorProcessor& src) : INHERITED(kGrConstColorProcessor_ClassID, src.optimizationFlags()) , color(src.color) - , mode(src.mode) {} + , mode(src.mode) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } +} std::unique_ptr<GrFragmentProcessor> GrConstColorProcessor::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrConstColorProcessor(*this)); } @@ -98,6 +139,6 @@ std::unique_ptr<GrFragmentProcessor> GrConstColorProcessor::TestCreate(GrProcess break; } InputMode mode = static_cast<InputMode>(d->fRandom->nextULessThan(kInputModeCnt)); - return GrConstColorProcessor::Make(color, mode); + return GrConstColorProcessor::Make(/*inputFP=*/nullptr, color, mode); } #endif diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrConstColorProcessor.h b/chromium/third_party/skia/src/gpu/effects/generated/GrConstColorProcessor.h index 6d84f836cf2..e9b8b86c5cc 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrConstColorProcessor.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrConstColorProcessor.h @@ -10,53 +10,73 @@ **************************************************************************************************/ #ifndef GrConstColorProcessor_DEFINED #define GrConstColorProcessor_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrConstColorProcessor : public GrFragmentProcessor { public: enum class InputMode { kIgnore = 0, kLast = 2, kModulateA = 2, kModulateRGBA = 1 }; static const int kInputModeCnt = (int)InputMode::kLast + 1; - static OptimizationFlags OptFlags(const SkPMColor4f& color, InputMode mode) { - OptimizationFlags flags = kConstantOutputForConstantInput_OptimizationFlag; - if (mode != InputMode::kIgnore) { - flags |= kCompatibleWithCoverageAsAlpha_OptimizationFlag; - } - if (color.isOpaque()) { - flags |= kPreservesOpaqueInput_OptimizationFlag; - } - return flags; - } - - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { switch (mode) { - case InputMode::kIgnore: + case InputMode::kIgnore: { return color; - case InputMode::kModulateA: + } + case InputMode::kModulateA: { + SkPMColor4f input = this->numChildProcessors() + ? ConstantOutputForConstantInput( + this->childProcessor(inputFP_index), inColor) + : inColor; return color * input.fA; - case InputMode::kModulateRGBA: + } + case InputMode::kModulateRGBA: { + SkPMColor4f input = this->numChildProcessors() + ? ConstantOutputForConstantInput( + this->childProcessor(inputFP_index), inColor) + : inColor; return color * input; + } } - SK_ABORT("Unexpected mode"); + SkUNREACHABLE; } - static std::unique_ptr<GrFragmentProcessor> Make(SkPMColor4f color, InputMode mode) { - return std::unique_ptr<GrFragmentProcessor>(new GrConstColorProcessor(color, mode)); + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + SkPMColor4f color, + InputMode mode) { + return std::unique_ptr<GrFragmentProcessor>( + new GrConstColorProcessor(std::move(inputFP), color, mode)); } GrConstColorProcessor(const GrConstColorProcessor& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "ConstColorProcessor"; } + int inputFP_index = -1; SkPMColor4f color; InputMode mode; private: - GrConstColorProcessor(SkPMColor4f color, InputMode mode) - : INHERITED(kGrConstColorProcessor_ClassID, (OptimizationFlags)OptFlags(color, mode)) + GrConstColorProcessor(std::unique_ptr<GrFragmentProcessor> inputFP, + SkPMColor4f color, + InputMode mode) + : INHERITED(kGrConstColorProcessor_ClassID, + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + (kConstantOutputForConstantInput_OptimizationFlag | + ((mode != InputMode::kIgnore) + ? kCompatibleWithCoverageAsAlpha_OptimizationFlag + : kNone_OptimizationFlags) | + ((color.isOpaque()) ? kPreservesOpaqueInput_OptimizationFlag + : kNone_OptimizationFlags))) , color(color) - , mode(mode) {} + , mode(mode) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrDeviceSpaceEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrDeviceSpaceEffect.cpp index be9e92c6ecf..4fec9b1ab0d 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrDeviceSpaceEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrDeviceSpaceEffect.cpp @@ -23,17 +23,32 @@ public: GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrDeviceSpaceEffect& _outer = args.fFp.cast<GrDeviceSpaceEffect>(); (void)_outer; - SkString _input204 = SkStringPrintf("%s", args.fInputColor); - SkString _sample204; - SkString _coords204("sk_FragCoord.xy"); - _sample204 = - this->invokeChild(_outer.fp_index, _input204.c_str(), args, _coords204.c_str()); - fragBuilder->codeAppendf("%s = %s;\n", args.fOutputColor, _sample204.c_str()); + auto matrix = _outer.matrix; + (void)matrix; + matrixVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, + kFloat3x3_GrSLType, "matrix"); + fragBuilder->codeAppendf( + R"SkSL(float3 p = %s * float3(sk_FragCoord.xy, 1);)SkSL", + args.fUniformHandler->getUniformCStr(matrixVar)); + SkString _input276(args.fInputColor); + SkString _sample276; + SkString _coords276("p.xy / p.z"); + _sample276 = + this->invokeChild(_outer.fp_index, _input276.c_str(), args, _coords276.c_str()); + fragBuilder->codeAppendf( + R"SkSL( +%s = %s; +)SkSL", + args.fOutputColor, _sample276.c_str()); } private: void onSetData(const GrGLSLProgramDataManager& pdman, - const GrFragmentProcessor& _proc) override {} + const GrFragmentProcessor& _proc) override { + const GrDeviceSpaceEffect& _outer = _proc.cast<GrDeviceSpaceEffect>(); + { pdman.setSkMatrix(matrixVar, (_outer.matrix)); } + } + UniformHandle matrixVar; }; GrGLSLFragmentProcessor* GrDeviceSpaceEffect::onCreateGLSLInstance() const { return new GrGLSLDeviceSpaceEffect(); @@ -43,17 +58,12 @@ void GrDeviceSpaceEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, bool GrDeviceSpaceEffect::onIsEqual(const GrFragmentProcessor& other) const { const GrDeviceSpaceEffect& that = other.cast<GrDeviceSpaceEffect>(); (void)that; + if (matrix != that.matrix) return false; return true; } GrDeviceSpaceEffect::GrDeviceSpaceEffect(const GrDeviceSpaceEffect& src) - : INHERITED(kGrDeviceSpaceEffect_ClassID, src.optimizationFlags()), fp_index(src.fp_index) { - { - auto clone = src.childProcessor(fp_index).clone(); - if (src.childProcessor(fp_index).isSampledWithExplicitCoords()) { - clone->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(clone)); - } + : INHERITED(kGrDeviceSpaceEffect_ClassID, src.optimizationFlags()), matrix(src.matrix) { + { fp_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.fp_index)); } } std::unique_ptr<GrFragmentProcessor> GrDeviceSpaceEffect::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrDeviceSpaceEffect(*this)); diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrDeviceSpaceEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrDeviceSpaceEffect.h index e08d29d892d..c7e4f2439aa 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrDeviceSpaceEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrDeviceSpaceEffect.h @@ -10,28 +10,30 @@ **************************************************************************************************/ #ifndef GrDeviceSpaceEffect_DEFINED #define GrDeviceSpaceEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrDeviceSpaceEffect : public GrFragmentProcessor { public: - static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) { - return std::unique_ptr<GrFragmentProcessor>(new GrDeviceSpaceEffect(std::move(fp))); + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp, + const SkMatrix& matrix = SkMatrix::I()) { + return std::unique_ptr<GrFragmentProcessor>(new GrDeviceSpaceEffect(std::move(fp), matrix)); } GrDeviceSpaceEffect(const GrDeviceSpaceEffect& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "DeviceSpaceEffect"; } int fp_index = -1; + SkMatrix matrix; private: - GrDeviceSpaceEffect(std::unique_ptr<GrFragmentProcessor> fp) - : INHERITED(kGrDeviceSpaceEffect_ClassID, kNone_OptimizationFlags) { + GrDeviceSpaceEffect(std::unique_ptr<GrFragmentProcessor> fp, SkMatrix matrix) + : INHERITED(kGrDeviceSpaceEffect_ClassID, kNone_OptimizationFlags), matrix(matrix) { SkASSERT(fp); - fp_index = this->numChildProcessors(); - fp->setSampledWithExplicitCoords(); - this->registerChildProcessor(std::move(fp)); + fp_index = this->registerExplicitlySampledChild(std::move(fp)); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrEllipseEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrEllipseEffect.cpp index fa349032589..0a75b96dd8e 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrEllipseEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrEllipseEffect.cpp @@ -38,26 +38,61 @@ public: kFloat2_GrSLType, "scale"); } fragBuilder->codeAppendf( - "float2 prevCenter;\nfloat2 prevRadii = float2(%f, %f);\nbool medPrecision = " - "%s;\nfloat2 d = sk_FragCoord.xy - %s.xy;\n@if (medPrecision) {\n d *= " - "%s.y;\n}\nfloat2 Z = d * %s.zw;\nfloat implicit = dot(Z, d) - 1.0;\nfloat " - "grad_dot = 4.0 * dot(Z, Z);\n@if (medPrecision) {\n grad_dot = max(grad_dot, " - "6.1036000261083245e-05);\n} else {\n grad_dot = max(grad_dot, " - "1.1754999560161448e-38);\n}\nfloat approx_dist = implicit * " - "inversesqrt(grad_dot);\n@if (medPrecision) {\n approx_dist *= %s.x;\n}\nhalf " - "alph", + R"SkSL(float2 prevCenter; +float2 prevRadii = float2(%f, %f); +bool medPrecision = %s; +float2 d = sk_FragCoord.xy - %s.xy; +@if (medPrecision) { + d *= %s.y; +} +float2 Z = d * %s.zw; +float implicit = dot(Z, d) - 1.0; +float grad_dot = 4.0 * dot(Z, Z); +@if (medPrecision) { + grad_dot = max(grad_dot, 6.1036000261083245e-05); +} else { + grad_dot = max(grad_dot, 1.1754999560161448e-38); +} +float approx_dist = implicit * inversesqrt(grad_dot); +@if (medPrecision) { + approx_dist *= %s.x; +} +half alpha; +@switch (%d) { + case 0: + alpha = approx_dist > 0.0 ? 0.0 : 1.0; + break; + case 1: + alpha = clamp(0.5 - half(approx_dist), 0.0, 1.0); + break; + case 2: + alpha = approx_dist > 0.0 ? 1.0 : 0.0; + break; + case 3: + alpha = clamp(0.5 + half(approx_dist), 0.0, 1.0); + break; + default: + discard; +})SkSL", prevRadii.fX, prevRadii.fY, (medPrecision ? "true" : "false"), args.fUniformHandler->getUniformCStr(ellipseVar), scaleVar.isValid() ? args.fUniformHandler->getUniformCStr(scaleVar) : "float2(0)", args.fUniformHandler->getUniformCStr(ellipseVar), - scaleVar.isValid() ? args.fUniformHandler->getUniformCStr(scaleVar) : "float2(0)"); + scaleVar.isValid() ? args.fUniformHandler->getUniformCStr(scaleVar) : "float2(0)", + (int)_outer.edgeType); + SkString _input4481(args.fInputColor); + SkString _sample4481; + if (_outer.inputFP_index >= 0) { + _sample4481 = this->invokeChild(_outer.inputFP_index, _input4481.c_str(), args); + } else { + _sample4481.swap(_input4481); + } fragBuilder->codeAppendf( - "a;\n@switch (%d) {\n case 0:\n alpha = approx_dist > 0.0 ? 0.0 : 1.0;\n " - " break;\n case 1:\n alpha = clamp(0.5 - half(approx_dist), 0.0, " - "1.0);\n break;\n case 2:\n alpha = approx_dist > 0.0 ? 1.0 : " - "0.0;\n break;\n case 3:\n alpha = clamp(0.5 + half(approx_dist), " - "0.0, 1.0);\n break;\n default:\n discard;\n}\n%s = %s * alpha;\n", - (int)_outer.edgeType, args.fOutputColor, args.fInputColor); + R"SkSL( +half4 inputColor = %s; +%s = inputColor * alpha; +)SkSL", + _sample4481.c_str(), args.fOutputColor); } private: @@ -125,7 +160,11 @@ GrEllipseEffect::GrEllipseEffect(const GrEllipseEffect& src) : INHERITED(kGrEllipseEffect_ClassID, src.optimizationFlags()) , edgeType(src.edgeType) , center(src.center) - , radii(src.radii) {} + , radii(src.radii) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } +} std::unique_ptr<GrFragmentProcessor> GrEllipseEffect::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrEllipseEffect(*this)); } @@ -137,11 +176,14 @@ std::unique_ptr<GrFragmentProcessor> GrEllipseEffect::TestCreate(GrProcessorTest center.fY = testData->fRandom->nextRangeScalar(0.f, 1000.f); SkScalar rx = testData->fRandom->nextRangeF(0.f, 1000.f); SkScalar ry = testData->fRandom->nextRangeF(0.f, 1000.f); - GrClipEdgeType et; + bool success; + std::unique_ptr<GrFragmentProcessor> fp; do { - et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt); - } while (GrClipEdgeType::kHairlineAA == et); - return GrEllipseEffect::Make(et, center, SkPoint::Make(rx, ry), - *testData->caps()->shaderCaps()); + GrClipEdgeType et = (GrClipEdgeType)testData->fRandom->nextULessThan(kGrClipEdgeTypeCnt); + std::tie(success, fp) = + GrEllipseEffect::Make(/*inputFP=*/nullptr, et, center, SkPoint::Make(rx, ry), + *testData->caps()->shaderCaps()); + } while (!success); + return fp; } #endif diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrEllipseEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrEllipseEffect.h index fb746b36c88..6348d97b34d 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrEllipseEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrEllipseEffect.h @@ -10,47 +10,61 @@ **************************************************************************************************/ #ifndef GrEllipseEffect_DEFINED #define GrEllipseEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrShaderCaps.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrEllipseEffect : public GrFragmentProcessor { public: - static std::unique_ptr<GrFragmentProcessor> Make(GrClipEdgeType edgeType, - SkPoint center, - SkPoint radii, - const GrShaderCaps& caps) { + static GrFPResult Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, + SkPoint center, + SkPoint radii, + const GrShaderCaps& caps) { // Small radii produce bad results on devices without full float. if (!caps.floatIs32Bits() && (radii.fX < 0.5f || radii.fY < 0.5f)) { - return nullptr; + return GrFPFailure(std::move(inputFP)); } // Very narrow ellipses produce bad results on devices without full float if (!caps.floatIs32Bits() && (radii.fX > 255 * radii.fY || radii.fY > 255 * radii.fX)) { - return nullptr; + return GrFPFailure(std::move(inputFP)); } // Very large ellipses produce bad results on devices without full float if (!caps.floatIs32Bits() && (radii.fX > 16384 || radii.fY > 16384)) { - return nullptr; + return GrFPFailure(std::move(inputFP)); } - return std::unique_ptr<GrFragmentProcessor>(new GrEllipseEffect(edgeType, center, radii)); + return GrFPSuccess(std::unique_ptr<GrFragmentProcessor>( + new GrEllipseEffect(std::move(inputFP), edgeType, center, radii))); } GrEllipseEffect(const GrEllipseEffect& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "EllipseEffect"; } + int inputFP_index = -1; GrClipEdgeType edgeType; SkPoint center; SkPoint radii; private: - GrEllipseEffect(GrClipEdgeType edgeType, SkPoint center, SkPoint radii) + GrEllipseEffect(std::unique_ptr<GrFragmentProcessor> inputFP, + GrClipEdgeType edgeType, + SkPoint center, + SkPoint radii) : INHERITED(kGrEllipseEffect_ClassID, - (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag) + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag) , edgeType(edgeType) , center(center) - , radii(radii) {} + , radii(radii) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrHSLToRGBFilterEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrHSLToRGBFilterEffect.cpp index 11effd21a3e..91796e1f0d7 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrHSLToRGBFilterEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrHSLToRGBFilterEffect.cpp @@ -23,13 +23,24 @@ public: GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrHSLToRGBFilterEffect& _outer = args.fFp.cast<GrHSLToRGBFilterEffect>(); (void)_outer; + SkString _input523(args.fInputColor); + SkString _sample523; + if (_outer.inputFP_index >= 0) { + _sample523 = this->invokeChild(_outer.inputFP_index, _input523.c_str(), args); + } else { + _sample523.swap(_input523); + } fragBuilder->codeAppendf( - "half3 hsl = %s.xyz;\nhalf C = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y;\nhalf3 p = " - "hsl.xxx + half3(0.0, 0.66666666666666663, 0.33333333333333331);\nhalf3 q = " - "clamp(abs(fract(p) * 6.0 - 3.0) - 1.0, 0.0, 1.0);\nhalf3 rgb = (q - 0.5) * C + " - "hsl.z;\n%s = clamp(half4(rgb, %s.w), 0.0, 1.0);\n%s.xyz *= %s.w;\n", - args.fInputColor, args.fOutputColor, args.fInputColor, args.fOutputColor, - args.fOutputColor); + R"SkSL(half4 inputColor = %s; +half3 hsl = inputColor.xyz; +half C = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y; +half3 p = hsl.xxx + half3(0.0, 0.66666666666666663, 0.33333333333333331); +half3 q = clamp(abs(fract(p) * 6.0 - 3.0) - 1.0, 0.0, 1.0); +half3 rgb = (q - 0.5) * C + hsl.z; +%s = clamp(half4(rgb, inputColor.w), 0.0, 1.0); +%s.xyz *= %s.w; +)SkSL", + _sample523.c_str(), args.fOutputColor, args.fOutputColor, args.fOutputColor); } private: @@ -47,7 +58,11 @@ bool GrHSLToRGBFilterEffect::onIsEqual(const GrFragmentProcessor& other) const { return true; } GrHSLToRGBFilterEffect::GrHSLToRGBFilterEffect(const GrHSLToRGBFilterEffect& src) - : INHERITED(kGrHSLToRGBFilterEffect_ClassID, src.optimizationFlags()) {} + : INHERITED(kGrHSLToRGBFilterEffect_ClassID, src.optimizationFlags()) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } +} std::unique_ptr<GrFragmentProcessor> GrHSLToRGBFilterEffect::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrHSLToRGBFilterEffect(*this)); } diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrHSLToRGBFilterEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrHSLToRGBFilterEffect.h index a86c4af0464..25f10b87206 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrHSLToRGBFilterEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrHSLToRGBFilterEffect.h @@ -10,17 +10,22 @@ **************************************************************************************************/ #ifndef GrHSLToRGBFilterEffect_DEFINED #define GrHSLToRGBFilterEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrHSLToRGBFilterEffect : public GrFragmentProcessor { public: #include "include/private/SkColorData.h" #include "include/private/SkNx.h" - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& c) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { + SkPMColor4f c = this->numChildProcessors() + ? ConstantOutputForConstantInput(this->childProcessor(0), inColor) + : inColor; const auto H = c[0], S = c[1], L = c[2], C = (1 - std::abs(2 * L - 1)) * S; const auto p = H + Sk4f(0, 2 / 3.f, 1 / 3.f, 0), @@ -30,18 +35,25 @@ public: return SkColor4f{rgba[0], rgba[1], rgba[2], rgba[3]}.premul(); } - static std::unique_ptr<GrFragmentProcessor> Make() { - return std::unique_ptr<GrFragmentProcessor>(new GrHSLToRGBFilterEffect()); + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP) { + return std::unique_ptr<GrFragmentProcessor>(new GrHSLToRGBFilterEffect(std::move(inputFP))); } GrHSLToRGBFilterEffect(const GrHSLToRGBFilterEffect& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "HSLToRGBFilterEffect"; } + int inputFP_index = -1; private: - GrHSLToRGBFilterEffect() + GrHSLToRGBFilterEffect(std::unique_ptr<GrFragmentProcessor> inputFP) : INHERITED(kGrHSLToRGBFilterEffect_ClassID, - (OptimizationFlags)(kConstantOutputForConstantInput_OptimizationFlag | - kPreservesOpaqueInput_OptimizationFlag)) {} + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + (kConstantOutputForConstantInput_OptimizationFlag | + kPreservesOpaqueInput_OptimizationFlag)) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrLumaColorFilterEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrLumaColorFilterEffect.cpp index c85bc65069b..ec9045b9324 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrLumaColorFilterEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrLumaColorFilterEffect.cpp @@ -23,10 +23,20 @@ public: GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrLumaColorFilterEffect& _outer = args.fFp.cast<GrLumaColorFilterEffect>(); (void)_outer; + SkString _input953(args.fInputColor); + SkString _sample953; + if (_outer.inputFP_index >= 0) { + _sample953 = this->invokeChild(_outer.inputFP_index, _input953.c_str(), args); + } else { + _sample953.swap(_input953); + } fragBuilder->codeAppendf( - "\nhalf luma = clamp(dot(half3(0.2125999927520752, 0.71520000696182251, " - "0.072200000286102295), %s.xyz), 0.0, 1.0);\n%s = half4(0.0, 0.0, 0.0, luma);\n", - args.fInputColor, args.fOutputColor); + R"SkSL(half4 inputColor = %s; + +half luma = clamp(dot(half3(0.2125999927520752, 0.71520000696182251, 0.072200000286102295), inputColor.xyz), 0.0, 1.0); +%s = half4(0.0, 0.0, 0.0, luma); +)SkSL", + _sample953.c_str(), args.fOutputColor); } private: @@ -44,7 +54,11 @@ bool GrLumaColorFilterEffect::onIsEqual(const GrFragmentProcessor& other) const return true; } GrLumaColorFilterEffect::GrLumaColorFilterEffect(const GrLumaColorFilterEffect& src) - : INHERITED(kGrLumaColorFilterEffect_ClassID, src.optimizationFlags()) {} + : INHERITED(kGrLumaColorFilterEffect_ClassID, src.optimizationFlags()) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } +} std::unique_ptr<GrFragmentProcessor> GrLumaColorFilterEffect::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrLumaColorFilterEffect(*this)); } diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrLumaColorFilterEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrLumaColorFilterEffect.h index 3ee5c06aede..274958efef9 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrLumaColorFilterEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrLumaColorFilterEffect.h @@ -10,31 +10,45 @@ **************************************************************************************************/ #ifndef GrLumaColorFilterEffect_DEFINED #define GrLumaColorFilterEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrLumaColorFilterEffect : public GrFragmentProcessor { public: #include "include/private/SkColorData.h" - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { + SkPMColor4f input = this->numChildProcessors() + ? ConstantOutputForConstantInput( + this->childProcessor(inputFP_index), inColor) + : inColor; float luma = SK_ITU_BT709_LUM_COEFF_R * input.fR + SK_ITU_BT709_LUM_COEFF_G * input.fG + SK_ITU_BT709_LUM_COEFF_B * input.fB; return {0, 0, 0, SkTPin(luma, 0.0f, 1.0f)}; } - static std::unique_ptr<GrFragmentProcessor> Make() { - return std::unique_ptr<GrFragmentProcessor>(new GrLumaColorFilterEffect()); + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP) { + return std::unique_ptr<GrFragmentProcessor>( + new GrLumaColorFilterEffect(std::move(inputFP))); } GrLumaColorFilterEffect(const GrLumaColorFilterEffect& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "LumaColorFilterEffect"; } + int inputFP_index = -1; private: - GrLumaColorFilterEffect() + GrLumaColorFilterEffect(std::unique_ptr<GrFragmentProcessor> inputFP) : INHERITED(kGrLumaColorFilterEffect_ClassID, - (OptimizationFlags)kConstantOutputForConstantInput_OptimizationFlag) {} + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + kConstantOutputForConstantInput_OptimizationFlag) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrMagnifierEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrMagnifierEffect.cpp index 0746fbf6c60..acc344d4a86 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrMagnifierEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrMagnifierEffect.cpp @@ -35,44 +35,51 @@ public: (void)xInvInset; auto yInvInset = _outer.yInvInset; (void)yInvInset; - boundsUniformVar = args.fUniformHandler->addUniform( - &_outer, kFragment_GrShaderFlag, kFloat4_GrSLType, "boundsUniform"); - xInvZoomVar = args.fUniformHandler->addUniform( - &_outer, kFragment_GrShaderFlag, kFloat_GrSLType, "xInvZoom"); - yInvZoomVar = args.fUniformHandler->addUniform( - &_outer, kFragment_GrShaderFlag, kFloat_GrSLType, "yInvZoom"); - xInvInsetVar = args.fUniformHandler->addUniform( - &_outer, kFragment_GrShaderFlag, kFloat_GrSLType, "xInvInset"); - yInvInsetVar = args.fUniformHandler->addUniform( - &_outer, kFragment_GrShaderFlag, kFloat_GrSLType, "yInvInset"); - offsetVar = args.fUniformHandler->addUniform( - &_outer, kFragment_GrShaderFlag, kHalf2_GrSLType, "offset"); + boundsUniformVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, + kFloat4_GrSLType, "boundsUniform"); + xInvZoomVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, + kFloat_GrSLType, "xInvZoom"); + yInvZoomVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, + kFloat_GrSLType, "yInvZoom"); + xInvInsetVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, + kFloat_GrSLType, "xInvInset"); + yInvInsetVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, + kFloat_GrSLType, "yInvInset"); + offsetVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, + kHalf2_GrSLType, "offset"); SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D( args.fTransformedCoords[0].fVaryingPoint, _outer.sampleMatrix()); fragBuilder->codeAppendf( - "float2 coord = %s;\nfloat2 zoom_coord = float2(%s) + coord * float2(%s, " - "%s);\nfloat2 delta = (coord - %s.xy) * %s.zw;\ndelta = min(delta, " - "float2(half2(1.0, 1.0)) - delta);\ndelta *= float2(%s, %s);\nfloat weight = " - "0.0;\nif (delta.x < 2.0 && delta.y < 2.0) {\n delta = float2(half2(2.0, 2.0)) " - "- delta;\n float dist = length(delta);\n dist = max(2.0 - dist, 0.0);\n " - "weight = min(dist * dist, 1.0);\n} else {\n float2 delta_squared = delta * " - "delta;\n weight = min(min(delta_squared.x, delta_square", - sk_TransformedCoords2D_0.c_str(), - args.fUniformHandler->getUniformCStr(offsetVar), + R"SkSL(float2 coord = %s; +float2 zoom_coord = float2(%s) + coord * float2(%s, %s); +float2 delta = (coord - %s.xy) * %s.zw; +delta = min(delta, float2(half2(1.0, 1.0)) - delta); +delta *= float2(%s, %s); +float weight = 0.0; +if (delta.x < 2.0 && delta.y < 2.0) { + delta = float2(half2(2.0, 2.0)) - delta; + float dist = length(delta); + dist = max(2.0 - dist, 0.0); + weight = min(dist * dist, 1.0); +} else { + float2 delta_squared = delta * delta; + weight = min(min(delta_squared.x, delta_squared.y), 1.0); +})SkSL", + sk_TransformedCoords2D_0.c_str(), args.fUniformHandler->getUniformCStr(offsetVar), args.fUniformHandler->getUniformCStr(xInvZoomVar), args.fUniformHandler->getUniformCStr(yInvZoomVar), args.fUniformHandler->getUniformCStr(boundsUniformVar), args.fUniformHandler->getUniformCStr(boundsUniformVar), args.fUniformHandler->getUniformCStr(xInvInsetVar), args.fUniformHandler->getUniformCStr(yInvInsetVar)); + SkString _sample1112; + SkString _coords1112("mix(coord, zoom_coord, weight)"); + _sample1112 = this->invokeChild(_outer.src_index, args, _coords1112.c_str()); fragBuilder->codeAppendf( - "d.y), 1.0);\n}\n%s = sample(%s, mix(coord, zoom_coord, weight)).%s;\n", - args.fOutputColor, - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]), - fragBuilder->getProgramBuilder() - ->samplerSwizzle(args.fTexSamplers[0]) - .asString() - .c_str()); + R"SkSL( +%s = %s; +)SkSL", + args.fOutputColor, _sample1112.c_str()); } private: @@ -85,9 +92,6 @@ private: pdman.set1f(xInvInsetVar, (_outer.xInvInset)); pdman.set1f(yInvInsetVar, (_outer.yInvInset)); } - const GrSurfaceProxyView& srcView = _outer.textureSampler(0).view(); - GrTexture& src = *srcView.proxy()->peekTexture(); - (void)src; auto bounds = _outer.bounds; (void)bounds; UniformHandle& boundsUniform = boundsUniformVar; @@ -105,32 +109,9 @@ private: UniformHandle& offset = offsetVar; (void)offset; - SkScalar invW = 1.0f / src.width(); - SkScalar invH = 1.0f / src.height(); - - { - SkScalar y = srcRect.y() * invH; - if (srcView.origin() != kTopLeft_GrSurfaceOrigin) { - y = 1.0f - (srcRect.height() / bounds.height()) - y; - } - - pdman.set2f(offset, srcRect.x() * invW, y); - } - - { - SkScalar y = bounds.y() * invH; - SkScalar hSign = 1.f; - if (srcView.origin() != kTopLeft_GrSurfaceOrigin) { - y = 1.0f - bounds.y() * invH; - hSign = -1.f; - } - - pdman.set4f(boundsUniform, - bounds.x() * invW, - y, - SkIntToScalar(src.width()) / bounds.width(), - hSign * SkIntToScalar(src.height()) / bounds.height()); - } + pdman.set2f(offset, srcRect.x(), srcRect.y()); + pdman.set4f(boundsUniform, bounds.x(), bounds.y(), 1.f / bounds.width(), + 1.f / bounds.height()); } UniformHandle boundsUniformVar; UniformHandle offsetVar; @@ -147,7 +128,6 @@ void GrMagnifierEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, bool GrMagnifierEffect::onIsEqual(const GrFragmentProcessor& other) const { const GrMagnifierEffect& that = other.cast<GrMagnifierEffect>(); (void)that; - if (src != that.src) return false; if (bounds != that.bounds) return false; if (srcRect != that.srcRect) return false; if (xInvZoom != that.xInvZoom) return false; @@ -158,27 +138,22 @@ bool GrMagnifierEffect::onIsEqual(const GrFragmentProcessor& other) const { } GrMagnifierEffect::GrMagnifierEffect(const GrMagnifierEffect& src) : INHERITED(kGrMagnifierEffect_ClassID, src.optimizationFlags()) - , srcCoordTransform(src.srcCoordTransform) - , src(src.src) + , fCoordTransform0(src.fCoordTransform0) , bounds(src.bounds) , srcRect(src.srcRect) , xInvZoom(src.xInvZoom) , yInvZoom(src.yInvZoom) , xInvInset(src.xInvInset) , yInvInset(src.yInvInset) { - this->setTextureSamplerCnt(1); - this->addCoordTransform(&srcCoordTransform); + { src_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.src_index)); } + this->addCoordTransform(&fCoordTransform0); } std::unique_ptr<GrFragmentProcessor> GrMagnifierEffect::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrMagnifierEffect(*this)); } -const GrFragmentProcessor::TextureSampler& GrMagnifierEffect::onTextureSampler(int index) const { - return IthTextureSampler(index, src); -} GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrMagnifierEffect); #if GR_TEST_UTILS std::unique_ptr<GrFragmentProcessor> GrMagnifierEffect::TestCreate(GrProcessorTestData* d) { - auto[view, ct, at] = d->randomView(); const int kMaxWidth = 200; const int kMaxHeight = 200; const SkScalar kMaxInset = 20.0f; @@ -189,7 +164,8 @@ std::unique_ptr<GrFragmentProcessor> GrMagnifierEffect::TestCreate(GrProcessorTe SkIRect bounds = SkIRect::MakeWH(SkIntToScalar(kMaxWidth), SkIntToScalar(kMaxHeight)); SkRect srcRect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height)); - auto effect = GrMagnifierEffect::Make(std::move(view), + auto src = GrProcessorUnitTest::MakeChildFP(d); + auto effect = GrMagnifierEffect::Make(std::move(src), bounds, srcRect, srcRect.width() / bounds.width(), diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrMagnifierEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrMagnifierEffect.h index ab930d9cdb3..aff287f30a3 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrMagnifierEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrMagnifierEffect.h @@ -10,14 +10,16 @@ **************************************************************************************************/ #ifndef GrMagnifierEffect_DEFINED #define GrMagnifierEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrMagnifierEffect : public GrFragmentProcessor { public: - static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView src, + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> src, SkIRect bounds, SkRect srcRect, float xInvZoom, @@ -30,8 +32,8 @@ public: GrMagnifierEffect(const GrMagnifierEffect& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "MagnifierEffect"; } - GrCoordTransform srcCoordTransform; - TextureSampler src; + GrCoordTransform fCoordTransform0; + int src_index = -1; SkIRect bounds; SkRect srcRect; float xInvZoom; @@ -40,7 +42,7 @@ public: float yInvInset; private: - GrMagnifierEffect(GrSurfaceProxyView src, + GrMagnifierEffect(std::unique_ptr<GrFragmentProcessor> src, SkIRect bounds, SkRect srcRect, float xInvZoom, @@ -48,21 +50,20 @@ private: float xInvInset, float yInvInset) : INHERITED(kGrMagnifierEffect_ClassID, kNone_OptimizationFlags) - , srcCoordTransform(SkMatrix::I(), src.proxy(), src.origin()) - , src(std::move(src)) + , fCoordTransform0(SkMatrix::I()) , bounds(bounds) , srcRect(srcRect) , xInvZoom(xInvZoom) , yInvZoom(yInvZoom) , xInvInset(xInvInset) , yInvInset(yInvInset) { - this->setTextureSamplerCnt(1); - this->addCoordTransform(&srcCoordTransform); + SkASSERT(src); + src_index = this->registerExplicitlySampledChild(std::move(src)); + this->addCoordTransform(&fCoordTransform0); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - const TextureSampler& onTextureSampler(int) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST typedef GrFragmentProcessor INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrMatrixEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrMatrixEffect.cpp deleted file mode 100644 index fa8b6910e2b..00000000000 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrMatrixEffect.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2020 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 GrMatrixEffect.fp; do not modify. - **************************************************************************************************/ -#include "GrMatrixEffect.h" - -#include "src/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 GrGLSLMatrixEffect : public GrGLSLFragmentProcessor { -public: - GrGLSLMatrixEffect() {} - void emitCode(EmitArgs& args) override { - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const GrMatrixEffect& _outer = args.fFp.cast<GrMatrixEffect>(); - (void)_outer; - auto matrix = _outer.matrix; - (void)matrix; - matrixVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, - kFloat3x3_GrSLType, "matrix"); - SkString _input716 = SkStringPrintf("%s", args.fInputColor); - SkString _sample716; - _sample716 = this->invokeChild(_outer.child_index, _input716.c_str(), args); - fragBuilder->codeAppendf("%s = %s;\n", args.fOutputColor, _sample716.c_str()); - } - -private: - void onSetData(const GrGLSLProgramDataManager& pdman, - const GrFragmentProcessor& _proc) override { - const GrMatrixEffect& _outer = _proc.cast<GrMatrixEffect>(); - { pdman.setSkMatrix(matrixVar, (_outer.matrix)); } - } - UniformHandle matrixVar; -}; -GrGLSLFragmentProcessor* GrMatrixEffect::onCreateGLSLInstance() const { - return new GrGLSLMatrixEffect(); -} -void GrMatrixEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const {} -bool GrMatrixEffect::onIsEqual(const GrFragmentProcessor& other) const { - const GrMatrixEffect& that = other.cast<GrMatrixEffect>(); - (void)that; - if (matrix != that.matrix) return false; - return true; -} -GrMatrixEffect::GrMatrixEffect(const GrMatrixEffect& src) - : INHERITED(kGrMatrixEffect_ClassID, src.optimizationFlags()) - , matrix(src.matrix) - , child_index(src.child_index) { - { - auto clone = src.childProcessor(child_index).clone(); - if (src.childProcessor(child_index).isSampledWithExplicitCoords()) { - clone->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(clone)); - } -} -std::unique_ptr<GrFragmentProcessor> GrMatrixEffect::clone() const { - return std::unique_ptr<GrFragmentProcessor>(new GrMatrixEffect(*this)); -} diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrMixerEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrMixerEffect.cpp index fea85f413a5..1dbf8ecabec 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrMixerEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrMixerEffect.cpp @@ -27,21 +27,25 @@ public: (void)weight; weightVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf_GrSLType, "weight"); - SkString _input1278 = SkStringPrintf("%s", args.fInputColor); + SkString _input1278(args.fInputColor); SkString _sample1278; _sample1278 = this->invokeChild(_outer.fp0_index, _input1278.c_str(), args); - fragBuilder->codeAppendf("half4 in0 = %s;", _sample1278.c_str()); - SkString _input1335 = SkStringPrintf("%s", args.fInputColor); + fragBuilder->codeAppendf( + R"SkSL(half4 in0 = %s;)SkSL", _sample1278.c_str()); + SkString _input1335(args.fInputColor); SkString _sample1335; if (_outer.fp1_index >= 0) { _sample1335 = this->invokeChild(_outer.fp1_index, _input1335.c_str(), args); } else { - _sample1335 = "half4(1)"; + _sample1335.swap(_input1335); } - fragBuilder->codeAppendf("\nhalf4 in1 = %s ? %s : %s;\n%s = mix(in0, in1, %s);\n", - _outer.fp1_index >= 0 ? "true" : "false", _sample1335.c_str(), - args.fInputColor, args.fOutputColor, - args.fUniformHandler->getUniformCStr(weightVar)); + fragBuilder->codeAppendf( + R"SkSL( +half4 in1 = %s ? %s : %s; +%s = mix(in0, in1, %s); +)SkSL", + _outer.fp1_index >= 0 ? "true" : "false", _sample1335.c_str(), args.fInputColor, + args.fOutputColor, args.fUniformHandler->getUniformCStr(weightVar)); } private: @@ -64,23 +68,10 @@ bool GrMixerEffect::onIsEqual(const GrFragmentProcessor& other) const { return true; } GrMixerEffect::GrMixerEffect(const GrMixerEffect& src) - : INHERITED(kGrMixerEffect_ClassID, src.optimizationFlags()) - , fp0_index(src.fp0_index) - , fp1_index(src.fp1_index) - , weight(src.weight) { - { - auto clone = src.childProcessor(fp0_index).clone(); - if (src.childProcessor(fp0_index).isSampledWithExplicitCoords()) { - clone->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(clone)); - } - if (fp1_index >= 0) { - auto clone = src.childProcessor(fp1_index).clone(); - if (src.childProcessor(fp1_index).isSampledWithExplicitCoords()) { - clone->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(clone)); + : INHERITED(kGrMixerEffect_ClassID, src.optimizationFlags()), weight(src.weight) { + { fp0_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.fp0_index)); } + if (src.fp1_index >= 0) { + fp1_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.fp1_index)); } } std::unique_ptr<GrFragmentProcessor> GrMixerEffect::clone() const { diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrMixerEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrMixerEffect.h index a9e3717f885..391fbf6bdb8 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrMixerEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrMixerEffect.h @@ -10,11 +10,13 @@ **************************************************************************************************/ #ifndef GrMixerEffect_DEFINED #define GrMixerEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrMixerEffect : public GrFragmentProcessor { public: static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp0, @@ -54,11 +56,9 @@ private: : INHERITED(kGrMixerEffect_ClassID, (OptimizationFlags)OptFlags(fp0, fp1)) , weight(weight) { SkASSERT(fp0); - fp0_index = this->numChildProcessors(); - this->registerChildProcessor(std::move(fp0)); + fp0_index = this->registerChild(std::move(fp0)); if (fp1) { - fp1_index = this->numChildProcessors(); - this->registerChildProcessor(std::move(fp1)); + fp1_index = this->registerChild(std::move(fp1)); } } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp index 0e34b530003..deae796c1b1 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.cpp @@ -35,8 +35,12 @@ public: kHalf4_GrSLType, "uniformColor"); } fragBuilder->codeAppendf( - "half4 constColor;\n@if (%s) {\n constColor = %s;\n} else {\n constColor = " - "half4(%f, %f, %f, %f);\n}", + R"SkSL(half4 constColor; +@if (%s) { + constColor = %s; +} else { + constColor = half4(%f, %f, %f, %f); +})SkSL", (_outer.useUniform ? "true" : "false"), uniformColorVar.isValid() ? args.fUniformHandler->getUniformCStr(uniformColorVar) : "half4(0)", @@ -45,7 +49,11 @@ public: SkString _input1992("constColor"); SkString _sample1992; _sample1992 = this->invokeChild(_outer.fp_index, _input1992.c_str(), args); - fragBuilder->codeAppendf("\n%s = %s;\n", args.fOutputColor, _sample1992.c_str()); + fragBuilder->codeAppendf( + R"SkSL( +%s = %s; +)SkSL", + args.fOutputColor, _sample1992.c_str()); } private: @@ -87,17 +95,10 @@ bool GrOverrideInputFragmentProcessor::onIsEqual(const GrFragmentProcessor& othe GrOverrideInputFragmentProcessor::GrOverrideInputFragmentProcessor( const GrOverrideInputFragmentProcessor& src) : INHERITED(kGrOverrideInputFragmentProcessor_ClassID, src.optimizationFlags()) - , fp_index(src.fp_index) , useUniform(src.useUniform) , uniformColor(src.uniformColor) , literalColor(src.literalColor) { - { - auto clone = src.childProcessor(fp_index).clone(); - if (src.childProcessor(fp_index).isSampledWithExplicitCoords()) { - clone->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(clone)); - } + { fp_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.fp_index)); } } std::unique_ptr<GrFragmentProcessor> GrOverrideInputFragmentProcessor::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrOverrideInputFragmentProcessor(*this)); diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h b/chromium/third_party/skia/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h index d69c16ebbbe..988b1caf0c4 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrOverrideInputFragmentProcessor.h @@ -10,11 +10,13 @@ **************************************************************************************************/ #ifndef GrOverrideInputFragmentProcessor_DEFINED #define GrOverrideInputFragmentProcessor_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrOverrideInputFragmentProcessor : public GrFragmentProcessor { public: static OptimizationFlags OptFlags(const std::unique_ptr<GrFragmentProcessor>& fp, @@ -59,8 +61,7 @@ private: , uniformColor(uniformColor) , literalColor(literalColor) { SkASSERT(fp); - fp_index = this->numChildProcessors(); - this->registerChildProcessor(std::move(fp)); + fp_index = this->registerChild(std::move(fp)); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrPremulInputFragmentProcessor.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrPremulInputFragmentProcessor.cpp deleted file mode 100644 index f327850bdb9..00000000000 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrPremulInputFragmentProcessor.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * 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 GrPremulInputFragmentProcessor.fp; do not modify. - **************************************************************************************************/ -#include "GrPremulInputFragmentProcessor.h" - -#include "src/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 GrGLSLPremulInputFragmentProcessor : public GrGLSLFragmentProcessor { -public: - GrGLSLPremulInputFragmentProcessor() {} - void emitCode(EmitArgs& args) override { - GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; - const GrPremulInputFragmentProcessor& _outer = - args.fFp.cast<GrPremulInputFragmentProcessor>(); - (void)_outer; - fragBuilder->codeAppendf("%s = %s;\n%s.xyz *= %s.w;\n", args.fOutputColor, args.fInputColor, - args.fOutputColor, args.fInputColor); - } - -private: - void onSetData(const GrGLSLProgramDataManager& pdman, - const GrFragmentProcessor& _proc) override {} -}; -GrGLSLFragmentProcessor* GrPremulInputFragmentProcessor::onCreateGLSLInstance() const { - return new GrGLSLPremulInputFragmentProcessor(); -} -void GrPremulInputFragmentProcessor::onGetGLSLProcessorKey(const GrShaderCaps& caps, - GrProcessorKeyBuilder* b) const {} -bool GrPremulInputFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const { - const GrPremulInputFragmentProcessor& that = other.cast<GrPremulInputFragmentProcessor>(); - (void)that; - return true; -} -GrPremulInputFragmentProcessor::GrPremulInputFragmentProcessor( - const GrPremulInputFragmentProcessor& src) - : INHERITED(kGrPremulInputFragmentProcessor_ClassID, src.optimizationFlags()) {} -std::unique_ptr<GrFragmentProcessor> GrPremulInputFragmentProcessor::clone() const { - return std::unique_ptr<GrFragmentProcessor>(new GrPremulInputFragmentProcessor(*this)); -} diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrPremulInputFragmentProcessor.h b/chromium/third_party/skia/src/gpu/effects/generated/GrPremulInputFragmentProcessor.h deleted file mode 100644 index ae093ca6daf..00000000000 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrPremulInputFragmentProcessor.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * 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 GrPremulInputFragmentProcessor.fp; do not modify. - **************************************************************************************************/ -#ifndef GrPremulInputFragmentProcessor_DEFINED -#define GrPremulInputFragmentProcessor_DEFINED -#include "include/core/SkTypes.h" -#include "include/core/SkM44.h" - -#include "src/gpu/GrCoordTransform.h" -#include "src/gpu/GrFragmentProcessor.h" -class GrPremulInputFragmentProcessor : public GrFragmentProcessor { -public: - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override { - return SkColor4f{input.fR, input.fG, input.fB, input.fA}.premul(); - } - static std::unique_ptr<GrFragmentProcessor> Make() { - return std::unique_ptr<GrFragmentProcessor>(new GrPremulInputFragmentProcessor()); - } - GrPremulInputFragmentProcessor(const GrPremulInputFragmentProcessor& src); - std::unique_ptr<GrFragmentProcessor> clone() const override; - const char* name() const override { return "PremulInputFragmentProcessor"; } - -private: - GrPremulInputFragmentProcessor() - : INHERITED(kGrPremulInputFragmentProcessor_ClassID, - (OptimizationFlags)kPreservesOpaqueInput_OptimizationFlag | - kConstantOutputForConstantInput_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 diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrRGBToHSLFilterEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrRGBToHSLFilterEffect.cpp index 6d93aa9ad2f..a2acd522195 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrRGBToHSLFilterEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrRGBToHSLFilterEffect.cpp @@ -23,15 +23,27 @@ public: GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; const GrRGBToHSLFilterEffect& _outer = args.fFp.cast<GrRGBToHSLFilterEffect>(); (void)_outer; + SkString _input1173(args.fInputColor); + SkString _sample1173; + if (_outer.inputFP_index >= 0) { + _sample1173 = this->invokeChild(_outer.inputFP_index, _input1173.c_str(), args); + } else { + _sample1173.swap(_input1173); + } fragBuilder->codeAppendf( - "half4 c = %s;\nhalf4 p = c.y < c.z ? half4(c.zy, -1.0, 0.66666666666666663) : " - "half4(c.yz, 0.0, -0.33333333333333331);\nhalf4 q = c.x < p.x ? half4(p.x, c.x, " - "p.yw) : half4(c.x, p.x, p.yz);\n\nhalf pmV = q.x;\nhalf pmC = pmV - min(q.y, " - "q.z);\nhalf pmL = pmV - pmC * 0.5;\nhalf H = abs(q.w + (q.y - q.z) / (pmC * 6.0 + " - "9.9999997473787516e-05));\nhalf S = pmC / ((c.w + 9.9999997473787516e-05) - " - "abs(pmL * 2.0 - c.w));\nhalf L = pmL / (c.w + 9.9999997473787516e-05);\n%s = " - "half4(H, S, L, c.w);\n", - args.fInputColor, args.fOutputColor); + R"SkSL(half4 c = %s; +half4 p = c.y < c.z ? half4(c.zy, -1.0, 0.66666666666666663) : half4(c.yz, 0.0, -0.33333333333333331); +half4 q = c.x < p.x ? half4(p.x, c.x, p.yw) : half4(c.x, p.x, p.yz); + +half pmV = q.x; +half pmC = pmV - min(q.y, q.z); +half pmL = pmV - pmC * 0.5; +half H = abs(q.w + (q.y - q.z) / (pmC * 6.0 + 9.9999997473787516e-05)); +half S = pmC / ((c.w + 9.9999997473787516e-05) - abs(pmL * 2.0 - c.w)); +half L = pmL / (c.w + 9.9999997473787516e-05); +%s = half4(H, S, L, c.w); +)SkSL", + _sample1173.c_str(), args.fOutputColor); } private: @@ -49,7 +61,11 @@ bool GrRGBToHSLFilterEffect::onIsEqual(const GrFragmentProcessor& other) const { return true; } GrRGBToHSLFilterEffect::GrRGBToHSLFilterEffect(const GrRGBToHSLFilterEffect& src) - : INHERITED(kGrRGBToHSLFilterEffect_ClassID, src.optimizationFlags()) {} + : INHERITED(kGrRGBToHSLFilterEffect_ClassID, src.optimizationFlags()) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } +} std::unique_ptr<GrFragmentProcessor> GrRGBToHSLFilterEffect::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrRGBToHSLFilterEffect(*this)); } diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrRGBToHSLFilterEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrRGBToHSLFilterEffect.h index e8e0bba7561..4b5fdccd835 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrRGBToHSLFilterEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrRGBToHSLFilterEffect.h @@ -10,16 +10,21 @@ **************************************************************************************************/ #ifndef GrRGBToHSLFilterEffect_DEFINED #define GrRGBToHSLFilterEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrRGBToHSLFilterEffect : public GrFragmentProcessor { public: #include "include/private/SkColorData.h" - SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& c) const override { + SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override { + SkPMColor4f c = this->numChildProcessors() + ? ConstantOutputForConstantInput(this->childProcessor(0), inColor) + : inColor; const auto p = (c.fG < c.fB) ? SkPMColor4f{c.fB, c.fG, -1, 2 / 3.f} : SkPMColor4f{c.fG, c.fB, 0, -1 / 3.f}, q = (c.fR < p[0]) ? SkPMColor4f{p[0], c.fR, p[1], p[3]} @@ -32,18 +37,25 @@ public: return {H, S, L, c.fA}; } - static std::unique_ptr<GrFragmentProcessor> Make() { - return std::unique_ptr<GrFragmentProcessor>(new GrRGBToHSLFilterEffect()); + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP) { + return std::unique_ptr<GrFragmentProcessor>(new GrRGBToHSLFilterEffect(std::move(inputFP))); } GrRGBToHSLFilterEffect(const GrRGBToHSLFilterEffect& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "RGBToHSLFilterEffect"; } + int inputFP_index = -1; private: - GrRGBToHSLFilterEffect() + GrRGBToHSLFilterEffect(std::unique_ptr<GrFragmentProcessor> inputFP) : INHERITED(kGrRGBToHSLFilterEffect_ClassID, - (OptimizationFlags)(kConstantOutputForConstantInput_OptimizationFlag | - kPreservesOpaqueInput_OptimizationFlag)) {} + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + (kConstantOutputForConstantInput_OptimizationFlag | + kPreservesOpaqueInput_OptimizationFlag)) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrRRectBlurEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrRRectBlurEffect.cpp index 74a49b102e0..968ab1e0ee6 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrRRectBlurEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrRRectBlurEffect.cpp @@ -10,11 +10,13 @@ **************************************************************************************************/ #include "GrRRectBlurEffect.h" -std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::Make(GrRecordingContext* context, - float sigma, - float xformedSigma, - const SkRRect& srcRRect, - const SkRRect& devRRect) { +std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::Make( + std::unique_ptr<GrFragmentProcessor> inputFP, + GrRecordingContext* context, + float sigma, + float xformedSigma, + const SkRRect& srcRRect, + const SkRRect& devRRect) { SkASSERT(!SkRRectPriv::IsCircle(devRRect) && !devRRect.isRect()); // Should've been caught up-stream @@ -39,15 +41,15 @@ std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::Make(GrRecordingContext* return nullptr; } - GrSurfaceProxyView mask = - find_or_create_rrect_blur_mask(context, rrectToDraw, dimensions, xformedSigma); - if (!mask) { + std::unique_ptr<GrFragmentProcessor> maskFP = + find_or_create_rrect_blur_mask_fp(context, rrectToDraw, dimensions, xformedSigma); + if (!maskFP) { return nullptr; } return std::unique_ptr<GrFragmentProcessor>( - new GrRRectBlurEffect(xformedSigma, devRRect.getBounds(), - SkRRectPriv::GetSimpleRadii(devRRect).fX, std::move(mask))); + new GrRRectBlurEffect(std::move(inputFP), xformedSigma, devRRect.getBounds(), + SkRRectPriv::GetSimpleRadii(devRRect).fX, std::move(maskFP))); } #include "src/gpu/GrTexture.h" #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" @@ -75,29 +77,42 @@ public: blurRadiusVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf_GrSLType, "blurRadius"); fragBuilder->codeAppendf( - "\nhalf2 translatedFragPos = half2(sk_FragCoord.xy - %s.xy);\nhalf threshold = %s " - "+ 2.0 * %s;\nhalf2 middle = half2((%s.zw - %s.xy) - float(2.0 * threshold));\nif " - "(translatedFragPos.x >= threshold && translatedFragPos.x < middle.x + threshold) " - "{\n translatedFragPos.x = threshold;\n} else if (translatedFragPos.x >= " - "middle.x + threshold) {\n translatedFragPos.x -= middle.x - 1.0;\n}\nif " - "(translatedFragPos.y > threshold && translatedFragPos.y < middle.y + threshold) " - "{\n translatedFragPos.y = threshold;", + R"SkSL(half2 translatedFragPos = half2(sk_FragCoord.xy - %s.xy); +half2 proxyCenter = half2((%s.zw - %s.xy) * 0.5); +half edgeSize = (2.0 * %s + %s) + 0.5; +translatedFragPos -= proxyCenter; +half2 fragDirection = sign(translatedFragPos); +translatedFragPos = abs(translatedFragPos); +translatedFragPos -= proxyCenter - edgeSize; +translatedFragPos = max(translatedFragPos, 0.0); +translatedFragPos *= fragDirection; +translatedFragPos += half2(edgeSize); +half2 proxyDims = half2(2.0 * edgeSize); +half2 texCoord = translatedFragPos / proxyDims;)SkSL", + args.fUniformHandler->getUniformCStr(proxyRectVar), args.fUniformHandler->getUniformCStr(proxyRectVar), - args.fUniformHandler->getUniformCStr(cornerRadiusVar), - args.fUniformHandler->getUniformCStr(blurRadiusVar), args.fUniformHandler->getUniformCStr(proxyRectVar), - args.fUniformHandler->getUniformCStr(proxyRectVar)); + args.fUniformHandler->getUniformCStr(blurRadiusVar), + args.fUniformHandler->getUniformCStr(cornerRadiusVar)); + SkString _input9604(args.fInputColor); + SkString _sample9604; + if (_outer.inputFP_index >= 0) { + _sample9604 = this->invokeChild(_outer.inputFP_index, _input9604.c_str(), args); + } else { + _sample9604.swap(_input9604); + } + fragBuilder->codeAppendf( + R"SkSL( +half4 inputColor = %s;)SkSL", + _sample9604.c_str()); + SkString _sample9664; + SkString _coords9664("float2(texCoord)"); + _sample9664 = this->invokeChild(_outer.ninePatchFP_index, args, _coords9664.c_str()); fragBuilder->codeAppendf( - "\n} else if (translatedFragPos.y >= middle.y + threshold) {\n " - "translatedFragPos.y -= middle.y - 1.0;\n}\nhalf2 proxyDims = half2(2.0 * " - "threshold + 1.0);\nhalf2 texCoord = translatedFragPos / proxyDims;\n%s = %s * " - "sample(%s, float2(texCoord)).%s;\n", - args.fOutputColor, args.fInputColor, - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]), - fragBuilder->getProgramBuilder() - ->samplerSwizzle(args.fTexSamplers[0]) - .asString() - .c_str()); + R"SkSL( +%s = inputColor * %s; +)SkSL", + args.fOutputColor, _sample9664.c_str()); } private: @@ -111,9 +126,6 @@ private: (void)rect; UniformHandle& cornerRadius = cornerRadiusVar; (void)cornerRadius; - const GrSurfaceProxyView& ninePatchSamplerView = _outer.textureSampler(0).view(); - GrTexture& ninePatchSampler = *ninePatchSamplerView.proxy()->peekTexture(); - (void)ninePatchSampler; UniformHandle& proxyRect = proxyRectVar; (void)proxyRect; UniformHandle& blurRadius = blurRadiusVar; @@ -141,23 +153,24 @@ bool GrRRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const { if (sigma != that.sigma) return false; if (rect != that.rect) return false; if (cornerRadius != that.cornerRadius) return false; - if (ninePatchSampler != that.ninePatchSampler) return false; return true; } GrRRectBlurEffect::GrRRectBlurEffect(const GrRRectBlurEffect& src) : INHERITED(kGrRRectBlurEffect_ClassID, src.optimizationFlags()) , sigma(src.sigma) , rect(src.rect) - , cornerRadius(src.cornerRadius) - , ninePatchSampler(src.ninePatchSampler) { - this->setTextureSamplerCnt(1); + , cornerRadius(src.cornerRadius) { + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } + { + ninePatchFP_index = + this->cloneAndRegisterChildProcessor(src.childProcessor(src.ninePatchFP_index)); + } } std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrRRectBlurEffect(*this)); } -const GrFragmentProcessor::TextureSampler& GrRRectBlurEffect::onTextureSampler(int index) const { - return IthTextureSampler(index, ninePatchSampler); -} GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRRectBlurEffect); #if GR_TEST_UTILS std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::TestCreate(GrProcessorTestData* d) { @@ -167,6 +180,6 @@ std::unique_ptr<GrFragmentProcessor> GrRRectBlurEffect::TestCreate(GrProcessorTe SkScalar sigma = d->fRandom->nextRangeF(1.f, 10.f); SkRRect rrect; rrect.setRectXY(SkRect::MakeWH(w, h), r, r); - return GrRRectBlurEffect::Make(d->context(), sigma, sigma, rrect, rrect); + return GrRRectBlurEffect::Make(/*inputFP=*/nullptr, d->context(), sigma, sigma, rrect, rrect); } #endif diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrRRectBlurEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrRRectBlurEffect.h index 84eb69d48d3..32efd147c60 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrRRectBlurEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrRRectBlurEffect.h @@ -10,8 +10,9 @@ **************************************************************************************************/ #ifndef GrRRectBlurEffect_DEFINED #define GrRRectBlurEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "include/gpu/GrContext.h" #include "include/private/GrRecordingContext.h" @@ -19,21 +20,23 @@ #include "src/core/SkGpuBlurUtils.h" #include "src/core/SkRRectPriv.h" #include "src/gpu/GrCaps.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrPaint.h" #include "src/gpu/GrProxyProvider.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/GrStyle.h" +#include "src/gpu/effects/GrTextureEffect.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrRRectBlurEffect : public GrFragmentProcessor { public: - static GrSurfaceProxyView find_or_create_rrect_blur_mask(GrRecordingContext* context, - const SkRRect& rrectToDraw, - const SkISize& dimensions, - float xformedSigma) { + static std::unique_ptr<GrFragmentProcessor> find_or_create_rrect_blur_mask_fp( + GrRecordingContext* context, + const SkRRect& rrectToDraw, + const SkISize& dimensions, + float xformedSigma) { static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain(); GrUniqueKey key; GrUniqueKey::Builder builder(&key, kDomain, 9, "RoundRect Blur Mask"); @@ -49,31 +52,37 @@ public: } builder.finish(); + // It seems like we could omit this matrix and modify the shader code to not normalize + // the coords used to sample the texture effect. However, the "proxyDims" value in the + // shader is not always the actual the proxy dimensions. This is because 'dimensions' here + // was computed using integer corner radii as determined in + // SkComputeBlurredRRectParams whereas the shader code uses the float radius to compute + // 'proxyDims'. Why it draws correctly with these unequal values is a mystery for the ages. + auto m = SkMatrix::Scale(dimensions.width(), dimensions.height()); static constexpr auto kMaskOrigin = kBottomLeft_GrSurfaceOrigin; GrProxyProvider* proxyProvider = context->priv().proxyProvider(); if (auto view = proxyProvider->findCachedProxyWithColorTypeFallback( key, kMaskOrigin, GrColorType::kAlpha_8, 1)) { - return view; + return GrTextureEffect::Make(std::move(view), kPremul_SkAlphaType, m); } auto rtc = GrRenderTargetContext::MakeWithFallback( context, GrColorType::kAlpha_8, nullptr, SkBackingFit::kExact, dimensions, 1, GrMipMapped::kNo, GrProtected::kNo, kMaskOrigin); if (!rtc) { - return {}; + return nullptr; } GrPaint paint; - rtc->clear(nullptr, SK_PMColor4fTRANSPARENT, - GrRenderTargetContext::CanClearFullscreen::kYes); - rtc->drawRRect(GrNoClip(), std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw, + rtc->clear(SK_PMColor4fTRANSPARENT); + rtc->drawRRect(nullptr, std::move(paint), GrAA::kYes, SkMatrix::I(), rrectToDraw, GrStyle::SimpleFill()); GrSurfaceProxyView srcView = rtc->readSurfaceView(); if (!srcView) { - return {}; + return nullptr; } SkASSERT(srcView.asTextureProxy()); auto rtc2 = SkGpuBlurUtils::GaussianBlur(context, @@ -88,21 +97,21 @@ public: SkTileMode::kClamp, SkBackingFit::kExact); if (!rtc2) { - return {}; + return nullptr; } GrSurfaceProxyView mask = rtc2->readSurfaceView(); if (!mask) { - return {}; + return nullptr; } SkASSERT(mask.asTextureProxy()); - SkASSERT(mask.origin() == kBottomLeft_GrSurfaceOrigin); + SkASSERT(mask.origin() == kMaskOrigin); proxyProvider->assignUniqueKeyToProxy(key, mask.asTextureProxy()); - - return mask; + return GrTextureEffect::Make(std::move(mask), kPremul_SkAlphaType, m); } - static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext* context, + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrRecordingContext* context, float sigma, float xformedSigma, const SkRRect& srcRRect, @@ -110,28 +119,34 @@ public: GrRRectBlurEffect(const GrRRectBlurEffect& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "RRectBlurEffect"; } + int inputFP_index = -1; float sigma; SkRect rect; float cornerRadius; - TextureSampler ninePatchSampler; + int ninePatchFP_index = -1; private: - GrRRectBlurEffect(float sigma, + GrRRectBlurEffect(std::unique_ptr<GrFragmentProcessor> inputFP, + float sigma, SkRect rect, float cornerRadius, - GrSurfaceProxyView ninePatchSampler) + std::unique_ptr<GrFragmentProcessor> ninePatchFP) : INHERITED(kGrRRectBlurEffect_ClassID, - (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag) + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag) , sigma(sigma) , rect(rect) - , cornerRadius(cornerRadius) - , ninePatchSampler(std::move(ninePatchSampler)) { - this->setTextureSamplerCnt(1); + , cornerRadius(cornerRadius) { + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + SkASSERT(ninePatchFP); + ninePatchFP_index = this->registerExplicitlySampledChild(std::move(ninePatchFP)); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - const TextureSampler& onTextureSampler(int) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST typedef GrFragmentProcessor INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrRectBlurEffect.cpp b/chromium/third_party/skia/src/gpu/effects/generated/GrRectBlurEffect.cpp index 11180695942..689c69bb725 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrRectBlurEffect.cpp +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrRectBlurEffect.cpp @@ -25,8 +25,6 @@ public: (void)_outer; auto rect = _outer.rect; (void)rect; - auto invSixSigma = _outer.invSixSigma; - (void)invSixSigma; auto isFast = _outer.isFast; (void)isFast; highp = ((abs(rect.left()) > 16000.0 || abs(rect.top()) > 16000.0) || @@ -40,103 +38,94 @@ public: rectHVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf4_GrSLType, "rectH"); } - invSixSigmaVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, - kHalf_GrSLType, "invSixSigma"); fragBuilder->codeAppendf( - "/* key */ bool highp = %s;\nhalf xCoverage, yCoverage;\n@if (%s) {\n half x, " - "y;\n @if (highp) {\n x = max(half(%s.x - sk_FragCoord.x), " - "half(sk_FragCoord.x - %s.z));\n y = max(half(%s.y - sk_FragCoord.y), " - "half(sk_FragCoord.y - %s.w));\n } else {\n x = max(half(float(%s.x) - " - "sk_FragCoord.x), half(sk_FragCoord.x - float(%s.z)));\n y = " - "max(half(float(%s.y) - sk_FragCoord.y), half(sk_FragCoord.y - float(%s.w)));\n " - "}\n xCoverage = sample(%s, float2(half2(x * %s, 0.5))).", + R"SkSL(/* key */ bool highp = %s; +half xCoverage, yCoverage; +@if (%s) { + half2 xy; + @if (highp) { + xy = max(half2(%s.xy - sk_FragCoord.xy), half2(sk_FragCoord.xy - %s.zw)); + } else { + xy = max(half2(float2(%s.xy) - sk_FragCoord.xy), half2(sk_FragCoord.xy - float2(%s.zw))); + })SkSL", (highp ? "true" : "false"), (_outer.isFast ? "true" : "false"), rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)", rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)", - rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)", - rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)", - rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)", - rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)", - rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)", rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)", - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]), - args.fUniformHandler->getUniformCStr(invSixSigmaVar)); + rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)"); + SkString _sample7215; + SkString _coords7215("float2(half2(xy.x, 0.5))"); + _sample7215 = this->invokeChild(_outer.integral_index, args, _coords7215.c_str()); fragBuilder->codeAppendf( - "%s.w;\n yCoverage = sample(%s, float2(half2(y * %s, 0.5))).%s.w;\n %s = (%s " - "* xCoverage) * yCoverage;\n} else {\n half l, r, t, b;\n @if (highp) {\n " - " l = half(sk_FragCoord.x - %s.x);\n r = half(%s.z - sk_FragCoord.x);\n " - " t = half(sk_FragCoord.y - %s.y);\n b = half(%s.w - " - "sk_FragCoord.y);\n } else {\n l = half(sk_FragCoord.x - float(%s.x));\n " - " r = half(float(%s.z) - sk_FragCoord.x);\n t = half(sk_FragCoord.y - " - "float(%s.y));\n b = half(float(", - fragBuilder->getProgramBuilder() - ->samplerSwizzle(args.fTexSamplers[0]) - .asString() - .c_str(), - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]), - args.fUniformHandler->getUniformCStr(invSixSigmaVar), - fragBuilder->getProgramBuilder() - ->samplerSwizzle(args.fTexSamplers[0]) - .asString() - .c_str(), - args.fOutputColor, args.fInputColor, - rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)", - rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)", + R"SkSL( + xCoverage = %s.w;)SkSL", + _sample7215.c_str()); + SkString _sample7273; + SkString _coords7273("float2(half2(xy.y, 0.5))"); + _sample7273 = this->invokeChild(_outer.integral_index, args, _coords7273.c_str()); + fragBuilder->codeAppendf( + R"SkSL( + yCoverage = %s.w; +} else { + half4 rect; + @if (highp) { + rect.xy = half2(%s.xy - sk_FragCoord.xy); + rect.zw = half2(sk_FragCoord.xy - %s.zw); + } else { + rect.xy = half2(float2(%s.xy) - sk_FragCoord.xy); + rect.zw = half2(sk_FragCoord.xy - float2(%s.zw)); + })SkSL", + _sample7273.c_str(), rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)", rectFVar.isValid() ? args.fUniformHandler->getUniformCStr(rectFVar) : "float4(0)", rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)", - rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)", rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)"); + SkString _sample8640; + SkString _coords8640("float2(half2(rect.x, 0.5))"); + _sample8640 = this->invokeChild(_outer.integral_index, args, _coords8640.c_str()); + SkString _sample8703; + SkString _coords8703("float2(half2(rect.z, 0.5))"); + _sample8703 = this->invokeChild(_outer.integral_index, args, _coords8703.c_str()); fragBuilder->codeAppendf( - "%s.w) - sk_FragCoord.y);\n }\n half il = 1.0 + l * %s;\n half ir = 1.0 + " - "r * %s;\n half it = 1.0 + t * %s;\n half ib = 1.0 + b * %s;\n xCoverage " - "= (1.0 - sample(%s, float2(half2(il, 0.5))).%s.w) - sample(%s, float2(half2(ir, " - "0.5))).%s.w;\n yCoverage = (1.0 - sample(%s, float2(half2(it, 0.5))).%s.w) - " - "sample(%s, float2(half2(ib, 0.5))).%s.w;\n}\n%s = (%s * xCoverage) * yCoverage;\n", - rectHVar.isValid() ? args.fUniformHandler->getUniformCStr(rectHVar) : "half4(0)", - args.fUniformHandler->getUniformCStr(invSixSigmaVar), - args.fUniformHandler->getUniformCStr(invSixSigmaVar), - args.fUniformHandler->getUniformCStr(invSixSigmaVar), - args.fUniformHandler->getUniformCStr(invSixSigmaVar), - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]), - fragBuilder->getProgramBuilder() - ->samplerSwizzle(args.fTexSamplers[0]) - .asString() - .c_str(), - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]), - fragBuilder->getProgramBuilder() - ->samplerSwizzle(args.fTexSamplers[0]) - .asString() - .c_str(), - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]), - fragBuilder->getProgramBuilder() - ->samplerSwizzle(args.fTexSamplers[0]) - .asString() - .c_str(), - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]), - fragBuilder->getProgramBuilder() - ->samplerSwizzle(args.fTexSamplers[0]) - .asString() - .c_str(), - args.fOutputColor, args.fInputColor); + R"SkSL( + xCoverage = (1.0 - %s.w) - %s.w;)SkSL", + _sample8640.c_str(), _sample8703.c_str()); + SkString _sample8767; + SkString _coords8767("float2(half2(rect.y, 0.5))"); + _sample8767 = this->invokeChild(_outer.integral_index, args, _coords8767.c_str()); + SkString _sample8830; + SkString _coords8830("float2(half2(rect.w, 0.5))"); + _sample8830 = this->invokeChild(_outer.integral_index, args, _coords8830.c_str()); + fragBuilder->codeAppendf( + R"SkSL( + yCoverage = (1.0 - %s.w) - %s.w; +})SkSL", + _sample8767.c_str(), _sample8830.c_str()); + SkString _input8899(args.fInputColor); + SkString _sample8899; + if (_outer.inputFP_index >= 0) { + _sample8899 = this->invokeChild(_outer.inputFP_index, _input8899.c_str(), args); + } else { + _sample8899.swap(_input8899); + } + fragBuilder->codeAppendf( + R"SkSL( +half4 inputColor = %s; +%s = (inputColor * xCoverage) * yCoverage; +)SkSL", + _sample8899.c_str(), args.fOutputColor); } private: void onSetData(const GrGLSLProgramDataManager& pdman, const GrFragmentProcessor& _proc) override { const GrRectBlurEffect& _outer = _proc.cast<GrRectBlurEffect>(); - { pdman.set1f(invSixSigmaVar, (_outer.invSixSigma)); } auto rect = _outer.rect; (void)rect; UniformHandle& rectF = rectFVar; (void)rectF; UniformHandle& rectH = rectHVar; (void)rectH; - const GrSurfaceProxyView& integralView = _outer.textureSampler(0).view(); - GrTexture& integral = *integralView.proxy()->peekTexture(); - (void)integral; - UniformHandle& invSixSigma = invSixSigmaVar; - (void)invSixSigma; auto isFast = _outer.isFast; (void)isFast; @@ -146,7 +135,6 @@ private: bool highp = false; UniformHandle rectFVar; UniformHandle rectHVar; - UniformHandle invSixSigmaVar; }; GrGLSLFragmentProcessor* GrRectBlurEffect::onCreateGLSLInstance() const { return new GrGLSLRectBlurEffect(); @@ -163,32 +151,31 @@ bool GrRectBlurEffect::onIsEqual(const GrFragmentProcessor& other) const { const GrRectBlurEffect& that = other.cast<GrRectBlurEffect>(); (void)that; if (rect != that.rect) return false; - if (integral != that.integral) return false; - if (invSixSigma != that.invSixSigma) return false; if (isFast != that.isFast) return false; return true; } GrRectBlurEffect::GrRectBlurEffect(const GrRectBlurEffect& src) : INHERITED(kGrRectBlurEffect_ClassID, src.optimizationFlags()) , rect(src.rect) - , integral(src.integral) - , invSixSigma(src.invSixSigma) , isFast(src.isFast) { - this->setTextureSamplerCnt(1); + if (src.inputFP_index >= 0) { + inputFP_index = this->cloneAndRegisterChildProcessor(src.childProcessor(src.inputFP_index)); + } + { + integral_index = + this->cloneAndRegisterChildProcessor(src.childProcessor(src.integral_index)); + } } std::unique_ptr<GrFragmentProcessor> GrRectBlurEffect::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrRectBlurEffect(*this)); } -const GrFragmentProcessor::TextureSampler& GrRectBlurEffect::onTextureSampler(int index) const { - return IthTextureSampler(index, integral); -} GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrRectBlurEffect); #if GR_TEST_UTILS std::unique_ptr<GrFragmentProcessor> GrRectBlurEffect::TestCreate(GrProcessorTestData* data) { float sigma = data->fRandom->nextRangeF(3, 8); float width = data->fRandom->nextRangeF(200, 300); float height = data->fRandom->nextRangeF(200, 300); - return GrRectBlurEffect::Make(data->context(), *data->caps()->shaderCaps(), + return GrRectBlurEffect::Make(/*inputFP=*/nullptr, data->context(), *data->caps()->shaderCaps(), SkRect::MakeWH(width, height), sigma); } #endif diff --git a/chromium/third_party/skia/src/gpu/effects/generated/GrRectBlurEffect.h b/chromium/third_party/skia/src/gpu/effects/generated/GrRectBlurEffect.h index 37727a96d38..9b45f1e983e 100644 --- a/chromium/third_party/skia/src/gpu/effects/generated/GrRectBlurEffect.h +++ b/chromium/third_party/skia/src/gpu/effects/generated/GrRectBlurEffect.h @@ -10,8 +10,9 @@ **************************************************************************************************/ #ifndef GrRectBlurEffect_DEFINED #define GrRectBlurEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include <cmath> #include "include/core/SkRect.h" @@ -24,12 +25,15 @@ #include "src/gpu/GrProxyProvider.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrShaderCaps.h" +#include "src/gpu/effects/GrTextureEffect.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrRectBlurEffect : public GrFragmentProcessor { public: - static GrSurfaceProxyView CreateIntegralTexture(GrRecordingContext* context, float sixSigma) { + static std::unique_ptr<GrFragmentProcessor> MakeIntegralFP(GrRecordingContext* context, + float sixSigma) { // The texture we're producing represents the integral of a normal distribution over a // six-sigma range centered at zero. We want enough resolution so that the linear // interpolation done in texture lookup doesn't introduce noticeable artifacts. We @@ -44,11 +48,15 @@ public: builder[0] = width; builder.finish(); + SkMatrix m = SkMatrix::Scale(width / sixSigma, 1.f); + GrProxyProvider* proxyProvider = context->priv().proxyProvider(); if (sk_sp<GrTextureProxy> proxy = proxyProvider->findOrCreateProxyByUniqueKey(key)) { GrSwizzle swizzle = context->priv().caps()->getReadSwizzle(proxy->backendFormat(), GrColorType::kAlpha_8); - return {std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}; + GrSurfaceProxyView view{std::move(proxy), kTopLeft_GrSurfaceOrigin, swizzle}; + return GrTextureEffect::Make(std::move(view), kPremul_SkAlphaType, m, + GrSamplerState::Filter::kBilerp); } SkBitmap bitmap; @@ -73,10 +81,12 @@ public: } SkASSERT(view.origin() == kTopLeft_GrSurfaceOrigin); proxyProvider->assignUniqueKeyToProxy(key, view.asTextureProxy()); - return view; + return GrTextureEffect::Make(std::move(view), kPremul_SkAlphaType, m, + GrSamplerState::Filter::kBilerp); } - static std::unique_ptr<GrFragmentProcessor> Make(GrRecordingContext* context, + static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> inputFP, + GrRecordingContext* context, const GrShaderCaps& caps, const SkRect& rect, float sigma) { @@ -92,7 +102,7 @@ public: } const float sixSigma = 6 * sigma; - GrSurfaceProxyView integral = CreateIntegralTexture(context, sixSigma); + std::unique_ptr<GrFragmentProcessor> integral = MakeIntegralFP(context, sixSigma); if (!integral) { return nullptr; } @@ -110,39 +120,39 @@ public: // less than 6 sigma wide then things aren't so simple and we have to consider both the // left and right edge of the rectangle (and similar in y). bool isFast = insetRect.isSorted(); - // 1 / (6 * sigma) is the domain of the integral texture. We use the inverse to produce - // normalized texture coords from frag coord distances. - float invSixSigma = 1.f / sixSigma; return std::unique_ptr<GrFragmentProcessor>( - new GrRectBlurEffect(insetRect, std::move(integral), invSixSigma, isFast, + new GrRectBlurEffect(std::move(inputFP), insetRect, std::move(integral), isFast, GrSamplerState::Filter::kBilerp)); } GrRectBlurEffect(const GrRectBlurEffect& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "RectBlurEffect"; } + int inputFP_index = -1; SkRect rect; - TextureSampler integral; - float invSixSigma; + int integral_index = -1; bool isFast; private: - GrRectBlurEffect(SkRect rect, - GrSurfaceProxyView integral, - float invSixSigma, + GrRectBlurEffect(std::unique_ptr<GrFragmentProcessor> inputFP, + SkRect rect, + std::unique_ptr<GrFragmentProcessor> integral, bool isFast, GrSamplerState samplerParams) : INHERITED(kGrRectBlurEffect_ClassID, - (OptimizationFlags)kCompatibleWithCoverageAsAlpha_OptimizationFlag) + (OptimizationFlags)(inputFP ? ProcessorOptimizationFlags(inputFP.get()) + : kAll_OptimizationFlags) & + kCompatibleWithCoverageAsAlpha_OptimizationFlag) , rect(rect) - , integral(std::move(integral), samplerParams) - , invSixSigma(invSixSigma) , isFast(isFast) { - this->setTextureSamplerCnt(1); + if (inputFP) { + inputFP_index = this->registerChild(std::move(inputFP)); + } + SkASSERT(integral); + integral_index = this->registerExplicitlySampledChild(std::move(integral)); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - const TextureSampler& onTextureSampler(int) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST typedef GrFragmentProcessor INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/geometry/GrPathUtils.cpp b/chromium/third_party/skia/src/gpu/geometry/GrPathUtils.cpp index 625b9d6756f..55d1207c4ca 100644 --- a/chromium/third_party/skia/src/gpu/geometry/GrPathUtils.cpp +++ b/chromium/third_party/skia/src/gpu/geometry/GrPathUtils.cpp @@ -188,6 +188,7 @@ int GrPathUtils::worstCasePointCount(const SkPath& path, int* subpaths, SkScalar for (int i = 0; i < converter.countQuads(); ++i) { pointCount += quadraticPointCount(quadPts + 2*i, tol); } + [[fallthrough]]; } case SkPath::kQuad_Verb: pointCount += quadraticPointCount(pts, tol); @@ -806,7 +807,7 @@ SkCubicType GrPathUtils::getCubicKLM(const SkPoint src[4], SkMatrix* klm, double switch (type) { case SkCubicType::kCuspAtInfinity: SkASSERT(1 == t1 && 0 == s1); // Infinity. - // fallthru. + [[fallthrough]]; case SkCubicType::kLocalCusp: case SkCubicType::kSerpentine: calc_serp_kcoeffs(t0, s0, t1, s1, skipTerm, &klmCoeffs[0]); diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLBuffer.cpp b/chromium/third_party/skia/src/gpu/gl/GrGLBuffer.cpp index fc11731b736..0ac421d116d 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLBuffer.cpp +++ b/chromium/third_party/skia/src/gpu/gl/GrGLBuffer.cpp @@ -14,15 +14,17 @@ #define GL_CALL(X) GR_GL_CALL(this->glGpu()->glInterface(), X) #define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->glGpu()->glInterface(), RET, X) -#if GR_GL_CHECK_ALLOC_WITH_GET_ERROR - #define CLEAR_ERROR_BEFORE_ALLOC(iface) GrGLClearErr(iface) - #define GL_ALLOC_CALL(iface, call) GR_GL_CALL_NOERRCHECK(iface, call) - #define CHECK_ALLOC_ERROR(iface) GR_GL_GET_ERROR(iface) -#else - #define CLEAR_ERROR_BEFORE_ALLOC(iface) - #define GL_ALLOC_CALL(iface, call) GR_GL_CALL(iface, call) - #define CHECK_ALLOC_ERROR(iface) GR_GL_NO_ERROR -#endif +#define GL_ALLOC_CALL(call) \ + [&] { \ + if (this->glGpu()->glCaps().skipErrorChecks()) { \ + GR_GL_CALL(this->glGpu()->glInterface(), call); \ + return static_cast<GrGLenum>(GR_GL_NO_ERROR); \ + } else { \ + this->glGpu()->clearErrorsAndCheckForOOM(); \ + GR_GL_CALL_NOERRCHECK(this->glGpu()->glInterface(), call); \ + return this->glGpu()->getErrorAndCheckForOOM(); \ + } \ + }() #ifdef SK_DEBUG #define VALIDATE() this->validate() @@ -109,13 +111,8 @@ GrGLBuffer::GrGLBuffer(GrGLGpu* gpu, size_t size, GrGpuBufferType intendedType, GL_CALL(GenBuffers(1, &fBufferID)); if (fBufferID) { GrGLenum target = gpu->bindBuffer(fIntendedType, this); - CLEAR_ERROR_BEFORE_ALLOC(gpu->glInterface()); - // make sure driver can allocate memory for this buffer - GL_ALLOC_CALL(gpu->glInterface(), BufferData(target, - (GrGLsizeiptr) size, - data, - fUsage)); - if (CHECK_ALLOC_ERROR(gpu->glInterface()) != GR_GL_NO_ERROR) { + GrGLenum error = GL_ALLOC_CALL(BufferData(target, (GrGLsizeiptr)size, data, fUsage)); + if (error != GR_GL_NO_ERROR) { GL_CALL(DeleteBuffers(1, &fBufferID)); fBufferID = 0; } else { @@ -182,7 +179,11 @@ void GrGLBuffer::onMap() { if (!readOnly) { // Let driver know it can discard the old data if (this->glCaps().useBufferDataNullHint() || fGLSizeInBytes != this->size()) { - GL_CALL(BufferData(target, this->size(), nullptr, fUsage)); + GrGLenum error = + GL_ALLOC_CALL(BufferData(target, this->size(), nullptr, fUsage)); + if (error != GR_GL_NO_ERROR) { + return; + } } } GL_CALL_RET(fMapPtr, MapBuffer(target, readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY)); @@ -192,7 +193,10 @@ void GrGLBuffer::onMap() { GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this); // Make sure the GL buffer size agrees with fDesc before mapping. if (fGLSizeInBytes != this->size()) { - GL_CALL(BufferData(target, this->size(), nullptr, fUsage)); + GrGLenum error = GL_ALLOC_CALL(BufferData(target, this->size(), nullptr, fUsage)); + if (error != GR_GL_NO_ERROR) { + return; + } } GrGLbitfield access; if (readOnly) { @@ -211,7 +215,10 @@ void GrGLBuffer::onMap() { GrGLenum target = this->glGpu()->bindBuffer(fIntendedType, this); // Make sure the GL buffer size agrees with fDesc before mapping. if (fGLSizeInBytes != this->size()) { - GL_CALL(BufferData(target, this->size(), nullptr, fUsage)); + GrGLenum error = GL_ALLOC_CALL(BufferData(target, this->size(), nullptr, fUsage)); + if (error != GR_GL_NO_ERROR) { + return; + } } GL_CALL_RET(fMapPtr, MapBufferSubData(target, 0, this->size(), readOnly ? GR_GL_READ_ONLY : GR_GL_WRITE_ONLY)); @@ -266,7 +273,11 @@ bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) { if (this->glCaps().useBufferDataNullHint()) { if (this->size() == srcSizeInBytes) { - GL_CALL(BufferData(target, (GrGLsizeiptr) srcSizeInBytes, src, fUsage)); + GrGLenum error = + GL_ALLOC_CALL(BufferData(target, (GrGLsizeiptr)srcSizeInBytes, src, fUsage)); + if (error != GR_GL_NO_ERROR) { + return false; + } } else { // Before we call glBufferSubData we give the driver a hint using // glBufferData with nullptr. This makes the old buffer contents @@ -275,7 +286,11 @@ bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) { // assign a different allocation for the new contents to avoid // flushing the gpu past draws consuming the old contents. // TODO I think we actually want to try calling bufferData here - GL_CALL(BufferData(target, this->size(), nullptr, fUsage)); + GrGLenum error = + GL_ALLOC_CALL(BufferData(target, (GrGLsizeiptr)this->size(), nullptr, fUsage)); + if (error != GR_GL_NO_ERROR) { + return false; + } GL_CALL(BufferSubData(target, 0, (GrGLsizeiptr) srcSizeInBytes, src)); } fGLSizeInBytes = this->size(); @@ -283,7 +298,11 @@ bool GrGLBuffer::onUpdateData(const void* src, size_t srcSizeInBytes) { // Note that we're cheating on the size here. Currently no methods // allow a partial update that preserves contents of non-updated // portions of the buffer (map() does a glBufferData(..size, nullptr..)) - GL_CALL(BufferData(target, srcSizeInBytes, src, fUsage)); + GrGLenum error = + GL_ALLOC_CALL(BufferData(target, (GrGLsizeiptr)srcSizeInBytes, src, fUsage)); + if (error != GR_GL_NO_ERROR) { + return false; + } fGLSizeInBytes = srcSizeInBytes; } VALIDATE(); diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLCaps.cpp b/chromium/third_party/skia/src/gpu/gl/GrGLCaps.cpp index 062a3e10d87..dd4e89b084e 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLCaps.cpp +++ b/chromium/third_party/skia/src/gpu/gl/GrGLCaps.cpp @@ -11,6 +11,7 @@ #include "src/core/SkCompressedDataUtils.h" #include "src/core/SkTSearch.h" #include "src/core/SkTSort.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrProgramDesc.h" #include "src/gpu/GrRenderTargetProxyPriv.h" #include "src/gpu/GrShaderCaps.h" @@ -236,15 +237,8 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, fRectangleTextureSupport = true; } } else if (GR_IS_GR_GL_ES(standard)) { - if (ctxInfo.driver() == kChromium_GrGLDriver || - ctxInfo.driver() == kSwiftShader_GrGLDriver) { - fRectangleTextureSupport = ctxInfo.hasExtension("GL_ARB_texture_rectangle"); - } else { - // ANGLE will advertise the extension in ES2 contexts but actually using the texture in - // a shader requires ES3 shading language. - fRectangleTextureSupport = ctxInfo.hasExtension("GL_ANGLE_texture_rectangle") && - ctxInfo.glslGeneration() >= k330_GrGLSLGeneration; - } + fRectangleTextureSupport = ctxInfo.hasExtension("GL_ARB_texture_rectangle") || + ctxInfo.hasExtension("GL_ANGLE_texture_rectangle"); } // no WebGL support // GrCaps defaults fClampToBorderSupport to true, so disable when unsupported @@ -335,6 +329,10 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, } // No WebGL support fSkipErrorChecks = ctxInfo.driver() == kChromium_GrGLDriver; + if (GR_IS_GR_WEBGL(standard)) { + // Error checks are quite costly in webgl, especially in Chrome. + fSkipErrorChecks = true; + } /************************************************************************** * GrShaderCaps fields @@ -652,13 +650,12 @@ void GrGLCaps::init(const GrContextOptions& contextOptions, // Only in WebGL 2.0 fSemaphoreSupport = fFenceSyncSupport = version >= GR_GL_VER(2, 0); fFenceType = FenceType::kSyncObject; - } else if (ctxInfo.hasExtension("GL_ARB_sync") || ctxInfo.hasExtension("GL_APPLE_sync")) { + } else if (GR_IS_GR_GL(standard) && + (version >= GR_GL_VER(3, 2) || ctxInfo.hasExtension("GL_ARB_sync"))) { fSemaphoreSupport = fFenceSyncSupport = true; fFenceType = FenceType::kSyncObject; - } else if (GR_IS_GR_GL(standard) && version >= GR_GL_VER(3, 2)) { - fSemaphoreSupport = fFenceSyncSupport = true; - fFenceType = FenceType::kSyncObject; - } else if (GR_IS_GR_GL_ES(standard) && version >= GR_GL_VER(3, 0)) { + } else if (GR_IS_GR_GL_ES(standard) && + (version >= GR_GL_VER(3, 0) || ctxInfo.hasExtension("GL_APPLE_sync"))) { fSemaphoreSupport = fFenceSyncSupport = true; fFenceType = FenceType::kSyncObject; } else if (ctxInfo.hasExtension("GL_NV_fence")) { @@ -843,6 +840,14 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli fFBFetchRequiresEnablePerSample = true; } shaderCaps->fUsesPrecisionModifiers = true; + } else if (GR_IS_GR_GL(standard)) { + if (ctxInfo.hasExtension("GL_EXT_shader_framebuffer_fetch")) { + shaderCaps->fFBFetchNeedsCustomOutput = (version >= GR_GL_VER(3, 0)); + shaderCaps->fFBFetchSupport = true; + shaderCaps->fFBFetchColorName = "gl_LastFragData[0]"; + shaderCaps->fFBFetchExtensionString = "GL_EXT_shader_framebuffer_fetch"; + fFBFetchRequiresEnablePerSample = false; + } } else if (GR_IS_GR_WEBGL(standard)) { shaderCaps->fUsesPrecisionModifiers = true; } @@ -882,17 +887,21 @@ void GrGLCaps::initGLSL(const GrGLContextInfo& ctxInfo, const GrGLInterface* gli } } + bool hasTessellationSupport = false; if (GR_IS_GR_GL(standard)) { - shaderCaps->fTessellationSupport = - version >= GR_GL_VER(4,0) || - ctxInfo.hasExtension("GL_ARB_tessellation_shader"); - } else { - if (version >= GR_GL_VER(3,2)) { - shaderCaps->fTessellationSupport = true; - } else if (ctxInfo.hasExtension("GL_OES_tessellation_shader")) { - shaderCaps->fTessellationSupport = true; - shaderCaps->fTessellationExtensionString = "GL_OES_tessellation_shader"; - } + hasTessellationSupport = version >= GR_GL_VER(4,0) || + ctxInfo.hasExtension("GL_ARB_tessellation_shader"); + } else if (version >= GR_GL_VER(3,2)) { + hasTessellationSupport = true; + } else if (ctxInfo.hasExtension("GL_OES_tessellation_shader")) { + hasTessellationSupport = true; + shaderCaps->fTessellationExtensionString = "GL_OES_tessellation_shader"; + } + if (hasTessellationSupport) { + GR_GL_GetIntegerv(gli, GR_GL_MAX_TESS_GEN_LEVEL_OES, + &shaderCaps->fMaxTessellationSegments); + // Just in case a driver returns a negative number? + shaderCaps->fMaxTessellationSegments = std::max(0, shaderCaps->fMaxTessellationSegments); } shaderCaps->fVersionDeclString = get_glsl_version_decl_string(standard, @@ -1029,13 +1038,6 @@ void GrGLCaps::initFSAASupport(const GrContextOptions& contextOptions, fMSFBOType = kNone_MSFBOType; } } - - // We disable MSAA for all Intel GPUs. Before Gen9, performance was very bad. Even with Gen9, - // we've seen driver crashes in the wild. We don't have data on Gen11 yet. - // chromium:527565, chromium:983926 - if (kIntel_GrGLVendor == ctxInfo.vendor()) { - fMSFBOType = kNone_MSFBOType; - } } void GrGLCaps::initBlendEqationSupport(const GrGLContextInfo& ctxInfo) { @@ -3640,6 +3642,10 @@ void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo, // Tegra3 fract() seems to trigger undefined behavior for negative values, so we // must avoid this condition. shaderCaps->fCanUseFractForNegativeValues = false; + + // Seeing crashes on Tegra3 with inlined functions that have early returns. Looks like the + // do { ... break; } while (false); construct is causing a crash in the driver. + shaderCaps->fCanUseDoLoops = false; } // On Intel GPU there is an issue where it reads the second argument to atan "- %s.x" as an int @@ -3849,14 +3855,14 @@ void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo, if (ctxInfo.version() >= GR_GL_VER(4,2)) { fRequiresManualFBBarrierAfterTessellatedStencilDraw = true; } else { - shaderCaps->fTessellationSupport = false; + shaderCaps->fMaxTessellationSegments = 0; } } else { // glMemoryBarrier wasn't around until es version 3.1. if (ctxInfo.version() >= GR_GL_VER(3,1)) { fRequiresManualFBBarrierAfterTessellatedStencilDraw = true; } else { - shaderCaps->fTessellationSupport = false; + shaderCaps->fMaxTessellationSegments = 0; } } } @@ -3864,7 +3870,7 @@ void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo, if (kQualcomm_GrGLDriver == ctxInfo.driver()) { // Qualcomm fails to link programs with tessellation and does not give an error message. // http://skbug.com/9740 - shaderCaps->fTessellationSupport = false; + shaderCaps->fMaxTessellationSegments = 0; } #ifdef SK_BUILD_FOR_WIN @@ -3937,8 +3943,10 @@ void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo, #ifdef SK_BUILD_FOR_MAC // On a MacBookPro 11.5 running MacOS 10.13 with a Radeon M370X the TransferPixelsFrom test // fails when transferring out from a GL_RG8 texture using GL_RG/GL_UNSIGNED_BYTE. + // The same error also occurs in MacOS 10.15 with a Radeon Pro 5300M. formatWorkarounds->fDisallowDirectRG8ReadPixels = ctxInfo.renderer() == kAMDRadeonR9M3xx_GrGLRenderer || + ctxInfo.renderer() == kAMDRadeonPro5xxx_GrGLRenderer || ctxInfo.renderer() == kAMDRadeonProVegaxx_GrGLRenderer; #endif @@ -3987,6 +3995,24 @@ void GrGLCaps::applyDriverCorrectnessWorkarounds(const GrGLContextInfo& ctxInfo, if (ctxInfo.angleBackend() == GrGLANGLEBackend::kD3D9) { formatWorkarounds->fDisallowBGRA8ReadPixels = true; } + + // We disable MSAA for all Intel GPUs. Before Gen9, performance was very bad. Even with Gen9, + // we've seen driver crashes in the wild. We don't have data on Gen11 yet. + // (crbug.com/527565, crbug.com/983926) + if (kIntel_GrGLVendor == ctxInfo.vendor()) { + fMSFBOType = kNone_MSFBOType; + } + + // ANGLE doesn't support do-while loops + if (kANGLE_GrGLDriver == ctxInfo.driver()) { + shaderCaps->fCanUseDoLoops = false; + } + + // ANGLE's D3D9 backend + AMD GPUs are flaky with program binary caching (skbug.com/10395) + if (ctxInfo.angleBackend() == GrGLANGLEBackend::kD3D9 && + ctxInfo.angleVendor() == GrGLANGLEVendor::kAMD) { + fProgramBinarySupport = false; + } } void GrGLCaps::onApplyOptionsOverrides(const GrContextOptions& options) { @@ -4066,6 +4092,7 @@ size_t offset_alignment_for_transfer_buffer(GrGLenum externalType) { case GR_GL_UNSIGNED_INT: return sizeof(GrGLuint); case GR_GL_INT: return sizeof(GrGLint); case GR_GL_HALF_FLOAT: return sizeof(GrGLhalf); + case GR_GL_HALF_FLOAT_OES: return sizeof(GrGLhalf); case GR_GL_FLOAT: return sizeof(GrGLfloat); case GR_GL_UNSIGNED_SHORT_5_6_5: return sizeof(GrGLushort); case GR_GL_UNSIGNED_SHORT_4_4_4_4: return sizeof(GrGLushort); @@ -4094,7 +4121,7 @@ GrCaps::SupportedRead GrGLCaps::onSupportedReadPixelsColorType( GrColorType srcColorType, const GrBackendFormat& srcBackendFormat, GrColorType dstColorType) const { - SkImage::CompressionType compression = this->compressionType(srcBackendFormat); + SkImage::CompressionType compression = GrBackendFormatToCompressionType(srcBackendFormat); if (compression != SkImage::CompressionType::kNone) { return { SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x : GrColorType::kRGBA_8888, @@ -4174,25 +4201,10 @@ bool GrGLCaps::isFormatSRGB(const GrBackendFormat& format) const { return format.asGLFormat() == GrGLFormat::kSRGB8_ALPHA8; } -SkImage::CompressionType GrGLCaps::compressionType(const GrBackendFormat& format) const { - auto fmt = format.asGLFormat(); - - switch (fmt) { - case GrGLFormat::kCOMPRESSED_ETC1_RGB8: // same compression layout as ETC2_RGB8_UNORM - case GrGLFormat::kCOMPRESSED_RGB8_ETC2: - return SkImage::CompressionType::kETC2_RGB8_UNORM; - case GrGLFormat::kCOMPRESSED_RGB8_BC1: - return SkImage::CompressionType::kBC1_RGB8_UNORM; - case GrGLFormat::kCOMPRESSED_RGBA8_BC1: - return SkImage::CompressionType::kBC1_RGBA8_UNORM; - default: - return SkImage::CompressionType::kNone; - } - - SkUNREACHABLE; -} - bool GrGLCaps::isFormatTexturable(const GrBackendFormat& format) const { + if (format.textureType() == GrTextureType::kRectangle && !this->rectangleTextureSupport()) { + return false; + } return this->isFormatTexturable(format.asGLFormat()); } @@ -4203,6 +4215,12 @@ bool GrGLCaps::isFormatTexturable(GrGLFormat format) const { bool GrGLCaps::isFormatAsColorTypeRenderable(GrColorType ct, const GrBackendFormat& format, int sampleCount) const { + if (format.textureType() == GrTextureType::kRectangle && !this->rectangleTextureSupport()) { + return false; + } + if (format.textureType() == GrTextureType::kExternal) { + return false; + } auto f = format.asGLFormat(); const FormatInfo& info = this->getFormatInfo(f); if (!SkToBool(info.colorTypeFlags(ct) & ColorTypeInfo::kRenderable_Flag)) { @@ -4213,6 +4231,12 @@ bool GrGLCaps::isFormatAsColorTypeRenderable(GrColorType ct, const GrBackendForm } bool GrGLCaps::isFormatRenderable(const GrBackendFormat& format, int sampleCount) const { + if (format.textureType() == GrTextureType::kRectangle && !this->rectangleTextureSupport()) { + return false; + } + if (format.textureType() == GrTextureType::kExternal) { + return false; + } return this->isFormatRenderable(format.asGLFormat(), sampleCount); } @@ -4324,13 +4348,6 @@ void GrGLCaps::didQueryImplementationReadSupport(GrGLFormat format, bool GrGLCaps::onAreColorTypeAndFormatCompatible(GrColorType ct, const GrBackendFormat& format) const { GrGLFormat glFormat = format.asGLFormat(); - - SkImage::CompressionType compression = GrGLFormatToCompressionType(glFormat); - if (compression != SkImage::CompressionType::kNone) { - return ct == (SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x - : GrColorType::kRGBA_8888); - } - const auto& info = this->getFormatInfo(glFormat); for (int i = 0; i < info.fColorTypeInfoCount; ++i) { if (info.fColorTypeInfos[i].fColorType == ct) { @@ -4379,8 +4396,9 @@ GrBackendFormat GrGLCaps::getBackendFormatFromCompressionType( SkUNREACHABLE; } -GrSwizzle GrGLCaps::getReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const { - const auto& info = this->getFormatInfo(format.asGLFormat()); +GrSwizzle GrGLCaps::onGetReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const { + GrGLFormat glFormat = format.asGLFormat(); + const auto& info = this->getFormatInfo(glFormat); for (int i = 0; i < info.fColorTypeInfoCount; ++i) { const auto& ctInfo = info.fColorTypeInfos[i]; if (ctInfo.fColorType == colorType) { @@ -4388,7 +4406,7 @@ GrSwizzle GrGLCaps::getReadSwizzle(const GrBackendFormat& format, GrColorType co } } SkDEBUGFAILF("Illegal color type (%d) and format (%d) combination.", colorType, - format.asGLFormat()); + glFormat); return {}; } @@ -4481,7 +4499,15 @@ std::vector<GrCaps::TestFormatColorTypeCombination> GrGLCaps::getTestingCombinat combos.push_back({ GrColorType::kBGRA_8888, GrBackendFormat::MakeGL(GR_GL_BGRA8, GR_GL_TEXTURE_2D) }); } - + if (this->rectangleTextureSupport()) { + size_t count2D = combos.size(); + for (size_t i = 0; i < count2D; ++i) { + auto combo2D = combos[i]; + GrGLenum formatEnum = GrGLFormatToEnum(combo2D.fFormat.asGLFormat()); + combos.push_back({combo2D.fColorType, + GrBackendFormat::MakeGL(formatEnum, GR_GL_TEXTURE_RECTANGLE)}); + } + } return combos; } #endif diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLCaps.h b/chromium/third_party/skia/src/gpu/gl/GrGLCaps.h index 1371b26c28b..8ee8e9b84b5 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLCaps.h +++ b/chromium/third_party/skia/src/gpu/gl/GrGLCaps.h @@ -114,7 +114,6 @@ public: const GrGLInterface* glInterface); bool isFormatSRGB(const GrBackendFormat&) const override; - SkImage::CompressionType compressionType(const GrBackendFormat&) const override; bool isFormatTexturable(const GrBackendFormat&) const override; bool isFormatTexturable(GrGLFormat) const; @@ -441,7 +440,6 @@ public: GrBackendFormat getBackendFormatFromCompressionType(SkImage::CompressionType) const override; - GrSwizzle getReadSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getWriteSwizzle(const GrBackendFormat&, GrColorType) const override; uint64_t computeFormatKey(const GrBackendFormat&) const override; @@ -502,6 +500,8 @@ private: SupportedRead onSupportedReadPixelsColorType(GrColorType, const GrBackendFormat&, GrColorType) const override; + GrSwizzle onGetReadSwizzle(const GrBackendFormat&, GrColorType) const override; + GrGLStandard fStandard = kNone_GrGLStandard; SkTArray<StencilFormat, true> fStencilFormats; diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLDefines.h b/chromium/third_party/skia/src/gpu/gl/GrGLDefines.h index a2ac31561c5..8fde6be2ebb 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLDefines.h +++ b/chromium/third_party/skia/src/gpu/gl/GrGLDefines.h @@ -1140,4 +1140,7 @@ /** GL_NV_fence_sync */ #define GR_GL_ALL_COMPLETED 0x84F2 +/* Tessellation */ +#define GR_GL_MAX_TESS_GEN_LEVEL_OES 0x8E7E + #endif diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLGpu.cpp b/chromium/third_party/skia/src/gpu/gl/GrGLGpu.cpp index f1d744d3307..24d4318d6ad 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLGpu.cpp +++ b/chromium/third_party/skia/src/gpu/gl/GrGLGpu.cpp @@ -19,10 +19,10 @@ #include "src/core/SkConvertPixels.h" #include "src/core/SkMipMap.h" #include "src/core/SkTraceEvent.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrCpuBuffer.h" #include "src/gpu/GrDataUtils.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrGpuResourcePriv.h" #include "src/gpu/GrPipeline.h" #include "src/gpu/GrProgramInfo.h" @@ -50,9 +50,9 @@ GR_GL_CALL(this->glInterface(), call); \ return static_cast<GrGLenum>(GR_GL_NO_ERROR); \ } else { \ - GrGLClearErr(this->glInterface()); \ + this->clearErrorsAndCheckForOOM(); \ GR_GL_CALL_NOERRCHECK(this->glInterface(), call); \ - return GR_GL_GET_ERROR(this->glInterface()); \ + return this->getErrorAndCheckForOOM(); \ } \ }() @@ -333,7 +333,11 @@ GrGLGpu::GrGLGpu(std::unique_ptr<GrGLContext> ctx, GrContext* context) , fStencilClearFBOID(0) , fFinishCallbacks(this) { SkASSERT(fGLContext); - GrGLClearErr(this->glInterface()); + // Clear errors so we don't get confused whether we caused an error. + this->clearErrorsAndCheckForOOM(); + // Toss out any pre-existing OOM that was hanging around before we got started. + this->checkAndResetOOMed(); + fCaps = sk_ref_sp(fGLContext->caps()); fHWTextureUnitBindings.reset(this->numTextureUnits()); @@ -837,9 +841,10 @@ bool GrGLGpu::onWritePixels(GrSurface* surface, int left, int top, int width, in this->bindTextureToScratchUnit(glTex->target(), glTex->textureID()); SkASSERT(!GrGLFormatIsCompressed(glTex->format())); - return this->uploadTexData(glTex->format(), surfaceColorType, glTex->width(), glTex->height(), - glTex->target(), left, top, width, height, srcColorType, texels, - mipLevelCount); + SkIRect dstRect = SkIRect::MakeXYWH(left, top, width, height); + return this->uploadColorTypeTexData(glTex->format(), surfaceColorType, glTex->dimensions(), + glTex->target(), dstRect, srcColorType, texels, + mipLevelCount); } bool GrGLGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int width, int height, @@ -931,33 +936,21 @@ void GrGLGpu::unbindCpuToGpuXferBuffer() { } } -bool GrGLGpu::uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType, int texWidth, - int texHeight, GrGLenum target, int left, int top, int width, - int height, GrColorType srcColorType, const GrMipLevel texels[], - int mipLevelCount, GrMipMapsStatus* mipMapsStatus) { +bool GrGLGpu::uploadColorTypeTexData(GrGLFormat textureFormat, + GrColorType textureColorType, + SkISize texDims, + GrGLenum target, + SkIRect dstRect, + GrColorType srcColorType, + const GrMipLevel texels[], + int mipLevelCount) { // If we're uploading compressed data then we should be using uploadCompressedTexData SkASSERT(!GrGLFormatIsCompressed(textureFormat)); SkASSERT(this->glCaps().isFormatTexturable(textureFormat)); - SkDEBUGCODE( - SkIRect subRect = SkIRect::MakeXYWH(left, top, width, height); - SkIRect bounds = SkIRect::MakeWH(texWidth, texHeight); - SkASSERT(bounds.contains(subRect)); - ) - SkASSERT(1 == mipLevelCount || - (0 == left && 0 == top && width == texWidth && height == texHeight)); - - this->unbindCpuToGpuXferBuffer(); - - const GrGLInterface* interface = this->glInterface(); - const GrGLCaps& caps = this->glCaps(); size_t bpp = GrColorTypeBytesPerPixel(srcColorType); - if (width == 0 || height == 0) { - return false; - } - // External format and type come from the upload data. GrGLenum externalFormat; GrGLenum externalType; @@ -966,52 +959,100 @@ bool GrGLGpu::uploadTexData(GrGLFormat textureFormat, GrColorType textureColorTy if (!externalFormat || !externalType) { return false; } + this->uploadTexData(texDims, target, dstRect, externalFormat, externalType, bpp, texels, + mipLevelCount); + return true; +} - /* - * Check whether to allocate a temporary buffer for flipping y or - * because our srcData has extra bytes past each row. If so, we need - * to trim those off here, since GL ES may not let us specify - * GL_UNPACK_ROW_LENGTH. - */ - bool restoreGLRowLength = false; +bool GrGLGpu::uploadColorToTex(GrGLFormat textureFormat, + SkISize texDims, + GrGLenum target, + SkColor4f color, + uint32_t levelMask) { + GrColorType colorType; + GrGLenum externalFormat, externalType; + this->glCaps().getTexSubImageDefaultFormatTypeAndColorType(textureFormat, &externalFormat, + &externalType, &colorType); + if (colorType == GrColorType::kUnknown) { + return false; + } - if (mipMapsStatus) { - *mipMapsStatus = (mipLevelCount > 1) ? - GrMipMapsStatus::kValid : GrMipMapsStatus::kNotAllocated; + std::unique_ptr<char[]> pixelStorage; + size_t bpp = 0; + int numLevels = SkMipMap::ComputeLevelCount(texDims) + 1; + SkSTArray<16, GrMipLevel> levels; + levels.resize(numLevels); + SkISize levelDims = texDims; + for (int i = 0; i < numLevels; ++i, levelDims = {std::max(levelDims.width() >> 1, 1), + std::max(levelDims.height() >> 1, 1)}) { + if (levelMask & (1 << i)) { + if (!pixelStorage) { + // Make one tight image at the first size and reuse it for smaller levels. + GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, levelDims); + size_t rb = ii.minRowBytes(); + pixelStorage.reset(new char[rb * levelDims.height()]); + if (!GrClearImage(ii, pixelStorage.get(), ii.minRowBytes(), color)) { + return false; + } + bpp = ii.bpp(); + } + levels[i] = {pixelStorage.get(), levelDims.width()*bpp}; + } } + this->uploadTexData(texDims, target, SkIRect::MakeSize(texDims), externalFormat, externalType, + bpp, levels.begin(), levels.count()); + return true; +} - GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1)); +void GrGLGpu::uploadTexData(SkISize texDims, + GrGLenum target, + SkIRect dstRect, + GrGLenum externalFormat, + GrGLenum externalType, + size_t bpp, + const GrMipLevel texels[], + int mipLevelCount) { + SkASSERT(!texDims.isEmpty()); + SkASSERT(!dstRect.isEmpty()); + SkASSERT(SkIRect::MakeSize(texDims).contains(dstRect)); + SkASSERT(mipLevelCount > 0 && mipLevelCount <= SkMipMap::ComputeLevelCount(texDims) + 1); + SkASSERT(mipLevelCount == 1 || dstRect == SkIRect::MakeSize(texDims)); - for (int currentMipLevel = 0; currentMipLevel < mipLevelCount; currentMipLevel++) { - if (!texels[currentMipLevel].fPixels) { - if (mipMapsStatus) { - *mipMapsStatus = GrMipMapsStatus::kDirty; - } + const GrGLCaps& caps = this->glCaps(); + + bool restoreGLRowLength = false; + + this->unbindCpuToGpuXferBuffer(); + GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1)); + + SkISize dims = dstRect.size(); + for (int level = 0; level < mipLevelCount; ++level, dims = {std::max(dims.width() >> 1, 1), + std::max(dims.height() >> 1, 1)}) { + if (!texels[level].fPixels) { continue; } - int twoToTheMipLevel = 1 << currentMipLevel; - const int currentWidth = std::max(1, width / twoToTheMipLevel); - const int currentHeight = std::max(1, height / twoToTheMipLevel); - const size_t trimRowBytes = currentWidth * bpp; - const size_t rowBytes = texels[currentMipLevel].fRowBytes; + const size_t trimRowBytes = dims.width() * bpp; + const size_t rowBytes = texels[level].fRowBytes; if (caps.writePixelsRowBytesSupport() && (rowBytes != trimRowBytes || restoreGLRowLength)) { GrGLint rowLength = static_cast<GrGLint>(rowBytes / bpp); - GR_GL_CALL(interface, PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength)); + GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, rowLength)); restoreGLRowLength = true; + } else { + SkASSERT(rowBytes == trimRowBytes); } - GL_CALL(TexSubImage2D(target, currentMipLevel, left, top, currentWidth, currentHeight, - externalFormat, externalType, texels[currentMipLevel].fPixels)); + GL_CALL(TexSubImage2D(target, level, dstRect.x(), dstRect.y(), dims.width(), dims.height(), + externalFormat, externalType, texels[level].fPixels)); } if (restoreGLRowLength) { SkASSERT(caps.writePixelsRowBytesSupport()); GL_CALL(PixelStorei(GR_GL_UNPACK_ROW_LENGTH, 0)); } - return true; } -bool GrGLGpu::uploadCompressedTexData(GrGLFormat format, +bool GrGLGpu::uploadCompressedTexData(SkImage::CompressionType compressionType, + GrGLFormat format, SkISize dimensions, GrMipMapped mipMapped, GrGLenum target, @@ -1025,7 +1066,6 @@ bool GrGLGpu::uploadCompressedTexData(GrGLFormat format, return false; } - SkImage::CompressionType compressionType = GrGLFormatToCompressionType(format); SkASSERT(compressionType != SkImage::CompressionType::kNone); bool useTexStorage = caps.formatSupportsTexStorage(format); @@ -1250,14 +1290,27 @@ sk_sp<GrTexture> GrGLGpu::onCreateTexture(SkISize dimensions, GrGLTextureParameters::SamplerOverriddenState initialState; GrGLTexture::Desc texDesc; texDesc.fSize = dimensions; - texDesc.fTarget = GR_GL_TEXTURE_2D; + switch (format.textureType()) { + case GrTextureType::kExternal: + case GrTextureType::kNone: + return nullptr; + case GrTextureType::k2D: + texDesc.fTarget = GR_GL_TEXTURE_2D; + break; + case GrTextureType::kRectangle: + if (mipLevelCount > 1 || !this->glCaps().rectangleTextureSupport()) { + return nullptr; + } + texDesc.fTarget = GR_GL_TEXTURE_RECTANGLE; + break; + } texDesc.fFormat = format.asGLFormat(); texDesc.fOwnership = GrBackendObjectOwnership::kOwned; SkASSERT(texDesc.fFormat != GrGLFormat::kUnknown); SkASSERT(!GrGLFormatIsCompressed(texDesc.fFormat)); - texDesc.fID = this->createTexture2D(dimensions, texDesc.fFormat, renderable, &initialState, - mipLevelCount); + texDesc.fID = this->createTexture(dimensions, texDesc.fFormat, texDesc.fTarget, renderable, + &initialState, mipLevelCount); if (!texDesc.fID) { return return_null_texture(); @@ -1283,11 +1336,11 @@ sk_sp<GrTexture> GrGLGpu::onCreateTexture(SkISize dimensions, tex->parameters()->set(&initialState, GrGLTextureParameters::NonsamplerState(), fResetTimestampForTextureParameters); if (levelClearMask) { - GrGLenum externalFormat, externalType; - GrColorType colorType; - this->glCaps().getTexSubImageDefaultFormatTypeAndColorType(texDesc.fFormat, &externalFormat, - &externalType, &colorType); if (this->glCaps().clearTextureSupport()) { + GrGLenum externalFormat, externalType; + GrColorType colorType; + this->glCaps().getTexSubImageDefaultFormatTypeAndColorType( + texDesc.fFormat, &externalFormat, &externalType, &colorType); for (int i = 0; i < mipLevelCount; ++i) { if (levelClearMask & (1U << i)) { GL_CALL(ClearTexImage(tex->textureID(), i, externalFormat, externalType, @@ -1310,24 +1363,10 @@ sk_sp<GrTexture> GrGLGpu::onCreateTexture(SkISize dimensions, } fHWBoundRenderTargetUniqueID.makeInvalid(); } else { - std::unique_ptr<char[]> zeros; - GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1)); - for (int i = 0; i < mipLevelCount; ++i) { - if (levelClearMask & (1U << i)) { - int levelWidth = std::max(1, texDesc.fSize.width() >> i); - int levelHeight = std::max(1, texDesc.fSize.height() >> i); - // Levels only get smaller as we proceed. Once we create a zeros use it for all - // smaller levels that need clearing. - if (!zeros) { - size_t bpp = GrColorTypeBytesPerPixel(colorType); - size_t size = levelWidth * levelHeight * bpp; - zeros.reset(new char[size]()); - } - this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, tex->textureID()); - GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D, i, 0, 0, levelWidth, levelHeight, - externalFormat, externalType, zeros.get())); - } - } + this->bindTextureToScratchUnit(texDesc.fTarget, tex->textureID()); + static constexpr SkColor4f kZeroColor = {0, 0, 0, 0}; + this->uploadColorToTex(texDesc.fFormat, texDesc.fSize, texDesc.fTarget, kZeroColor, + levelClearMask); } } return std::move(tex); @@ -1343,13 +1382,15 @@ sk_sp<GrTexture> GrGLGpu::onCreateCompressedTexture(SkISize dimensions, if (isProtected == GrProtected::kYes) { return nullptr; } + SkImage::CompressionType compression = GrBackendFormatToCompressionType(format); + GrGLTextureParameters::SamplerOverriddenState initialState; GrGLTexture::Desc desc; desc.fSize = dimensions; desc.fTarget = GR_GL_TEXTURE_2D; desc.fOwnership = GrBackendObjectOwnership::kOwned; desc.fFormat = format.asGLFormat(); - desc.fID = this->createCompressedTexture2D(desc.fSize, desc.fFormat, + desc.fID = this->createCompressedTexture2D(desc.fSize, compression, desc.fFormat, mipMapped, &initialState, data, dataSize); if (!desc.fID) { @@ -1386,16 +1427,16 @@ GrBackendTexture GrGLGpu::onCreateCompressedBackendTexture( return {}; } + SkImage::CompressionType compression = GrBackendFormatToCompressionType(format); + const char* rawData = nullptr; size_t rawDataSize = 0; SkAutoMalloc am; - SkASSERT(!data || data->type() != BackendTextureData::Type::kPixmaps); if (data && data->type() == BackendTextureData::Type::kCompressed) { rawData = (const char*) data->compressedData(); rawDataSize = data->compressedSize(); } else if (data && data->type() == BackendTextureData::Type::kColor) { - SkImage::CompressionType compression = GrGLFormatToCompressionType(glFormat); SkASSERT(compression != SkImage::CompressionType::kNone); rawDataSize = SkCompressedDataSize(compression, dimensions, nullptr, @@ -1413,7 +1454,7 @@ GrBackendTexture GrGLGpu::onCreateCompressedBackendTexture( info.fTarget = GR_GL_TEXTURE_2D; info.fFormat = GrGLFormatToEnum(glFormat); - info.fID = this->createCompressedTexture2D(dimensions, glFormat, + info.fID = this->createCompressedTexture2D(dimensions, compression, glFormat, mipMapped, &initialState, rawData, rawDataSize); if (!info.fID) { @@ -1466,8 +1507,8 @@ int GrGLGpu::getCompatibleStencilIndex(GrGLFormat format) { // Default to unsupported, set this if we find a stencil format that works. int firstWorkingStencilFormatIndex = -1; - GrGLuint colorID = - this->createTexture2D({kSize, kSize}, format, GrRenderable::kYes, nullptr, 1); + GrGLuint colorID = this->createTexture({kSize, kSize}, format, GR_GL_TEXTURE_2D, + GrRenderable::kYes, nullptr, 1); if (!colorID) { return -1; } @@ -1536,6 +1577,7 @@ int GrGLGpu::getCompatibleStencilIndex(GrGLFormat format) { GrGLuint GrGLGpu::createCompressedTexture2D( SkISize dimensions, + SkImage::CompressionType compression, GrGLFormat format, GrMipMapped mipMapped, GrGLTextureParameters::SamplerOverriddenState* initialState, @@ -1554,7 +1596,7 @@ GrGLuint GrGLGpu::createCompressedTexture2D( *initialState = set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D); if (data) { - if (!this->uploadCompressedTexData(format, dimensions, mipMapped, + if (!this->uploadCompressedTexData(compression, format, dimensions, mipMapped, GR_GL_TEXTURE_2D, data, dataSize)) { GL_CALL(DeleteTextures(1, &id)); return 0; @@ -1564,11 +1606,12 @@ GrGLuint GrGLGpu::createCompressedTexture2D( return id; } -GrGLuint GrGLGpu::createTexture2D(SkISize dimensions, - GrGLFormat format, - GrRenderable renderable, - GrGLTextureParameters::SamplerOverriddenState* initialState, - int mipLevelCount) { +GrGLuint GrGLGpu::createTexture(SkISize dimensions, + GrGLFormat format, + GrGLenum target, + GrRenderable renderable, + GrGLTextureParameters::SamplerOverriddenState* initialState, + int mipLevelCount) { SkASSERT(format != GrGLFormat::kUnknown); SkASSERT(!GrGLFormatIsCompressed(format)); @@ -1579,17 +1622,17 @@ GrGLuint GrGLGpu::createTexture2D(SkISize dimensions, return 0; } - this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, id); + this->bindTextureToScratchUnit(target, id); if (GrRenderable::kYes == renderable && this->glCaps().textureUsageSupport()) { // provides a hint about how this texture will be used - GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_USAGE, GR_GL_FRAMEBUFFER_ATTACHMENT)); + GL_CALL(TexParameteri(target, GR_GL_TEXTURE_USAGE, GR_GL_FRAMEBUFFER_ATTACHMENT)); } if (initialState) { - *initialState = set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D); + *initialState = set_initial_texture_params(this->glInterface(), target); } else { - set_initial_texture_params(this->glInterface(), GR_GL_TEXTURE_2D); + set_initial_texture_params(this->glInterface(), target); } GrGLenum internalFormat = this->glCaps().getTexImageOrStorageInternalFormat(format); @@ -1598,9 +1641,8 @@ GrGLuint GrGLGpu::createTexture2D(SkISize dimensions, if (internalFormat) { if (this->glCaps().formatSupportsTexStorage(format)) { auto levelCount = std::max(mipLevelCount, 1); - GrGLenum error = - GL_ALLOC_CALL(TexStorage2D(GR_GL_TEXTURE_2D, levelCount, internalFormat, - dimensions.width(), dimensions.height())); + GrGLenum error = GL_ALLOC_CALL(TexStorage2D(target, levelCount, internalFormat, + dimensions.width(), dimensions.height())); success = (error == GR_GL_NO_ERROR); } else { GrGLenum externalFormat, externalType; @@ -1611,9 +1653,9 @@ GrGLuint GrGLGpu::createTexture2D(SkISize dimensions, const int twoToTheMipLevel = 1 << level; const int currentWidth = std::max(1, dimensions.width() / twoToTheMipLevel); const int currentHeight = std::max(1, dimensions.height() / twoToTheMipLevel); - error = GL_ALLOC_CALL(TexImage2D(GR_GL_TEXTURE_2D, level, internalFormat, - currentWidth, currentHeight, 0, externalFormat, - externalType, nullptr)); + error = GL_ALLOC_CALL(TexImage2D(target, level, internalFormat, currentWidth, + currentHeight, 0, externalFormat, externalType, + nullptr)); } success = (error == GR_GL_NO_ERROR); } @@ -1748,8 +1790,7 @@ void GrGLGpu::disableWindowRectangles() { #endif } -bool GrGLGpu::flushGLState(GrRenderTarget* renderTarget, - const GrProgramInfo& programInfo) { +bool GrGLGpu::flushGLState(GrRenderTarget* renderTarget, const GrProgramInfo& programInfo) { this->handleDirtyContext(); sk_sp<GrGLProgram> program = fProgramCache->findOrCreateProgram(renderTarget, programInfo); @@ -1847,51 +1888,29 @@ GrGLenum GrGLGpu::bindBuffer(GrGpuBufferType type, const GrBuffer* buffer) { return bufferState->fGLTarget; } -void GrGLGpu::clear(const GrFixedClip& clip, const SkPMColor4f& color, +void GrGLGpu::clear(const GrScissorState& scissor, const SkPMColor4f& color, GrRenderTarget* target, GrSurfaceOrigin origin) { // parent class should never let us get here with no RT SkASSERT(target); SkASSERT(!this->caps()->performColorClearsAsDraws()); - SkASSERT(!clip.scissorEnabled() || !this->caps()->performPartialClearsAsDraws()); + SkASSERT(!scissor.enabled() || !this->caps()->performPartialClearsAsDraws()); this->handleDirtyContext(); GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target); - if (clip.scissorEnabled()) { - this->flushRenderTarget(glRT, origin, clip.scissorRect()); + if (scissor.enabled()) { + this->flushRenderTarget(glRT, origin, scissor.rect()); } else { this->flushRenderTarget(glRT); } - this->flushScissor(clip.scissorState(), glRT->width(), glRT->height(), origin); - this->flushWindowRectangles(clip.windowRectsState(), glRT, origin); + this->flushScissor(scissor, glRT->width(), glRT->height(), origin); + this->disableWindowRectangles(); this->flushColorWrite(true); this->flushClearColor(color); GL_CALL(Clear(GR_GL_COLOR_BUFFER_BIT)); } -void GrGLGpu::clearStencil(GrRenderTarget* target, int clearValue) { - SkASSERT(!this->caps()->performStencilClearsAsDraws()); - - if (!target) { - return; - } - - // This should only be called internally when we know we have a stencil buffer. - SkASSERT(target->renderTargetPriv().getStencilAttachment()); - - GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target); - this->flushRenderTargetNoColorWrites(glRT); - - this->flushScissorTest(GrScissorTest::kDisabled); - this->disableWindowRectangles(); - - GL_CALL(StencilMask(0xffffffff)); - GL_CALL(ClearStencil(clearValue)); - GL_CALL(Clear(GR_GL_STENCIL_BUFFER_BIT)); - fHWStencilSettings.invalidate(); -} - static bool use_tiled_rendering(const GrGLCaps& glCaps, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilLoadStore) { // Only use the tiled rendering extension if we can explicitly clear and discard the stencil. @@ -1989,11 +2008,11 @@ void GrGLGpu::endCommandBuffer(GrRenderTarget* rt, SkDEBUGCODE(fIsExecutingCommandBuffer_DebugOnly = false); } -void GrGLGpu::clearStencilClip(const GrFixedClip& clip, - bool insideStencilMask, +void GrGLGpu::clearStencilClip(const GrScissorState& scissor, bool insideStencilMask, GrRenderTarget* target, GrSurfaceOrigin origin) { SkASSERT(target); SkASSERT(!this->caps()->performStencilClearsAsDraws()); + SkASSERT(!scissor.enabled() || !this->caps()->performPartialClearsAsDraws()); this->handleDirtyContext(); GrStencilAttachment* sb = target->renderTargetPriv().getStencilAttachment(); @@ -2024,8 +2043,8 @@ void GrGLGpu::clearStencilClip(const GrFixedClip& clip, GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(target); this->flushRenderTargetNoColorWrites(glRT); - this->flushScissor(clip.scissorState(), glRT->width(), glRT->height(), origin); - this->flushWindowRectangles(clip.windowRectsState(), glRT, origin); + this->flushScissor(scissor, glRT->width(), glRT->height(), origin); + this->disableWindowRectangles(); GL_CALL(StencilMask((uint32_t) clipStencilMask)); GL_CALL(ClearStencil(value)); @@ -2136,7 +2155,8 @@ bool GrGLGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int } GrOpsRenderPass* GrGLGpu::getOpsRenderPass( - GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds, + GrRenderTarget* rt, GrStencilAttachment*, + GrSurfaceOrigin origin, const SkIRect& bounds, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { @@ -2258,11 +2278,11 @@ void GrGLGpu::onResolveRenderTarget(GrRenderTarget* target, const SkIRect& resol fHWBoundRenderTargetUniqueID.makeInvalid(); if (GrGLCaps::kES_Apple_MSFBOType == this->glCaps().msFBOType()) { // Apple's extension uses the scissor as the blit bounds. - GrScissorState scissorState; - scissorState.set(resolveRect); // Passing in kTopLeft_GrSurfaceOrigin will make sure no transformation of the rect // happens inside flushScissor since resolveRect is already in native device coordinates. - this->flushScissor(scissorState, rt->width(), rt->height(), kTopLeft_GrSurfaceOrigin); + GrScissorState scissor(rt->dimensions()); + SkAssertResult(scissor.set(resolveRect)); + this->flushScissor(scissor, rt->width(), rt->height(), kTopLeft_GrSurfaceOrigin); this->disableWindowRectangles(); GL_CALL(ResolveMultisampleFramebuffer()); } else { @@ -3547,16 +3567,29 @@ GrBackendTexture GrGLGpu::onCreateBackendTexture(SkISize dimensions, if (glFormat == GrGLFormat::kUnknown) { return {}; } - - info.fTarget = GR_GL_TEXTURE_2D; + switch (format.textureType()) { + case GrTextureType::kNone: + case GrTextureType::kExternal: + return {}; + case GrTextureType::k2D: + info.fTarget = GR_GL_TEXTURE_2D; + break; + case GrTextureType::kRectangle: + if (!this->glCaps().rectangleTextureSupport() || mipMapped == GrMipMapped::kYes) { + return {}; + } + info.fTarget = GR_GL_TEXTURE_RECTANGLE; + break; + } info.fFormat = GrGLFormatToEnum(glFormat); - info.fID = this->createTexture2D(dimensions, glFormat, renderable, &initialState, numMipLevels); + info.fID = this->createTexture(dimensions, glFormat, info.fTarget, renderable, &initialState, + numMipLevels); if (!info.fID) { return {}; } // Unbind this texture from the scratch texture unit. - this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, 0); + this->bindTextureToScratchUnit(info.fTarget, 0); auto parameters = sk_make_sp<GrGLTextureParameters>(); // The non-sampler params are still at their default values. @@ -3581,25 +3614,26 @@ bool GrGLGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture, GrGLFormat glFormat = GrGLFormatFromGLEnum(info.fFormat); - this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, info.fID); + this->bindTextureToScratchUnit(info.fTarget, info.fID); - // If we have mips make sure the base level is set to 0 and the max level set to numMipLevesl-1 + // If we have mips make sure the base level is set to 0 and the max level set to numMipLevels-1 // so that the uploads go to the right levels. - if (numMipLevels) { + if (numMipLevels && this->glCaps().mipMapLevelAndLodControlSupport()) { auto params = backendTexture.getGLTextureParams(); GrGLTextureParameters::NonsamplerState nonsamplerState = params->nonsamplerState(); if (params->nonsamplerState().fBaseMipMapLevel != 0) { - GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_BASE_LEVEL, 0)); + GL_CALL(TexParameteri(info.fTarget, GR_GL_TEXTURE_BASE_LEVEL, 0)); nonsamplerState.fBaseMipMapLevel = 0; } if (params->nonsamplerState().fMaxMipMapLevel != (numMipLevels - 1)) { - GL_CALL(TexParameteri(GR_GL_TEXTURE_2D, GR_GL_TEXTURE_MAX_LEVEL, numMipLevels - 1)); + GL_CALL(TexParameteri(info.fTarget, GR_GL_TEXTURE_MAX_LEVEL, numMipLevels - 1)); nonsamplerState.fBaseMipMapLevel = numMipLevels - 1; } params->set(nullptr, nonsamplerState, fResetTimestampForTextureParameters); } SkASSERT(data->type() != BackendTextureData::Type::kCompressed); + bool result = false; if (data->type() == BackendTextureData::Type::kPixmaps) { SkTDArray<GrMipLevel> texels; GrColorType colorType = SkColorTypeToGrColorType(data->pixmap(0).colorType()); @@ -3607,47 +3641,19 @@ bool GrGLGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture, for (int i = 0; i < numMipLevels; ++i) { texels[i] = {data->pixmap(i).addr(), data->pixmap(i).rowBytes()}; } - if (!this->uploadTexData(glFormat, colorType, backendTexture.width(), - backendTexture.height(), GR_GL_TEXTURE_2D, 0, 0, - backendTexture.width(), backendTexture.height(), - colorType, texels.begin(), texels.count())) { - GL_CALL(DeleteTextures(1, &info.fID)); - return false; - } - } else if (data && data->type() == BackendTextureData::Type::kColor) { - // TODO: Unify this with the clear texture code in onCreateTexture(). - GrColorType colorType; - GrGLenum externalFormat, externalType; - this->glCaps().getTexSubImageDefaultFormatTypeAndColorType(glFormat, &externalFormat, - &externalType, &colorType); - if (colorType == GrColorType::kUnknown) { - GL_CALL(DeleteTextures(1, &info.fID)); - return false; - } - - // Make one tight image at the base size and reuse it for smaller levels. - GrImageInfo ii(colorType, kUnpremul_SkAlphaType, nullptr, backendTexture.dimensions()); - auto rb = ii.minRowBytes(); - std::unique_ptr<char[]> pixelStorage(new char[rb * backendTexture.height()]); - if (!GrClearImage(ii, pixelStorage.get(), rb, data->color())) { - GL_CALL(DeleteTextures(1, &info.fID)); - return false; - } - - GL_CALL(PixelStorei(GR_GL_UNPACK_ALIGNMENT, 1)); - SkISize levelDimensions = backendTexture.dimensions(); - for (int i = 0; i < numMipLevels; ++i) { - GL_CALL(TexSubImage2D(GR_GL_TEXTURE_2D, i, 0, 0, levelDimensions.width(), - levelDimensions.height(), externalFormat, externalType, - pixelStorage.get())); - levelDimensions = {std::max(1, levelDimensions.width() / 2), - std::max(1, levelDimensions.height() / 2)}; - } + SkIRect dstRect = SkIRect::MakeSize(backendTexture.dimensions()); + result = this->uploadColorTypeTexData(glFormat, colorType, backendTexture.dimensions(), + info.fTarget, dstRect, colorType, texels.begin(), + texels.count()); + } else if (data->type() == BackendTextureData::Type::kColor) { + uint32_t levelMask = (1 << numMipLevels) - 1; + result = this->uploadColorToTex(glFormat, backendTexture.dimensions(), info.fTarget, + data->color(), levelMask); } // Unbind this texture from the scratch texture unit. - this->bindTextureToScratchUnit(GR_GL_TEXTURE_2D, 0); - return true; + this->bindTextureToScratchUnit(info.fTarget, 0); + return result; } void GrGLGpu::deleteBackendTexture(const GrBackendTexture& tex) { @@ -3743,7 +3749,8 @@ GrBackendRenderTarget GrGLGpu::createTestingOnlyBackendRenderTarget(int w, int h this->bindFramebuffer(GR_GL_FRAMEBUFFER, info.fFBOID); if (useTexture) { GrGLTextureParameters::SamplerOverriddenState initialState; - colorID = this->createTexture2D({w, h}, format, GrRenderable::kYes, &initialState, 1); + colorID = this->createTexture({w, h}, format, GR_GL_TEXTURE_2D, GrRenderable::kYes, + &initialState, 1); if (!colorID) { deleteIDs(); return {}; @@ -3859,6 +3866,9 @@ bool GrGLGpu::onSubmitToGpu(bool syncCpu) { // See if any previously inserted finish procs are good to go. fFinishCallbacks.check(); } + if (!this->glCaps().skipErrorChecks()) { + this->clearErrorsAndCheckForOOM(); + } return true; } @@ -3938,6 +3948,7 @@ std::unique_ptr<GrSemaphore> GrGLGpu::wrapBackendSemaphore( } void GrGLGpu::insertSemaphore(GrSemaphore* semaphore) { + SkASSERT(semaphore); GrGLSemaphore* glSem = static_cast<GrGLSemaphore*>(semaphore); GrGLsync sync; @@ -3947,6 +3958,7 @@ void GrGLGpu::insertSemaphore(GrSemaphore* semaphore) { } void GrGLGpu::waitSemaphore(GrSemaphore* semaphore) { + SkASSERT(semaphore); GrGLSemaphore* glSem = static_cast<GrGLSemaphore*>(semaphore); GL_CALL(WaitSync(glSem->sync(), 0, GR_GL_TIMEOUT_IGNORED)); @@ -3956,6 +3968,23 @@ void GrGLGpu::checkFinishProcs() { fFinishCallbacks.check(); } +void GrGLGpu::clearErrorsAndCheckForOOM() { + while (this->getErrorAndCheckForOOM() != GR_GL_NO_ERROR) {} +} + +GrGLenum GrGLGpu::getErrorAndCheckForOOM() { +#if GR_GL_CHECK_ERROR + if (this->glInterface()->checkAndResetOOMed()) { + this->setOOMed(); + } +#endif + GrGLenum error = this->fGLContext->glInterface()->fFunctions.fGetError(); + if (error == GR_GL_OUT_OF_MEMORY) { + this->setOOMed(); + } + return error; +} + void GrGLGpu::deleteSync(GrGLsync sync) const { if (this->glCaps().fenceType() == GrGLCaps::FenceType::kNVFence) { GrGLuint nvFence = SkToUInt(reinterpret_cast<intptr_t>(sync)); diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLGpu.h b/chromium/third_party/skia/src/gpu/gl/GrGLGpu.h index a716cf8a03c..0a40333c531 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLGpu.h +++ b/chromium/third_party/skia/src/gpu/gl/GrGLGpu.h @@ -104,18 +104,14 @@ public: // The GrGLOpsRenderPass does not buffer up draws before submitting them to the gpu. // Thus this is the implementation of the clear call for the corresponding passthrough function // on GrGLOpsRenderPass. - void clear(const GrFixedClip&, const SkPMColor4f&, GrRenderTarget*, GrSurfaceOrigin); + void clear(const GrScissorState&, const SkPMColor4f&, GrRenderTarget*, GrSurfaceOrigin); // The GrGLOpsRenderPass does not buffer up draws before submitting them to the gpu. // Thus this is the implementation of the clearStencil call for the corresponding passthrough // function on GrGLOpsrenderPass. - void clearStencilClip(const GrFixedClip&, bool insideStencilMask, + void clearStencilClip(const GrScissorState&, bool insideStencilMask, GrRenderTarget*, GrSurfaceOrigin); - // FIXME (michaelludwig): Can this go away and just use clearStencilClip() + marking the - // stencil buffer as not dirty? - void clearStencil(GrRenderTarget*, int clearValue); - void beginCommandBuffer(GrRenderTarget*, const SkIRect& bounds, GrSurfaceOrigin, const GrOpsRenderPass::LoadAndStoreInfo& colorLoadStore, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilLoadStore); @@ -124,7 +120,8 @@ public: const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilLoadStore); GrOpsRenderPass* getOpsRenderPass( - GrRenderTarget*, GrSurfaceOrigin, const SkIRect&, + GrRenderTarget*, GrStencilAttachment*, + GrSurfaceOrigin, const SkIRect&, const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; @@ -172,6 +169,11 @@ public: void checkFinishProcs() override; + // Calls glGetError() until no errors are reported. Also looks for OOMs. + void clearErrorsAndCheckForOOM(); + // Calls glGetError() once and returns the result. Also looks for an OOM. + GrGLenum getErrorAndCheckForOOM(); + std::unique_ptr<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override; void deleteSync(GrGLsync) const; @@ -181,6 +183,11 @@ public: void insertManualFramebufferBarrier() override; + void flushProgram(sk_sp<GrGLProgram>); + + // Version for programs that aren't GrGLProgram. + void flushProgram(GrGLuint); + private: GrGLGpu(std::unique_ptr<GrGLContext>, GrContext*); @@ -253,13 +260,15 @@ private: // returned. On failure, zero is returned. // The texture is populated with |texels|, if it is non-null. // The texture parameters are cached in |initialTexParams|. - GrGLuint createTexture2D(SkISize dimensions, - GrGLFormat, - GrRenderable, - GrGLTextureParameters::SamplerOverriddenState*, - int mipLevelCount); + GrGLuint createTexture(SkISize dimensions, + GrGLFormat, + GrGLenum target, + GrRenderable, + GrGLTextureParameters::SamplerOverriddenState*, + int mipLevelCount); GrGLuint createCompressedTexture2D(SkISize dimensions, + SkImage::CompressionType compression, GrGLFormat, GrMipMapped, GrGLTextureParameters::SamplerOverriddenState*, @@ -299,11 +308,6 @@ private: // binds texture unit in GL void setTextureUnit(int unitIdx); - void flushProgram(sk_sp<GrGLProgram>); - - // Version for programs that aren't GrGLProgram. - void flushProgram(GrGLuint); - void flushBlendAndColorWrite(const GrXferProcessor::BlendInfo& blendInfo, const GrSwizzle&); void addFinishedProc(GrGpuFinishedProc finishedProc, @@ -411,14 +415,45 @@ private: void flushFramebufferSRGB(bool enable); - bool uploadTexData(GrGLFormat textureFormat, GrColorType textureColorType, int texWidth, - int texHeight, GrGLenum target, int left, int top, int width, int height, - GrColorType srcColorType, const GrMipLevel texels[], int mipLevelCount, - GrMipMapsStatus* mipMapsStatus = nullptr); + // Uploads src data of a color type to the currently bound texture on the active texture unit. + // The caller specifies color type that the texture is being used with, which may be different + // than the src color type. This fails if the combination of texture format, texture color type, + // and src data color type are not valid. No conversion is performed on the data before passing + // it to GL. 'dstRect' must be the texture bounds if mipLevelCount is greater than 1. + bool uploadColorTypeTexData(GrGLFormat textureFormat, + GrColorType textureColorType, + SkISize texDims, + GrGLenum target, + SkIRect dstRect, + GrColorType srcColorType, + const GrMipLevel texels[], + int mipLevelCount); + + // Uploads a constant color to a texture using the "default" format and color type. Overwrites + // entire levels. Bit n in 'levelMask' indicates whether level n should be written. This + // function doesn't know if MIP levels have been allocated, thus levelMask should not have bits + // beyond the low bit set if the texture is not MIP mapped. + bool uploadColorToTex(GrGLFormat textureFormat, + SkISize texDims, + GrGLenum target, + SkColor4f color, + uint32_t levelMask); + + // Pushes data to the currently bound texture to the currently active unit. 'dstRect' must be + // the texture bounds if mipLevelCount is greater than 1. + void uploadTexData(SkISize dimensions, + GrGLenum target, + SkIRect dstRect, + GrGLenum externalFormat, + GrGLenum externalType, + size_t bpp, + const GrMipLevel texels[], + int mipLevelCount); // Helper for onCreateCompressedTexture. Compressed textures are read-only so we only use this // to populate a new texture. Returns false if we failed to create and upload the texture. - bool uploadCompressedTexData(GrGLFormat, + bool uploadCompressedTexData(SkImage::CompressionType compressionType, + GrGLFormat, SkISize dimensions, GrMipMapped, GrGLenum target, diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLInterfaceAutogen.cpp b/chromium/third_party/skia/src/gpu/gl/GrGLInterfaceAutogen.cpp index c465fe618c0..c4f61ffe9f7 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLInterfaceAutogen.cpp +++ b/chromium/third_party/skia/src/gpu/gl/GrGLInterfaceAutogen.cpp @@ -19,6 +19,54 @@ GrGLInterface::GrGLInterface() { fStandard = kNone_GrGLStandard; } +#if GR_GL_CHECK_ERROR +static const char* get_error_string(GrGLenum err) { + switch (err) { + case GR_GL_NO_ERROR: + return ""; + case GR_GL_INVALID_ENUM: + return "Invalid Enum"; + case GR_GL_INVALID_VALUE: + return "Invalid Value"; + case GR_GL_INVALID_OPERATION: + return "Invalid Operation"; + case GR_GL_OUT_OF_MEMORY: + return "Out of Memory"; + case GR_GL_CONTEXT_LOST: + return "Context Lost"; + } + return "Unknown"; +} + +GrGLenum GrGLInterface::checkError(const char* location, const char* call) const { + GrGLenum error = fFunctions.fGetError(); + if (error != GR_GL_NO_ERROR && !fSuppressErrorLogging) { + SkDebugf("---- glGetError 0x%x(%s)", error, get_error_string(error)); + if (location) { + SkDebugf(" at\n\t%s", location); + } + if (call) { + SkDebugf("\n\t\t%s", call); + } + SkDebugf("\n"); + if (error == GR_GL_OUT_OF_MEMORY) { + fOOMed = true; + } + } + return error; +} + +bool GrGLInterface::checkAndResetOOMed() const { + if (fOOMed) { + fOOMed = false; + return true; + } + return false; +} + +void GrGLInterface::suppressErrorLogging() { fSuppressErrorLogging = true; } +#endif + #define RETURN_FALSE_INTERFACE \ SkDEBUGF("%s:%d GrGLInterface::validate() failed.\n", __FILE__, __LINE__); \ return false diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLOpsRenderPass.cpp b/chromium/third_party/skia/src/gpu/gl/GrGLOpsRenderPass.cpp index 865d8075fe8..0d2a801ed90 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLOpsRenderPass.cpp +++ b/chromium/third_party/skia/src/gpu/gl/GrGLOpsRenderPass.cpp @@ -8,7 +8,6 @@ #include "src/gpu/gl/GrGLOpsRenderPass.h" #include "src/gpu/GrContextPriv.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrProgramInfo.h" #include "src/gpu/GrRenderTargetPriv.h" @@ -259,12 +258,10 @@ void GrGLOpsRenderPass::onDrawIndexedIndirect(const GrBuffer* drawIndirectBuffer } } -void GrGLOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) { - fGpu->clear(clip, color, fRenderTarget, fOrigin); +void GrGLOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) { + fGpu->clear(scissor, color, fRenderTarget, fOrigin); } -void GrGLOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, - bool insideStencilMask) { - fGpu->clearStencilClip(clip, insideStencilMask, fRenderTarget, fOrigin); +void GrGLOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) { + fGpu->clearStencilClip(scissor, insideStencilMask, fRenderTarget, fOrigin); } - diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLOpsRenderPass.h b/chromium/third_party/skia/src/gpu/gl/GrGLOpsRenderPass.h index b16dda1a953..038e5586f35 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLOpsRenderPass.h +++ b/chromium/third_party/skia/src/gpu/gl/GrGLOpsRenderPass.h @@ -69,8 +69,8 @@ private: void onDrawIndirect(const GrBuffer* drawIndirectBuffer, size_t offset, int drawCount) override; void onDrawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t offset, int drawCount) override; - void onClear(const GrFixedClip& clip, const SkPMColor4f& color) override; - void onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) override; + void onClear(const GrScissorState& scissor, const SkPMColor4f& color) override; + void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override; GrGLGpu* fGpu; SkIRect fContentBounds; @@ -89,4 +89,3 @@ private: }; #endif - diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLProgram.cpp b/chromium/third_party/skia/src/gpu/gl/GrGLProgram.cpp index e8f08847ce6..17938d42a99 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLProgram.cpp +++ b/chromium/third_party/skia/src/gpu/gl/GrGLProgram.cpp @@ -26,6 +26,43 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// +sk_sp<GrGLProgram> GrGLProgram::Make( + GrGLGpu* gpu, + const GrGLSLBuiltinUniformHandles& builtinUniforms, + GrGLuint programID, + const UniformInfoArray& uniforms, + const UniformInfoArray& textureSamplers, + const VaryingInfoArray& pathProcVaryings, + std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor, + std::unique_ptr<GrGLSLXferProcessor> xferProcessor, + std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fps, + int fragmentProcessorCnt, + std::unique_ptr<Attribute[]> attributes, + int vertexAttributeCnt, + int instanceAttributeCnt, + int vertexStride, + int instanceStride) { + sk_sp<GrGLProgram> program(new GrGLProgram(gpu, + builtinUniforms, + programID, + uniforms, + textureSamplers, + pathProcVaryings, + std::move(geometryProcessor), + std::move(xferProcessor), + std::move(fps), + fragmentProcessorCnt, + std::move(attributes), + vertexAttributeCnt, + instanceAttributeCnt, + vertexStride, + instanceStride)); + // Assign texture units to sampler uniforms one time up front. + gpu->flushProgram(program); + program->fProgramDataManager.setSamplerUniforms(textureSamplers, 0); + return program; +} + GrGLProgram::GrGLProgram( GrGLGpu* gpu, const GrGLSLBuiltinUniformHandles& builtinUniforms, @@ -35,7 +72,7 @@ GrGLProgram::GrGLProgram( const VaryingInfoArray& pathProcVaryings, std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor, std::unique_ptr<GrGLSLXferProcessor> xferProcessor, - std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors, + std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fps, int fragmentProcessorCnt, std::unique_ptr<Attribute[]> attributes, int vertexAttributeCnt, @@ -46,7 +83,7 @@ GrGLProgram::GrGLProgram( , fProgramID(programID) , fPrimitiveProcessor(std::move(geometryProcessor)) , fXferProcessor(std::move(xferProcessor)) - , fFragmentProcessors(std::move(fragmentProcessors)) + , fFragmentProcessors(std::move(fps)) , fFragmentProcessorCnt(fragmentProcessorCnt) , fAttributes(std::move(attributes)) , fVertexAttributeCnt(vertexAttributeCnt) @@ -56,9 +93,6 @@ GrGLProgram::GrGLProgram( , fGpu(gpu) , fProgramDataManager(gpu, programID, uniforms, pathProcVaryings) , fNumTextureSamplers(textureSamplers.count()) { - // Assign texture units to sampler uniforms one time up front. - GL_CALL(UseProgram(fProgramID)); - fProgramDataManager.setSamplerUniforms(textureSamplers, 0); } GrGLProgram::~GrGLProgram() { diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLProgram.h b/chromium/third_party/skia/src/gpu/gl/GrGLProgram.h index f784f2b0aa9..ce9e262f7bc 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLProgram.h +++ b/chromium/third_party/skia/src/gpu/gl/GrGLProgram.h @@ -48,21 +48,21 @@ public: * The attribute array consists of vertexAttributeCnt + instanceAttributeCnt elements with * the vertex attributes preceding the instance attributes. */ - GrGLProgram(GrGLGpu*, - const GrGLSLBuiltinUniformHandles&, - GrGLuint programID, - const UniformInfoArray& uniforms, - const UniformInfoArray& textureSamplers, - const VaryingInfoArray&, // used for NVPR only currently - std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor, - std::unique_ptr<GrGLSLXferProcessor> xferProcessor, - std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fragmentProcessors, - int fragmentProcessorCnt, - std::unique_ptr<Attribute[]>, - int vertexAttributeCnt, - int instanceAttributeCnt, - int vertexStride, - int instanceStride); + static sk_sp<GrGLProgram> Make(GrGLGpu*, + const GrGLSLBuiltinUniformHandles&, + GrGLuint programID, + const UniformInfoArray& uniforms, + const UniformInfoArray& textureSamplers, + const VaryingInfoArray&, // used for NVPR only currently + std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor, + std::unique_ptr<GrGLSLXferProcessor> xferProcessor, + std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fps, + int fragmentProcessorCnt, + std::unique_ptr<Attribute[]>, + int vertexAttributeCnt, + int instanceAttributeCnt, + int vertexStride, + int instanceStride); ~GrGLProgram(); @@ -141,6 +141,22 @@ public: } private: + GrGLProgram(GrGLGpu*, + const GrGLSLBuiltinUniformHandles&, + GrGLuint programID, + const UniformInfoArray& uniforms, + const UniformInfoArray& textureSamplers, + const VaryingInfoArray&, // used for NVPR only currently + std::unique_ptr<GrGLSLPrimitiveProcessor> geometryProcessor, + std::unique_ptr<GrGLSLXferProcessor> xferProcessor, + std::unique_ptr<std::unique_ptr<GrGLSLFragmentProcessor>[]> fps, + int fragmentProcessorCnt, + std::unique_ptr<Attribute[]>, + int vertexAttributeCnt, + int instanceAttributeCnt, + int vertexStride, + int instanceStride); + // Helper for setData() that sets the view matrix and loads the render target height uniform void setRenderTargetState(const GrRenderTarget*, GrSurfaceOrigin, const GrPrimitiveProcessor&); diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLUtil.cpp b/chromium/third_party/skia/src/gpu/gl/GrGLUtil.cpp index 28bdbd6588e..fc4781d2814 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLUtil.cpp +++ b/chromium/third_party/skia/src/gpu/gl/GrGLUtil.cpp @@ -12,46 +12,6 @@ #include "src/gpu/gl/GrGLUtil.h" #include <stdio.h> -void GrGLClearErr(const GrGLInterface* gl) { - while (GR_GL_NO_ERROR != gl->fFunctions.fGetError()) {} -} - -namespace { -const char *get_error_string(uint32_t err) { - switch (err) { - case GR_GL_NO_ERROR: - return ""; - case GR_GL_INVALID_ENUM: - return "Invalid Enum"; - case GR_GL_INVALID_VALUE: - return "Invalid Value"; - case GR_GL_INVALID_OPERATION: - return "Invalid Operation"; - case GR_GL_OUT_OF_MEMORY: - return "Out of Memory"; - case GR_GL_CONTEXT_LOST: - return "Context Lost"; - } - return "Unknown"; -} -} - -void GrGLCheckErr(const GrGLInterface* gl, - const char* location, - const char* call) { - uint32_t err = GR_GL_GET_ERROR(gl); - if (GR_GL_NO_ERROR != err) { - SkDebugf("---- glGetError 0x%x(%s)", err, get_error_string(err)); - if (location) { - SkDebugf(" at\n\t%s", location); - } - if (call) { - SkDebugf("\n\t\t%s", call); - } - SkDebugf("\n"); - } -} - /////////////////////////////////////////////////////////////////////////////// #if GR_GL_LOG_CALLS @@ -480,33 +440,38 @@ GrGLRenderer GrGLGetRendererFromStrings(const char* rendererString, static constexpr char kRadeonStr[] = "Radeon "; if (const char* amdString = strstr(rendererString, kRadeonStr)) { amdString += strlen(kRadeonStr); - char amdGeneration, amdTier, amdRevision; // Sometimes there is a (TM) and sometimes not. static constexpr char kTMStr[] = "(TM) "; if (!strncmp(amdString, kTMStr, strlen(kTMStr))) { amdString += strlen(kTMStr); } - n = sscanf(amdString, "R9 M%c%c%c", &amdGeneration, &amdTier, &amdRevision); - if (3 == n) { - if ('3' == amdGeneration) { - return kAMDRadeonR9M3xx_GrGLRenderer; - } else if ('4' == amdGeneration) { - return kAMDRadeonR9M4xx_GrGLRenderer; - } - } char amd0, amd1, amd2; + int amdModel; + n = sscanf(amdString, "R9 M3%c%c", &amd0, &amd1); + if (2 == n && isdigit(amd0) && isdigit(amd1)) { + return kAMDRadeonR9M3xx_GrGLRenderer; + } + + n = sscanf(amdString, "R9 M4%c%c", &amd0, &amd1); + if (2 == n && isdigit(amd0) && isdigit(amd1)) { + return kAMDRadeonR9M4xx_GrGLRenderer; + } + n = sscanf(amdString, "HD 7%c%c%c Series", &amd0, &amd1, &amd2); - if (3 == n) { + if (3 == n && isdigit(amd0) && isdigit(amd1) && isdigit(amd2)) { return kAMDRadeonHD7xxx_GrGLRenderer; } - int amdVegaModel=0; - n = sscanf(amdString, "Pro Vega %i", &amdVegaModel); + n = sscanf(amdString, "Pro 5%c%c%c", &amd0, &amd1, &amd2); + if (3 == n && isdigit(amd0) && isdigit(amd1) && isdigit(amd2)) { + return kAMDRadeonPro5xxx_GrGLRenderer; + } + + n = sscanf(amdString, "Pro Vega %i", &amdModel); if (1 == n) { return kAMDRadeonProVegaxx_GrGLRenderer; } - } if (strstr(rendererString, "llvmpipe")) { @@ -579,6 +544,8 @@ std::tuple<GrGLANGLEBackend, GrGLANGLEVendor, GrGLANGLERenderer> GrGLGetANGLEInf } } else if (strstr(rendererString, "NVIDIA")) { vendor = GrGLANGLEVendor::kNVIDIA; + } else if (strstr(rendererString, "Radeon")) { + vendor = GrGLANGLEVendor::kAMD; } if (strstr(rendererString, "Direct3D11")) { backend = GrGLANGLEBackend::kD3D11; @@ -678,37 +645,3 @@ bool GrGLFormatIsCompressed(GrGLFormat format) { SkUNREACHABLE; } -SkImage::CompressionType GrGLFormatToCompressionType(GrGLFormat format) { - switch (format) { - case GrGLFormat::kCOMPRESSED_ETC1_RGB8: - case GrGLFormat::kCOMPRESSED_RGB8_ETC2: - return SkImage::CompressionType::kETC2_RGB8_UNORM; - case GrGLFormat::kCOMPRESSED_RGB8_BC1: - return SkImage::CompressionType::kBC1_RGB8_UNORM; - case GrGLFormat::kCOMPRESSED_RGBA8_BC1: - return SkImage::CompressionType::kBC1_RGBA8_UNORM; - - case GrGLFormat::kRGBA8: - case GrGLFormat::kR8: - case GrGLFormat::kALPHA8: - case GrGLFormat::kLUMINANCE8: - case GrGLFormat::kBGRA8: - case GrGLFormat::kRGB565: - case GrGLFormat::kRGBA16F: - case GrGLFormat::kR16F: - case GrGLFormat::kLUMINANCE16F: - case GrGLFormat::kRGB8: - case GrGLFormat::kRG8: - case GrGLFormat::kRGB10_A2: - case GrGLFormat::kRGBA4: - case GrGLFormat::kSRGB8_ALPHA8: - case GrGLFormat::kR16: - case GrGLFormat::kRG16: - case GrGLFormat::kRGBA16: - case GrGLFormat::kRG16F: - case GrGLFormat::kUnknown: - return SkImage::CompressionType::kNone; - } - SkUNREACHABLE; -} - diff --git a/chromium/third_party/skia/src/gpu/gl/GrGLUtil.h b/chromium/third_party/skia/src/gpu/gl/GrGLUtil.h index e168275a16d..08435d0a1ab 100644 --- a/chromium/third_party/skia/src/gpu/gl/GrGLUtil.h +++ b/chromium/third_party/skia/src/gpu/gl/GrGLUtil.h @@ -130,6 +130,7 @@ enum GrGLRenderer { kAMDRadeonHD7xxx_GrGLRenderer, // AMD Radeon HD 7000 Series kAMDRadeonR9M3xx_GrGLRenderer, // AMD Radeon R9 M300 Series kAMDRadeonR9M4xx_GrGLRenderer, // AMD Radeon R9 M400 Series + kAMDRadeonPro5xxx_GrGLRenderer, // AMD Radeon Pro 5000 Series kAMDRadeonProVegaxx_GrGLRenderer, // AMD Radeon Pro Vega kOther_GrGLRenderer @@ -157,7 +158,8 @@ enum class GrGLANGLEBackend { enum class GrGLANGLEVendor { kUnknown, kIntel, - kNVIDIA + kNVIDIA, + kAMD }; enum class GrGLANGLERenderer { @@ -255,23 +257,25 @@ void GrGLCheckErr(const GrGLInterface* gl, const char* location, const char* call); -void GrGLClearErr(const GrGLInterface* gl); - //////////////////////////////////////////////////////////////////////////////// /** * Macros for using GrGLInterface to make GL calls */ -// internal macro to conditionally call glGetError based on compile-time and -// run-time flags. +// Conditionally checks glGetError based on compile-time and run-time flags. #if GR_GL_CHECK_ERROR extern bool gCheckErrorGL; - #define GR_GL_CHECK_ERROR_IMPL(IFACE, X) \ - if (gCheckErrorGL) \ - GrGLCheckErr(IFACE, GR_FILE_AND_LINE_STR, #X) +#define GR_GL_CHECK_ERROR_IMPL(IFACE, X) \ + do { \ + if (gCheckErrorGL) { \ + IFACE->checkError(GR_FILE_AND_LINE_STR, #X); \ + } \ + } while (false) #else - #define GR_GL_CHECK_ERROR_IMPL(IFACE, X) +#define GR_GL_CHECK_ERROR_IMPL(IFACE, X) \ + do { \ + } while (false) #endif // internal macro to conditionally log the gl call using SkDebugf based on @@ -314,9 +318,6 @@ void GrGLClearErr(const GrGLInterface* gl); GR_GL_LOG_CALLS_IMPL(X); \ } while (false) -// call glGetError without doing a redundant error check or logging. -#define GR_GL_GET_ERROR(IFACE) (IFACE)->fFunctions.fGetError() - static constexpr GrGLFormat GrGLFormatFromGLEnum(GrGLenum glFormat) { switch (glFormat) { case GR_GL_RGBA8: return GrGLFormat::kRGBA8; @@ -415,9 +416,4 @@ GrGLenum GrToGLStencilFunc(GrStencilTest test); */ bool GrGLFormatIsCompressed(GrGLFormat); -/** - * This will return CompressionType::kNone if the format is uncompressed. - */ -SkImage::CompressionType GrGLFormatToCompressionType(GrGLFormat); - #endif diff --git a/chromium/third_party/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/chromium/third_party/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp index 6c2ba755bcd..230298f00c7 100644 --- a/chromium/third_party/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp +++ b/chromium/third_party/skia/src/gpu/gl/builders/GrGLProgramBuilder.cpp @@ -10,9 +10,9 @@ #include "include/gpu/GrContext.h" #include "src/core/SkATrace.h" #include "src/core/SkAutoMalloc.h" -#include "src/core/SkReader32.h" +#include "src/core/SkReadBuffer.h" #include "src/core/SkTraceEvent.h" -#include "src/core/SkWriter32.h" +#include "src/core/SkWriteBuffer.h" #include "src/gpu/GrAutoLocaleSetter.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrCoordTransform.h" @@ -166,16 +166,19 @@ void GrGLProgramBuilder::storeShaderInCache(const SkSL::Program::Inputs& inputs, GrGLsizei length = 0; GL_CALL(GetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &length)); if (length > 0) { - SkWriter32 writer; - writer.write32(kGLPB_Tag); + SkBinaryWriteBuffer writer; + writer.writeInt(GrPersistentCacheUtils::kCurrentVersion); + writer.writeUInt(kGLPB_Tag); - writer.writePad(&inputs, sizeof(inputs)); - writer.write32(length); + writer.writePad32(&inputs, sizeof(inputs)); - void* binary = writer.reservePad(length); + SkAutoSMalloc<2048> binary(length); GrGLenum binaryFormat; - GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary)); - writer.write32(binaryFormat); + GL_CALL(GetProgramBinary(programID, length, &length, &binaryFormat, binary.get())); + + writer.writeUInt(binaryFormat); + writer.writeInt(length); + writer.writePad32(binary.get(), length); auto data = writer.snapshotAsData(); this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data); @@ -254,7 +257,7 @@ sk_sp<GrGLProgram> GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* pr usedProgramBinaries = true; } else if (cached) { ATRACE_ANDROID_FRAMEWORK_ALWAYS("cache_hit"); - SkReader32 reader(fCached->data(), fCached->size()); + SkReadBuffer reader(fCached->data(), fCached->size()); SkFourByteTag shaderType = GrPersistentCacheUtils::GetType(&reader); switch (shaderType) { @@ -265,15 +268,18 @@ sk_sp<GrGLProgram> GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* pr cached = false; break; } - reader.read(&inputs, sizeof(inputs)); - GrGLsizei length = reader.readInt(); + reader.readPad32(&inputs, sizeof(inputs)); + GrGLenum binaryFormat = reader.readUInt(); + GrGLsizei length = reader.readInt(); const void* binary = reader.skip(length); - GrGLenum binaryFormat = reader.readU32(); - GrGLClearErr(this->gpu()->glInterface()); + if (!reader.isValid()) { + break; + } + this->gpu()->clearErrorsAndCheckForOOM(); GR_GL_CALL_NOERRCHECK(this->gpu()->glInterface(), ProgramBinary(programID, binaryFormat, const_cast<void*>(binary), length)); - if (GR_GL_GET_ERROR(this->gpu()->glInterface()) == GR_GL_NO_ERROR) { + if (this->gpu()->getErrorAndCheckForOOM() == GR_GL_NO_ERROR) { if (checkLinked) { cached = this->checkLinkStatus(programID, errorHandler, nullptr, nullptr); } @@ -295,11 +301,20 @@ sk_sp<GrGLProgram> GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* pr case kSKSL_Tag: // SkSL cache hit, this should only happen in tools overriding the generated SkSL - GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, &inputs, 1); - for (int i = 0; i < kGrShaderTypeCount; ++i) { - sksl[i] = &cached_sksl[i]; + if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, &inputs, 1)) { + for (int i = 0; i < kGrShaderTypeCount; ++i) { + sksl[i] = &cached_sksl[i]; + } } break; + + default: + // We got something invalid, so pretend it wasn't there + reader.validate(false); + break; + } + if (!reader.isValid()) { + cached = false; } } if (!usedProgramBinaries) { @@ -376,7 +391,8 @@ sk_sp<GrGLProgram> GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* pr } SkString tessControlShader = primProc.getTessControlShaderGLSL( - versionAndExtensionDecls.c_str(), *this->shaderCaps()); + fGeometryProcessor.get(), versionAndExtensionDecls.c_str(), fUniformHandler, + *this->shaderCaps()); if (!this->compileAndAttachShaders(tessControlShader.c_str(), programID, GR_GL_TESS_CONTROL_SHADER, &shadersToDelete, errorHandler)) { @@ -385,7 +401,8 @@ sk_sp<GrGLProgram> GrGLProgramBuilder::finalize(const GrGLPrecompiledProgram* pr } SkString tessEvaluationShader = primProc.getTessEvaluationShaderGLSL( - versionAndExtensionDecls.c_str(), *this->shaderCaps()); + fGeometryProcessor.get(), versionAndExtensionDecls.c_str(), fUniformHandler, + *this->shaderCaps()); if (!this->compileAndAttachShaders(tessEvaluationShader.c_str(), programID, GR_GL_TESS_EVALUATION_SHADER, &shadersToDelete, errorHandler)) { @@ -534,27 +551,27 @@ void GrGLProgramBuilder::resolveProgramResourceLocations(GrGLuint programID, boo } sk_sp<GrGLProgram> GrGLProgramBuilder::createProgram(GrGLuint programID) { - return sk_sp<GrGLProgram>(new GrGLProgram(fGpu, - fUniformHandles, - programID, - fUniformHandler.fUniforms, - fUniformHandler.fSamplers, - fVaryingHandler.fPathProcVaryingInfos, - std::move(fGeometryProcessor), - std::move(fXferProcessor), - std::move(fFragmentProcessors), - fFragmentProcessorCnt, - std::move(fAttributes), - fVertexAttributeCnt, - fInstanceAttributeCnt, - fVertexStride, - fInstanceStride)); + return GrGLProgram::Make(fGpu, + fUniformHandles, + programID, + fUniformHandler.fUniforms, + fUniformHandler.fSamplers, + fVaryingHandler.fPathProcVaryingInfos, + std::move(fGeometryProcessor), + std::move(fXferProcessor), + std::move(fFragmentProcessors), + fFragmentProcessorCnt, + std::move(fAttributes), + fVertexAttributeCnt, + fInstanceAttributeCnt, + fVertexStride, + fInstanceStride); } bool GrGLProgramBuilder::PrecompileProgram(GrGLPrecompiledProgram* precompiledProgram, GrGLGpu* gpu, const SkData& cachedData) { - SkReader32 reader(cachedData.data(), cachedData.size()); + SkReadBuffer reader(cachedData.data(), cachedData.size()); SkFourByteTag shaderType = GrPersistentCacheUtils::GetType(&reader); if (shaderType != kSKSL_Tag) { // TODO: Support GLSL, and maybe even program binaries, too? @@ -563,13 +580,6 @@ bool GrGLProgramBuilder::PrecompileProgram(GrGLPrecompiledProgram* precompiledPr const GrGLInterface* gl = gpu->glInterface(); auto errorHandler = gpu->getContext()->priv().getShaderErrorHandler(); - GrGLuint programID; - GR_GL_CALL_RET(gl, programID, CreateProgram()); - if (0 == programID) { - return false; - } - - SkTDArray<GrGLuint> shadersToDelete; SkSL::Program::Settings settings; const GrGLCaps& caps = gpu->glCaps(); @@ -580,7 +590,17 @@ bool GrGLProgramBuilder::PrecompileProgram(GrGLPrecompiledProgram* precompiledPr SkSL::String shaders[kGrShaderTypeCount]; SkSL::Program::Inputs inputs; - GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &meta); + if (!GrPersistentCacheUtils::UnpackCachedShaders(&reader, shaders, &inputs, 1, &meta)) { + return false; + } + + GrGLuint programID; + GR_GL_CALL_RET(gl, programID, CreateProgram()); + if (0 == programID) { + return false; + } + + SkTDArray<GrGLuint> shadersToDelete; auto compileShader = [&](SkSL::Program::Kind kind, const SkSL::String& sksl, GrGLenum type) { SkSL::String glsl; diff --git a/chromium/third_party/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp b/chromium/third_party/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp index ad629d0bf59..68ba303dc33 100644 --- a/chromium/third_party/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp +++ b/chromium/third_party/skia/src/gpu/glsl/GrGLSLFragmentShaderBuilder.cpp @@ -88,9 +88,16 @@ SkString GrGLSLFragmentShaderBuilder::ensureCoords2D(const GrShaderVar& coords, } switch (matrix.fKind) { case SkSL::SampleMatrix::Kind::kMixed: - case SkSL::SampleMatrix::Kind::kVariable: - result = SkStringPrintf("(_matrix * float3(%s, 1)).xy", result.c_str()); - break; + case SkSL::SampleMatrix::Kind::kVariable: { + SkString sampleCoords2D; + sampleCoords2D.printf("%s_sample", coords.c_str()); + this->codeAppendf("\tfloat3 %s_3d = _matrix * %s.xy1;\n", + sampleCoords2D.c_str(), result.c_str()); + this->codeAppendf("\tfloat2 %s = %s_3d.xy / %s_3d.z;\n", + sampleCoords2D.c_str(), sampleCoords2D.c_str(), + sampleCoords2D.c_str()); + result = sampleCoords2D; + break; } default: break; } @@ -181,11 +188,15 @@ SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor const GrShaderVar& transform = args.fTransformedCoords[0].fTransform; switch (transform.getType()) { case kFloat4_GrSLType: + // This is a scale+translate, so there's no perspective division needed this->codeAppendf("_coords = _coords * %s.xz + %s.yw;\n", transform.c_str(), transform.c_str()); break; case kFloat3x3_GrSLType: - this->codeAppendf("_coords = (%s * float3(_coords, 1)).xy;\n", transform.c_str()); + this->codeAppend("{\n"); + this->codeAppendf("float3 _coords3 = (%s * _coords.xy1);\n", transform.c_str()); + this->codeAppend("_coords = _coords3.xy / _coords3.z;\n"); + this->codeAppend("}\n"); break; default: SkASSERT(transform.getType() == kVoid_GrSLType); @@ -195,8 +206,12 @@ SkString GrGLSLFPFragmentBuilder::writeProcessorFunction(GrGLSLFragmentProcessor SkASSERT(!hasVariableMatrix); this->codeAppend("{\n"); args.fUniformHandler->writeUniformMappings(args.fFp.sampleMatrix().fOwner, this); - this->codeAppendf("_coords = (%s * float3(_coords, 1)).xy;\n", + // FIXME This is not a variable matrix, we could key on the matrix type and skip + // perspective division; it may also be worth detecting if it was scale+translate and + // evaluating this similarly to the kFloat4 explicit coord case. + this->codeAppendf("float3 _coords3 = (%s * _coords.xy1);\n", args.fFp.sampleMatrix().fExpression.c_str()); + this->codeAppend("_coords = _coords3.xy / _coords3.z;\n"); this->codeAppend("}\n"); } } diff --git a/chromium/third_party/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp b/chromium/third_party/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp index 3ef36d4f48c..4d2ee7e532c 100644 --- a/chromium/third_party/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp +++ b/chromium/third_party/skia/src/gpu/glsl/GrGLSLGeometryProcessor.cpp @@ -14,10 +14,19 @@ #include "src/gpu/glsl/GrGLSLVarying.h" #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h" +#include <unordered_map> + void GrGLSLGeometryProcessor::emitCode(EmitArgs& args) { GrGPArgs gpArgs; this->onEmitCode(args, &gpArgs); + // FIXME This must always be called at the moment, even when fLocalCoordVar is uninitialized + // and void because collectTransforms registers the uniforms for legacy coord transforms, which + // still need to be added even if the FPs are sampled explicitly. When they are gone, we only + // need to call this if the local coord isn't void (plus verify that FPs really don't need it). + this->collectTransforms(args.fVertBuilder, args.fVaryingHandler, args.fUniformHandler, + gpArgs.fLocalCoordVar, args.fFPCoordTransformHandler); + if (args.fGP.willUseTessellationShaders()) { // Tessellation shaders are temporarily responsible for integrating their own code strings // while we work out full support. @@ -42,11 +51,14 @@ void GrGLSLGeometryProcessor::emitCode(EmitArgs& args) { vBuilder->codeAppendf("sk_Position = float4(%s", gpArgs.fPositionVar.c_str()); switch (gpArgs.fPositionVar.getType()) { case kFloat_GrSLType: - vBuilder->codeAppend(", 0"); // fallthru. + vBuilder->codeAppend(", 0"); + [[fallthrough]]; case kFloat2_GrSLType: - vBuilder->codeAppend(", 0"); // fallthru. + vBuilder->codeAppend(", 0"); + [[fallthrough]]; case kFloat3_GrSLType: - vBuilder->codeAppend(", 1"); // fallthru. + vBuilder->codeAppend(", 1"); + [[fallthrough]]; case kFloat4_GrSLType: vBuilder->codeAppend(");"); break; @@ -57,12 +69,11 @@ void GrGLSLGeometryProcessor::emitCode(EmitArgs& args) { } } -void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb, - GrGLSLVaryingHandler* varyingHandler, - GrGLSLUniformHandler* uniformHandler, - const GrShaderVar& localCoordsVar, - const SkMatrix& localMatrix, - FPCoordTransformHandler* handler) { +void GrGLSLGeometryProcessor::collectTransforms(GrGLSLVertexBuilder* vb, + GrGLSLVaryingHandler* varyingHandler, + GrGLSLUniformHandler* uniformHandler, + const GrShaderVar& localCoordsVar, + FPCoordTransformHandler* handler) { // We only require localCoordsVar to be valid if there is a coord transform that needs // it. CTs on FPs called with explicit coords do not require a local coord. auto getLocalCoords = [&localCoordsVar, @@ -115,8 +126,7 @@ void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb, if (!fp.isSampledWithExplicitCoords()) { auto [localCoordsStr, localCoordLength] = getLocalCoords(); GrGLSLVarying v(kFloat2_GrSLType); - if (localMatrix.hasPerspective() || coordTransform.matrix().hasPerspective() || - localCoordLength == 3) { + if (coordTransform.matrix().hasPerspective() || localCoordLength == 3) { v = GrGLSLVarying(kFloat3_GrSLType); } SkString strVaryingName; @@ -142,41 +152,49 @@ void GrGLSLGeometryProcessor::emitTransforms(GrGLSLVertexBuilder* vb, void GrGLSLGeometryProcessor::emitTransformCode(GrGLSLVertexBuilder* vb, GrGLSLUniformHandler* uniformHandler) { + std::unordered_map<const GrFragmentProcessor*, const char*> localCoordsMap; for (const auto& tr : fTransformInfos) { switch (tr.fFP->sampleMatrix().fKind) { - case SkSL::SampleMatrix::Kind::kConstantOrUniform: + case SkSL::SampleMatrix::Kind::kConstantOrUniform: { + SkString localCoords; + localCoordsMap.insert({ tr.fFP, tr.fName }); + if (tr.fFP->sampleMatrix().fBase) { + SkASSERT(localCoordsMap[tr.fFP->sampleMatrix().fBase]); + localCoords = SkStringPrintf("float3(%s, 1)", + localCoordsMap[tr.fFP->sampleMatrix().fBase]); + } else { + localCoords = tr.fLocalCoords.c_str(); + } vb->codeAppend("{\n"); - uniformHandler->writeUniformMappings(tr.fFP->sampleMatrix().fOwner, vb); + if (tr.fFP->sampleMatrix().fOwner) { + uniformHandler->writeUniformMappings(tr.fFP->sampleMatrix().fOwner, vb); + } if (tr.fType == kFloat2_GrSLType) { vb->codeAppendf("%s = (%s * %s * %s).xy", tr.fName, tr.fFP->sampleMatrix().fExpression.c_str(), tr.fMatrix.c_str(), - tr.fLocalCoords.c_str()); + localCoords.c_str()); } else { SkASSERT(tr.fType == kFloat3_GrSLType); vb->codeAppendf("%s = %s * %s * %s", tr.fName, tr.fFP->sampleMatrix().fExpression.c_str(), tr.fMatrix.c_str(), - tr.fLocalCoords.c_str()); + localCoords.c_str()); } vb->codeAppend(";\n"); vb->codeAppend("}\n"); + break; + } default: break; } } } -void GrGLSLGeometryProcessor::setTransformDataHelper(const SkMatrix& localMatrix, - const GrGLSLProgramDataManager& pdman, +void GrGLSLGeometryProcessor::setTransformDataHelper(const GrGLSLProgramDataManager& pdman, const CoordTransformRange& transformRange) { int i = 0; for (auto [transform, fp] : transformRange) { if (fInstalledTransforms[i].fHandle.isValid()) { - SkMatrix m; - if (fp.isSampledWithExplicitCoords()) { - m = GetTransformMatrix(transform, SkMatrix::I()); - } else { - m = GetTransformMatrix(transform, localMatrix); - } + SkMatrix m = GetTransformMatrix(transform, SkMatrix::I()); if (!SkMatrixPriv::CheapEqual(fInstalledTransforms[i].fCurrentValue, m)) { if (fInstalledTransforms[i].fType == kFloat4_GrSLType) { float values[4] = {m.getScaleX(), m.getTranslateX(), @@ -196,11 +214,94 @@ void GrGLSLGeometryProcessor::setTransformDataHelper(const SkMatrix& localMatrix SkASSERT(i == fInstalledTransforms.count()); } +void GrGLSLGeometryProcessor::setTransform(const GrGLSLProgramDataManager& pdman, + const UniformHandle& uniform, + const SkMatrix& matrix, + SkMatrix* state) const { + if (!uniform.isValid() || (state && SkMatrixPriv::CheapEqual(*state, matrix))) { + // No update needed + return; + } + if (state) { + *state = matrix; + } + if (matrix.isScaleTranslate()) { + // ComputeMatrixKey and writeX() assume the uniform is a float4 (can't assert since nothing + // is exposed on a handle, but should be caught lower down). + float values[4] = {matrix.getScaleX(), matrix.getTranslateX(), + matrix.getScaleY(), matrix.getTranslateY()}; + pdman.set4fv(uniform, 1, values); + } else { + pdman.setSkMatrix(uniform, matrix); + } +} + +static void write_vertex_position(GrGLSLVertexBuilder* vertBuilder, + GrGLSLUniformHandler* uniformHandler, + const GrShaderVar& inPos, + const SkMatrix& matrix, + const char* matrixName, + GrShaderVar* outPos, + GrGLSLGeometryProcessor::UniformHandle* matrixUniform) { + SkASSERT(inPos.getType() == kFloat3_GrSLType || inPos.getType() == kFloat2_GrSLType); + SkString outName = vertBuilder->newTmpVarName(inPos.getName().c_str()); + + if (matrix.isIdentity()) { + // Direct assignment, we won't use a uniform for the matrix. + outPos->set(inPos.getType(), outName.c_str()); + vertBuilder->codeAppendf("float%d %s = %s;", GrSLTypeVecLength(inPos.getType()), + outName.c_str(), inPos.getName().c_str()); + } else { + SkASSERT(matrixUniform); + + bool useCompactTransform = matrix.isScaleTranslate(); + const char* mangledMatrixName; + *matrixUniform = uniformHandler->addUniform(nullptr, + kVertex_GrShaderFlag, + useCompactTransform ? kFloat4_GrSLType + : kFloat3x3_GrSLType, + matrixName, + &mangledMatrixName); + + if (inPos.getType() == kFloat3_GrSLType) { + // A float3 stays a float3 whether or not the matrix adds perspective + if (useCompactTransform) { + vertBuilder->codeAppendf("float3 %s = %s.xz1 * %s + %s.yw0;\n", + outName.c_str(), mangledMatrixName, + inPos.getName().c_str(), mangledMatrixName); + } else { + vertBuilder->codeAppendf("float3 %s = %s * %s;\n", outName.c_str(), + mangledMatrixName, inPos.getName().c_str()); + } + outPos->set(kFloat3_GrSLType, outName.c_str()); + } else if (matrix.hasPerspective()) { + // A float2 is promoted to a float3 if we add perspective via the matrix + SkASSERT(!useCompactTransform); + vertBuilder->codeAppendf("float3 %s = (%s * %s.xy1);", + outName.c_str(), mangledMatrixName, inPos.getName().c_str()); + outPos->set(kFloat3_GrSLType, outName.c_str()); + } else { + if (useCompactTransform) { + vertBuilder->codeAppendf("float2 %s = %s.xz * %s + %s.yw;\n", + outName.c_str(), mangledMatrixName, + inPos.getName().c_str(), mangledMatrixName); + } else { + vertBuilder->codeAppendf("float2 %s = (%s * %s.xy1).xy;\n", + outName.c_str(), mangledMatrixName, + inPos.getName().c_str()); + } + outPos->set(kFloat2_GrSLType, outName.c_str()); + } + } +} + void GrGLSLGeometryProcessor::writeOutputPosition(GrGLSLVertexBuilder* vertBuilder, GrGPArgs* gpArgs, const char* posName) { - gpArgs->fPositionVar.set(kFloat2_GrSLType, "pos2"); - vertBuilder->codeAppendf("float2 %s = %s;", gpArgs->fPositionVar.c_str(), posName); + // writeOutputPosition assumes the incoming pos name points to a float2 variable + GrShaderVar inPos(posName, kFloat2_GrSLType); + write_vertex_position(vertBuilder, nullptr, inPos, SkMatrix::I(), "viewMatrix", + &gpArgs->fPositionVar, nullptr); } void GrGLSLGeometryProcessor::writeOutputPosition(GrGLSLVertexBuilder* vertBuilder, @@ -209,24 +310,17 @@ void GrGLSLGeometryProcessor::writeOutputPosition(GrGLSLVertexBuilder* vertBuild const char* posName, const SkMatrix& mat, UniformHandle* viewMatrixUniform) { - if (mat.isIdentity()) { - gpArgs->fPositionVar.set(kFloat2_GrSLType, "pos2"); - vertBuilder->codeAppendf("float2 %s = %s;", gpArgs->fPositionVar.c_str(), posName); - } else { - const char* viewMatrixName; - *viewMatrixUniform = uniformHandler->addUniform(nullptr, - kVertex_GrShaderFlag, - kFloat3x3_GrSLType, - "uViewM", - &viewMatrixName); - if (!mat.hasPerspective()) { - gpArgs->fPositionVar.set(kFloat2_GrSLType, "pos2"); - vertBuilder->codeAppendf("float2 %s = (%s * float3(%s, 1)).xy;", - gpArgs->fPositionVar.c_str(), viewMatrixName, posName); - } else { - gpArgs->fPositionVar.set(kFloat3_GrSLType, "pos3"); - vertBuilder->codeAppendf("float3 %s = %s * float3(%s, 1);", - gpArgs->fPositionVar.c_str(), viewMatrixName, posName); - } - } + GrShaderVar inPos(posName, kFloat2_GrSLType); + write_vertex_position(vertBuilder, uniformHandler, inPos, mat, "viewMatrix", + &gpArgs->fPositionVar, viewMatrixUniform); +} + +void GrGLSLGeometryProcessor::writeLocalCoord(GrGLSLVertexBuilder* vertBuilder, + GrGLSLUniformHandler* uniformHandler, + GrGPArgs* gpArgs, + GrShaderVar localVar, + const SkMatrix& localMatrix, + UniformHandle* localMatrixUniform) { + write_vertex_position(vertBuilder, uniformHandler, localVar, localMatrix, "localMatrix", + &gpArgs->fLocalCoordVar, localMatrixUniform); } diff --git a/chromium/third_party/skia/src/gpu/glsl/GrGLSLGeometryProcessor.h b/chromium/third_party/skia/src/gpu/glsl/GrGLSLGeometryProcessor.h index f23bd0e800d..10e21376750 100644 --- a/chromium/third_party/skia/src/gpu/glsl/GrGLSLGeometryProcessor.h +++ b/chromium/third_party/skia/src/gpu/glsl/GrGLSLGeometryProcessor.h @@ -22,41 +22,33 @@ public: /* Any general emit code goes in the base class emitCode. Subclasses override onEmitCode */ void emitCode(EmitArgs&) final; + // Generate the final code for assigning transformed coordinates to the varyings recorded in + // the call to collectTransforms(). This must happen after FP code emission so that it has + // access to any uniforms the FPs registered for const/uniform sample matrix invocations. + void emitTransformCode(GrGLSLVertexBuilder* vb, + GrGLSLUniformHandler* uniformHandler) override; + protected: // A helper which subclasses can use to upload coord transform matrices in setData(). - void setTransformDataHelper(const SkMatrix& localMatrix, - const GrGLSLProgramDataManager& pdman, + void setTransformDataHelper(const GrGLSLProgramDataManager& pdman, const CoordTransformRange&); - // Emit transformed local coords from the vertex shader as a uniform matrix and varying per - // coord-transform. localCoordsVar must be a 2- or 3-component vector. If it is 3 then it is - // assumed to be a 2D homogeneous coordinate. - void emitTransforms(GrGLSLVertexBuilder*, - GrGLSLVaryingHandler*, - GrGLSLUniformHandler*, - const GrShaderVar& localCoordsVar, - const SkMatrix& localMatrix, - FPCoordTransformHandler*); - - // Version of above that assumes identity for the local matrix. - void emitTransforms(GrGLSLVertexBuilder* vb, - GrGLSLVaryingHandler* varyingHandler, - GrGLSLUniformHandler* uniformHandler, - const GrShaderVar& localCoordsVar, - FPCoordTransformHandler* handler) { - this->emitTransforms(vb, varyingHandler, uniformHandler, localCoordsVar, SkMatrix::I(), - handler); - } - - // TODO: doc - void emitTransformCode(GrGLSLVertexBuilder* vb, - GrGLSLUniformHandler* uniformHandler) override; + // A helper for setting the matrix on a uniform handle initialized through + // writeOutputPosition or writeLocalCoord. Automatically handles elided uniforms, + // scale+translate matrices, and state tracking (if provided state pointer is non-null). + void setTransform(const GrGLSLProgramDataManager& pdman, const UniformHandle& uniform, + const SkMatrix& matrix, SkMatrix* state=nullptr) const; struct GrGPArgs { // Used to specify the output variable used by the GP to store its device position. It can // either be a float2 or a float3 (in order to handle perspective). The subclass sets this // in its onEmitCode(). GrShaderVar fPositionVar; + // Used to specify the variable storing the draw's local coordinates. It can be either a + // float2, float3, or void. It can only be void when no FP needs local coordinates. This + // variable can be an attribute or local variable, but should not itself be a varying. + // GrGLSLGeometryProcessor automatically determines if this must be passed to a FS. + GrShaderVar fLocalCoordVar; }; // Helpers for adding code to write the transformed vertex position. The first simple version @@ -73,19 +65,54 @@ protected: const SkMatrix& mat, UniformHandle* viewMatrixUniform); - static uint32_t ComputePosKey(const SkMatrix& mat) { + // Helper to transform an existing variable by a given local matrix (e.g. the inverse view + // matrix). It will declare the transformed local coord variable and will set + // GrGPArgs::fLocalCoordVar. + void writeLocalCoord(GrGLSLVertexBuilder*, GrGLSLUniformHandler*, GrGPArgs*, + GrShaderVar localVar, const SkMatrix& localMatrix, + UniformHandle* localMatrixUniform); + + // GPs that use writeOutputPosition and/or writeLocalCoord must incorporate the matrix type + // into their key, and should use this function or one of the other related helpers. + static uint32_t ComputeMatrixKey(const SkMatrix& mat) { if (mat.isIdentity()) { - return 0x0; + return 0b00; + } else if (mat.isScaleTranslate()) { + return 0b01; } else if (!mat.hasPerspective()) { - return 0x01; + return 0b10; } else { - return 0x02; + return 0b11; } } + static uint32_t ComputeMatrixKeys(const SkMatrix& viewMatrix, const SkMatrix& localMatrix) { + return (ComputeMatrixKey(viewMatrix) << kMatrixKeyBits) | ComputeMatrixKey(localMatrix); + } + static uint32_t AddMatrixKeys(uint32_t flags, const SkMatrix& viewMatrix, + const SkMatrix& localMatrix) { + // Shifting to make room for the matrix keys shouldn't lose bits + SkASSERT(((flags << (2 * kMatrixKeyBits)) >> (2 * kMatrixKeyBits)) == flags); + return (flags << (2 * kMatrixKeyBits)) | ComputeMatrixKeys(viewMatrix, localMatrix); + } + static constexpr int kMatrixKeyBits = 2; private: virtual void onEmitCode(EmitArgs&, GrGPArgs*) = 0; + // Iterates over the FPs in 'handler' to register additional varyings and uniforms to support + // VS-promoted local coord evaluation for the FPs. Subclasses must call this with + // 'localCoordsVar' set to an SkSL variable expression of type 'float2' or 'float3' representing + // the original local coordinates of the draw. + // + // This must happen before FP code emission so that the FPs can find the appropriate varying + // handles they use in place of explicit coord sampling; it is automatically called after + // onEmitCode() returns using the value stored in GpArgs::fLocalCoordVar. + void collectTransforms(GrGLSLVertexBuilder* vb, + GrGLSLVaryingHandler* varyingHandler, + GrGLSLUniformHandler* uniformHandler, + const GrShaderVar& localCoordsVar, + FPCoordTransformHandler* handler); + struct TransformUniform { UniformHandle fHandle; GrSLType fType = kVoid_GrSLType; diff --git a/chromium/third_party/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp b/chromium/third_party/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp index 95f97feb695..e5a9c1448ff 100644 --- a/chromium/third_party/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp +++ b/chromium/third_party/skia/src/gpu/glsl/GrGLSLShaderBuilder.cpp @@ -20,7 +20,8 @@ GrGLSLShaderBuilder::GrGLSLShaderBuilder(GrGLSLProgramBuilder* program) , fOutputs(GrGLSLProgramBuilder::kVarsPerBlock) , fFeaturesAddedMask(0) , fCodeIndex(kCode) - , fFinalized(false) { + , fFinalized(false) + , fTmpVariableCounter(0) { // We push back some dummy pointers which will later become our header for (int i = 0; i <= kCode; i++) { fShaderStrings.push_back(); @@ -198,9 +199,7 @@ void GrGLSLShaderBuilder::appendColorGamutXform(SkString* out, GrShaderVar("color", useFloat ? kFloat4_GrSLType : kHalf4_GrSLType)}; SkString body; if (colorXformHelper->applyUnpremul()) { - body.appendf("%s nonZeroAlpha = max(color.a, 0.0001);", useFloat ? "float" : "half"); - body.appendf("color = %s(color.rgb / nonZeroAlpha, nonZeroAlpha);", - useFloat ? "float4" : "half4"); + body.appendf("color = unpremul%s(color);", useFloat ? "_float" : ""); } if (colorXformHelper->applySrcTF()) { body.appendf("color.r = %s(half(color.r));", srcTFFuncName.c_str()); diff --git a/chromium/third_party/skia/src/gpu/glsl/GrGLSLShaderBuilder.h b/chromium/third_party/skia/src/gpu/glsl/GrGLSLShaderBuilder.h index b69abe89442..b766280d23a 100644 --- a/chromium/third_party/skia/src/gpu/glsl/GrGLSLShaderBuilder.h +++ b/chromium/third_party/skia/src/gpu/glsl/GrGLSLShaderBuilder.h @@ -84,6 +84,13 @@ public: void declareGlobal(const GrShaderVar&); + // Generates a unique variable name for holding the result of a temporary expression when it's + // not reasonable to just add a new block for scoping. Does not declare anything. + SkString newTmpVarName(const char* suffix) { + int tmpIdx = fTmpVariableCounter++; + return SkStringPrintf("_tmp_%d_%s", tmpIdx, suffix); + } + /** * Called by GrGLSLProcessors to add code to one of the shaders. */ @@ -238,6 +245,9 @@ protected: int fCodeIndex; bool fFinalized; + // Counter for generating unique scratch variable names in a shader. + int fTmpVariableCounter; + friend class GrCCCoverageProcessor; // to access code(). friend class GrGLSLProgramBuilder; friend class GrGLProgramBuilder; diff --git a/chromium/third_party/skia/src/gpu/gradients/GrGradientShader.cpp b/chromium/third_party/skia/src/gpu/gradients/GrGradientShader.cpp index 59624f2bb7f..8981955a38e 100644 --- a/chromium/third_party/skia/src/gpu/gradients/GrGradientShader.cpp +++ b/chromium/third_party/skia/src/gpu/gradients/GrGradientShader.cpp @@ -27,6 +27,7 @@ #include "src/gpu/GrColorInfo.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/SkGr.h" +#include "src/gpu/effects/GrTextureEffect.h" // Intervals smaller than this (that aren't hard stops) on low-precision-only devices force us to // use the textured gradient @@ -64,8 +65,11 @@ static std::unique_ptr<GrFragmentProcessor> make_textured_colorizer(const SkPMCo SkDebugf("Gradient won't draw. Could not create texture."); return nullptr; } - - return GrTextureGradientColorizer::Make(std::move(view)); + // TODO: When we start sampling colorizers with explicit coords rather than using sk_InColor + // the GrTextureEffect can simply be the colorizer. + auto m = SkMatrix::Scale(view.width(), 1.f); + auto te = GrTextureEffect::Make(std::move(view), alphaType, m, GrSamplerState::Filter::kBilerp); + return GrTextureGradientColorizer::Make(std::move(te)); } // Analyze the shader's color stops and positions and chooses an appropriate colorizer to represent diff --git a/chromium/third_party/skia/src/gpu/gradients/GrTextureGradientColorizer.fp b/chromium/third_party/skia/src/gpu/gradients/GrTextureGradientColorizer.fp index c2146459f3e..b8dba025808 100644 --- a/chromium/third_party/skia/src/gpu/gradients/GrTextureGradientColorizer.fp +++ b/chromium/third_party/skia/src/gpu/gradients/GrTextureGradientColorizer.fp @@ -6,13 +6,9 @@ */ // Should have height = 1px, horizontal axis represents t = 0 to 1 -in uniform sampler2D gradient; - -@samplerParams(gradient) { - GrSamplerState::Filter::kBilerp -} +in fragmentProcessor textureFP; void main() { half2 coord = half2(sk_InColor.x, 0.5); - sk_OutColor = sample(gradient, coord); + sk_OutColor = sample(textureFP, coord); } diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrClampedGradientEffect.cpp b/chromium/third_party/skia/src/gpu/gradients/generated/GrClampedGradientEffect.cpp index 044165365d9..7e309c35b7e 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrClampedGradientEffect.cpp +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrClampedGradientEffect.cpp @@ -38,8 +38,14 @@ public: SkString _sample1099; _sample1099 = this->invokeChild(_outer.gradLayout_index, args); fragBuilder->codeAppendf( - "half4 t = %s;\nif (!%s && t.y < 0.0) {\n %s = half4(0.0);\n} else if (t.x < " - "0.0) {\n %s = %s;\n} else if (t.x > 1.0) {\n %s = %s;\n} else {", + R"SkSL(half4 t = %s; +if (!%s && t.y < 0.0) { + %s = half4(0.0); +} else if (t.x < 0.0) { + %s = %s; +} else if (t.x > 1.0) { + %s = %s; +} else {)SkSL", _sample1099.c_str(), (_outer.childProcessor(_outer.gradLayout_index).preservesOpaqueInput() ? "true" : "false"), @@ -49,10 +55,16 @@ public: SkString _input1767("t"); SkString _sample1767; _sample1767 = this->invokeChild(_outer.colorizer_index, _input1767.c_str(), args); - fragBuilder->codeAppendf("\n %s = %s;\n}\n@if (%s) {\n %s.xyz *= %s.w;\n}\n", - args.fOutputColor, _sample1767.c_str(), - (_outer.makePremul ? "true" : "false"), args.fOutputColor, - args.fOutputColor); + fragBuilder->codeAppendf( + R"SkSL( + %s = %s; +} +@if (%s) { + %s.xyz *= %s.w; +} +)SkSL", + args.fOutputColor, _sample1767.c_str(), (_outer.makePremul ? "true" : "false"), + args.fOutputColor, args.fOutputColor); } private: @@ -95,25 +107,17 @@ bool GrClampedGradientEffect::onIsEqual(const GrFragmentProcessor& other) const } GrClampedGradientEffect::GrClampedGradientEffect(const GrClampedGradientEffect& src) : INHERITED(kGrClampedGradientEffect_ClassID, src.optimizationFlags()) - , colorizer_index(src.colorizer_index) - , gradLayout_index(src.gradLayout_index) , leftBorderColor(src.leftBorderColor) , rightBorderColor(src.rightBorderColor) , makePremul(src.makePremul) , colorsAreOpaque(src.colorsAreOpaque) { { - auto clone = src.childProcessor(colorizer_index).clone(); - if (src.childProcessor(colorizer_index).isSampledWithExplicitCoords()) { - clone->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(clone)); + colorizer_index = + this->cloneAndRegisterChildProcessor(src.childProcessor(src.colorizer_index)); } { - auto clone = src.childProcessor(gradLayout_index).clone(); - if (src.childProcessor(gradLayout_index).isSampledWithExplicitCoords()) { - clone->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(clone)); + gradLayout_index = + this->cloneAndRegisterChildProcessor(src.childProcessor(src.gradLayout_index)); } } std::unique_ptr<GrFragmentProcessor> GrClampedGradientEffect::clone() const { diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrClampedGradientEffect.h b/chromium/third_party/skia/src/gpu/gradients/generated/GrClampedGradientEffect.h index 4779cdbb61f..eee25ff2726 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrClampedGradientEffect.h +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrClampedGradientEffect.h @@ -10,11 +10,13 @@ **************************************************************************************************/ #ifndef GrClampedGradientEffect_DEFINED #define GrClampedGradientEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrClampedGradientEffect : public GrFragmentProcessor { public: static std::unique_ptr<GrFragmentProcessor> Make( @@ -55,11 +57,9 @@ private: , makePremul(makePremul) , colorsAreOpaque(colorsAreOpaque) { SkASSERT(colorizer); - colorizer_index = this->numChildProcessors(); - this->registerChildProcessor(std::move(colorizer)); + colorizer_index = this->registerChild(std::move(colorizer)); SkASSERT(gradLayout); - gradLayout_index = this->numChildProcessors(); - this->registerChildProcessor(std::move(gradLayout)); + gradLayout_index = this->registerChild(std::move(gradLayout)); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrDualIntervalGradientColorizer.cpp b/chromium/third_party/skia/src/gpu/gradients/generated/GrDualIntervalGradientColorizer.cpp index 88b50df48f0..323fec5e1bb 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrDualIntervalGradientColorizer.cpp +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrDualIntervalGradientColorizer.cpp @@ -45,9 +45,17 @@ public: thresholdVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf_GrSLType, "threshold"); fragBuilder->codeAppendf( - "half t = %s.x;\nfloat4 scale, bias;\nif (t < %s) {\n scale = %s;\n bias = " - "%s;\n} else {\n scale = %s;\n bias = %s;\n}\n%s = half4(float(t) * scale + " - "bias);\n", + R"SkSL(half t = %s.x; +float4 scale, bias; +if (t < %s) { + scale = %s; + bias = %s; +} else { + scale = %s; + bias = %s; +} +%s = half4(float(t) * scale + bias); +)SkSL", args.fInputColor, args.fUniformHandler->getUniformCStr(thresholdVar), args.fUniformHandler->getUniformCStr(scale01Var), args.fUniformHandler->getUniformCStr(bias01Var), diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrDualIntervalGradientColorizer.h b/chromium/third_party/skia/src/gpu/gradients/generated/GrDualIntervalGradientColorizer.h index d8ebc1ef29b..58a97a3128a 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrDualIntervalGradientColorizer.h +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrDualIntervalGradientColorizer.h @@ -10,11 +10,13 @@ **************************************************************************************************/ #ifndef GrDualIntervalGradientColorizer_DEFINED #define GrDualIntervalGradientColorizer_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrDualIntervalGradientColorizer : public GrFragmentProcessor { public: static std::unique_ptr<GrFragmentProcessor> Make(const SkPMColor4f& c0, diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrLinearGradientLayout.cpp b/chromium/third_party/skia/src/gpu/gradients/generated/GrLinearGradientLayout.cpp index 2d28b92df08..5bc1732a773 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrLinearGradientLayout.cpp +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrLinearGradientLayout.cpp @@ -28,7 +28,9 @@ public: SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D( args.fTransformedCoords[0].fVaryingPoint, _outer.sampleMatrix()); fragBuilder->codeAppendf( - "half t = half(%s.x) + 9.9999997473787516e-06;\n%s = half4(t, 1.0, 0.0, 0.0);\n", + R"SkSL(half t = half(%s.x) + 9.9999997473787516e-06; +%s = half4(t, 1.0, 0.0, 0.0); +)SkSL", sk_TransformedCoords2D_0.c_str(), args.fOutputColor); } diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrLinearGradientLayout.h b/chromium/third_party/skia/src/gpu/gradients/generated/GrLinearGradientLayout.h index 6ecbeee850c..5c3323d2759 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrLinearGradientLayout.h +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrLinearGradientLayout.h @@ -10,14 +10,16 @@ **************************************************************************************************/ #ifndef GrLinearGradientLayout_DEFINED #define GrLinearGradientLayout_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/gradients/GrGradientShader.h" #include "src/shaders/gradients/SkLinearGradient.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrLinearGradientLayout : public GrFragmentProcessor { public: static std::unique_ptr<GrFragmentProcessor> Make(const SkLinearGradient& gradient, diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrRadialGradientLayout.cpp b/chromium/third_party/skia/src/gpu/gradients/generated/GrRadialGradientLayout.cpp index ecf6e742233..c17f77a3c48 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrRadialGradientLayout.cpp +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrRadialGradientLayout.cpp @@ -27,8 +27,11 @@ public: (void)gradientMatrix; SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D( args.fTransformedCoords[0].fVaryingPoint, _outer.sampleMatrix()); - fragBuilder->codeAppendf("half t = half(length(%s));\n%s = half4(t, 1.0, 0.0, 0.0);\n", - sk_TransformedCoords2D_0.c_str(), args.fOutputColor); + fragBuilder->codeAppendf( + R"SkSL(half t = half(length(%s)); +%s = half4(t, 1.0, 0.0, 0.0); +)SkSL", + sk_TransformedCoords2D_0.c_str(), args.fOutputColor); } private: diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrRadialGradientLayout.h b/chromium/third_party/skia/src/gpu/gradients/generated/GrRadialGradientLayout.h index 44be21202e4..897a97f02d2 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrRadialGradientLayout.h +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrRadialGradientLayout.h @@ -10,14 +10,16 @@ **************************************************************************************************/ #ifndef GrRadialGradientLayout_DEFINED #define GrRadialGradientLayout_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/gradients/GrGradientShader.h" #include "src/shaders/gradients/SkRadialGradient.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrRadialGradientLayout : public GrFragmentProcessor { public: static std::unique_ptr<GrFragmentProcessor> Make(const SkRadialGradient& gradient, diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrSingleIntervalGradientColorizer.cpp b/chromium/third_party/skia/src/gpu/gradients/generated/GrSingleIntervalGradientColorizer.cpp index cc4c82289d0..4a524a11f96 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrSingleIntervalGradientColorizer.cpp +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrSingleIntervalGradientColorizer.cpp @@ -32,10 +32,12 @@ public: kHalf4_GrSLType, "start"); endVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf4_GrSLType, "end"); - fragBuilder->codeAppendf("half t = %s.x;\n%s = (1.0 - t) * %s + t * %s;\n", - args.fInputColor, args.fOutputColor, - args.fUniformHandler->getUniformCStr(startVar), - args.fUniformHandler->getUniformCStr(endVar)); + fragBuilder->codeAppendf( + R"SkSL(half t = %s.x; +%s = (1.0 - t) * %s + t * %s; +)SkSL", + args.fInputColor, args.fOutputColor, args.fUniformHandler->getUniformCStr(startVar), + args.fUniformHandler->getUniformCStr(endVar)); } private: diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrSingleIntervalGradientColorizer.h b/chromium/third_party/skia/src/gpu/gradients/generated/GrSingleIntervalGradientColorizer.h index 2c808102c9d..a8cd30feea1 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrSingleIntervalGradientColorizer.h +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrSingleIntervalGradientColorizer.h @@ -10,11 +10,13 @@ **************************************************************************************************/ #ifndef GrSingleIntervalGradientColorizer_DEFINED #define GrSingleIntervalGradientColorizer_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrSingleIntervalGradientColorizer : public GrFragmentProcessor { public: static std::unique_ptr<GrFragmentProcessor> Make(SkPMColor4f start, SkPMColor4f end) { diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrSweepGradientLayout.cpp b/chromium/third_party/skia/src/gpu/gradients/generated/GrSweepGradientLayout.cpp index cd4653a75ea..0776671193d 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrSweepGradientLayout.cpp +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrSweepGradientLayout.cpp @@ -36,10 +36,15 @@ public: SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D( args.fTransformedCoords[0].fVaryingPoint, _outer.sampleMatrix()); fragBuilder->codeAppendf( - "half angle;\nif (sk_Caps.atan2ImplementedAsAtanYOverX) {\n angle = half(2.0 * " - "atan(-%s.y, length(%s) - %s.x));\n} else {\n angle = half(atan(-%s.y, " - "-%s.x));\n}\nhalf t = ((angle * 0.15915493667125702 + 0.5) + %s) * %s;\n%s = " - "half4(t, 1.0, 0.0, 0.0);\n", + R"SkSL(half angle; +if (sk_Caps.atan2ImplementedAsAtanYOverX) { + angle = half(2.0 * atan(-%s.y, length(%s) - %s.x)); +} else { + angle = half(atan(-%s.y, -%s.x)); +} +half t = ((angle * 0.15915493667125702 + 0.5) + %s) * %s; +%s = half4(t, 1.0, 0.0, 0.0); +)SkSL", sk_TransformedCoords2D_0.c_str(), sk_TransformedCoords2D_0.c_str(), sk_TransformedCoords2D_0.c_str(), sk_TransformedCoords2D_0.c_str(), sk_TransformedCoords2D_0.c_str(), args.fUniformHandler->getUniformCStr(biasVar), diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrSweepGradientLayout.h b/chromium/third_party/skia/src/gpu/gradients/generated/GrSweepGradientLayout.h index ef7a2ea4918..b547ec1db98 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrSweepGradientLayout.h +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrSweepGradientLayout.h @@ -10,14 +10,16 @@ **************************************************************************************************/ #ifndef GrSweepGradientLayout_DEFINED #define GrSweepGradientLayout_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/gradients/GrGradientShader.h" #include "src/shaders/gradients/SkSweepGradient.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrSweepGradientLayout : public GrFragmentProcessor { public: static std::unique_ptr<GrFragmentProcessor> Make(const SkSweepGradient& gradient, diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrTextureGradientColorizer.cpp b/chromium/third_party/skia/src/gpu/gradients/generated/GrTextureGradientColorizer.cpp index f2b079145de..c2f05339732 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrTextureGradientColorizer.cpp +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrTextureGradientColorizer.cpp @@ -24,13 +24,15 @@ public: const GrTextureGradientColorizer& _outer = args.fFp.cast<GrTextureGradientColorizer>(); (void)_outer; fragBuilder->codeAppendf( - "half2 coord = half2(%s.x, 0.5);\n%s = sample(%s, float2(coord)).%s;\n", - args.fInputColor, args.fOutputColor, - fragBuilder->getProgramBuilder()->samplerVariable(args.fTexSamplers[0]), - fragBuilder->getProgramBuilder() - ->samplerSwizzle(args.fTexSamplers[0]) - .asString() - .c_str()); + R"SkSL(half2 coord = half2(%s.x, 0.5);)SkSL", args.fInputColor); + SkString _sample327; + SkString _coords327("float2(coord)"); + _sample327 = this->invokeChild(_outer.textureFP_index, args, _coords327.c_str()); + fragBuilder->codeAppendf( + R"SkSL( +%s = %s; +)SkSL", + args.fOutputColor, _sample327.c_str()); } private: @@ -45,18 +47,15 @@ void GrTextureGradientColorizer::onGetGLSLProcessorKey(const GrShaderCaps& caps, bool GrTextureGradientColorizer::onIsEqual(const GrFragmentProcessor& other) const { const GrTextureGradientColorizer& that = other.cast<GrTextureGradientColorizer>(); (void)that; - if (gradient != that.gradient) return false; return true; } GrTextureGradientColorizer::GrTextureGradientColorizer(const GrTextureGradientColorizer& src) - : INHERITED(kGrTextureGradientColorizer_ClassID, src.optimizationFlags()) - , gradient(src.gradient) { - this->setTextureSamplerCnt(1); + : INHERITED(kGrTextureGradientColorizer_ClassID, src.optimizationFlags()) { + { + textureFP_index = + this->cloneAndRegisterChildProcessor(src.childProcessor(src.textureFP_index)); + } } std::unique_ptr<GrFragmentProcessor> GrTextureGradientColorizer::clone() const { return std::unique_ptr<GrFragmentProcessor>(new GrTextureGradientColorizer(*this)); } -const GrFragmentProcessor::TextureSampler& GrTextureGradientColorizer::onTextureSampler( - int index) const { - return IthTextureSampler(index, gradient); -} diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrTextureGradientColorizer.h b/chromium/third_party/skia/src/gpu/gradients/generated/GrTextureGradientColorizer.h index 0672b9fdf0d..b49637ac8f4 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrTextureGradientColorizer.h +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrTextureGradientColorizer.h @@ -10,32 +10,34 @@ **************************************************************************************************/ #ifndef GrTextureGradientColorizer_DEFINED #define GrTextureGradientColorizer_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrTextureGradientColorizer : public GrFragmentProcessor { public: - static std::unique_ptr<GrFragmentProcessor> Make(GrSurfaceProxyView gradient) { + static std::unique_ptr<GrFragmentProcessor> Make( + std::unique_ptr<GrFragmentProcessor> textureFP) { return std::unique_ptr<GrFragmentProcessor>( - new GrTextureGradientColorizer(std::move(gradient))); + new GrTextureGradientColorizer(std::move(textureFP))); } GrTextureGradientColorizer(const GrTextureGradientColorizer& src); std::unique_ptr<GrFragmentProcessor> clone() const override; const char* name() const override { return "TextureGradientColorizer"; } - TextureSampler gradient; + int textureFP_index = -1; private: - GrTextureGradientColorizer(GrSurfaceProxyView gradient) - : INHERITED(kGrTextureGradientColorizer_ClassID, kNone_OptimizationFlags) - , gradient(std::move(gradient), GrSamplerState::Filter::kBilerp) { - this->setTextureSamplerCnt(1); + GrTextureGradientColorizer(std::unique_ptr<GrFragmentProcessor> textureFP) + : INHERITED(kGrTextureGradientColorizer_ClassID, kNone_OptimizationFlags) { + SkASSERT(textureFP); + textureFP_index = this->registerExplicitlySampledChild(std::move(textureFP)); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; bool onIsEqual(const GrFragmentProcessor&) const override; - const TextureSampler& onTextureSampler(int) const override; GR_DECLARE_FRAGMENT_PROCESSOR_TEST typedef GrFragmentProcessor INHERITED; }; diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrTiledGradientEffect.cpp b/chromium/third_party/skia/src/gpu/gradients/generated/GrTiledGradientEffect.cpp index 248e7f9303d..3d9dc96d92c 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrTiledGradientEffect.cpp +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrTiledGradientEffect.cpp @@ -32,11 +32,20 @@ public: SkString _sample453; _sample453 = this->invokeChild(_outer.gradLayout_index, args); fragBuilder->codeAppendf( - "half4 t = %s;\nif (!%s && t.y < 0.0) {\n %s = half4(0.0);\n} else {\n @if " - "(%s) {\n half t_1 = t.x - 1.0;\n half tiled_t = (t_1 - 2.0 * " - "floor(t_1 * 0.5)) - 1.0;\n if (sk_Caps.mustDoOpBetweenFloorAndAbs) {\n " - " tiled_t = clamp(tiled_t, -1.0, 1.0);\n }\n t.x = " - "abs(tiled_t);\n } else {\n t.x = fract(t.x);\n }", + R"SkSL(half4 t = %s; +if (!%s && t.y < 0.0) { + %s = half4(0.0); +} else { + @if (%s) { + half t_1 = t.x - 1.0; + half tiled_t = (t_1 - 2.0 * floor(t_1 * 0.5)) - 1.0; + if (sk_Caps.mustDoOpBetweenFloorAndAbs) { + tiled_t = clamp(tiled_t, -1.0, 1.0); + } + t.x = abs(tiled_t); + } else { + t.x = fract(t.x); + })SkSL", _sample453.c_str(), (_outer.childProcessor(_outer.gradLayout_index).preservesOpaqueInput() ? "true" : "false"), @@ -44,10 +53,16 @@ public: SkString _input1464("t"); SkString _sample1464; _sample1464 = this->invokeChild(_outer.colorizer_index, _input1464.c_str(), args); - fragBuilder->codeAppendf("\n %s = %s;\n}\n@if (%s) {\n %s.xyz *= %s.w;\n}\n", - args.fOutputColor, _sample1464.c_str(), - (_outer.makePremul ? "true" : "false"), args.fOutputColor, - args.fOutputColor); + fragBuilder->codeAppendf( + R"SkSL( + %s = %s; +} +@if (%s) { + %s.xyz *= %s.w; +} +)SkSL", + args.fOutputColor, _sample1464.c_str(), (_outer.makePremul ? "true" : "false"), + args.fOutputColor, args.fOutputColor); } private: @@ -72,24 +87,16 @@ bool GrTiledGradientEffect::onIsEqual(const GrFragmentProcessor& other) const { } GrTiledGradientEffect::GrTiledGradientEffect(const GrTiledGradientEffect& src) : INHERITED(kGrTiledGradientEffect_ClassID, src.optimizationFlags()) - , colorizer_index(src.colorizer_index) - , gradLayout_index(src.gradLayout_index) , mirror(src.mirror) , makePremul(src.makePremul) , colorsAreOpaque(src.colorsAreOpaque) { { - auto clone = src.childProcessor(colorizer_index).clone(); - if (src.childProcessor(colorizer_index).isSampledWithExplicitCoords()) { - clone->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(clone)); + colorizer_index = + this->cloneAndRegisterChildProcessor(src.childProcessor(src.colorizer_index)); } { - auto clone = src.childProcessor(gradLayout_index).clone(); - if (src.childProcessor(gradLayout_index).isSampledWithExplicitCoords()) { - clone->setSampledWithExplicitCoords(); - } - this->registerChildProcessor(std::move(clone)); + gradLayout_index = + this->cloneAndRegisterChildProcessor(src.childProcessor(src.gradLayout_index)); } } std::unique_ptr<GrFragmentProcessor> GrTiledGradientEffect::clone() const { diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrTiledGradientEffect.h b/chromium/third_party/skia/src/gpu/gradients/generated/GrTiledGradientEffect.h index d22d1c61106..4fbf2d3b264 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrTiledGradientEffect.h +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrTiledGradientEffect.h @@ -10,11 +10,13 @@ **************************************************************************************************/ #ifndef GrTiledGradientEffect_DEFINED #define GrTiledGradientEffect_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrTiledGradientEffect : public GrFragmentProcessor { public: static std::unique_ptr<GrFragmentProcessor> Make( @@ -50,11 +52,9 @@ private: , makePremul(makePremul) , colorsAreOpaque(colorsAreOpaque) { SkASSERT(colorizer); - colorizer_index = this->numChildProcessors(); - this->registerChildProcessor(std::move(colorizer)); + colorizer_index = this->registerChild(std::move(colorizer)); SkASSERT(gradLayout); - gradLayout_index = this->numChildProcessors(); - this->registerChildProcessor(std::move(gradLayout)); + gradLayout_index = this->registerChild(std::move(gradLayout)); } GrGLSLFragmentProcessor* onCreateGLSLInstance() const override; void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override; diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrTwoPointConicalGradientLayout.cpp b/chromium/third_party/skia/src/gpu/gradients/generated/GrTwoPointConicalGradientLayout.cpp index 2f80228e6a1..fa172c76c29 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrTwoPointConicalGradientLayout.cpp +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrTwoPointConicalGradientLayout.cpp @@ -45,48 +45,90 @@ public: SkString sk_TransformedCoords2D_0 = fragBuilder->ensureCoords2D( args.fTransformedCoords[0].fVaryingPoint, _outer.sampleMatrix()); fragBuilder->codeAppendf( - "float2 p = %s;\nfloat t = -1.0;\nhalf v = 1.0;\n@switch (%d) {\n case 1:\n " - " {\n half r0_2 = %s.y;\n t = float(r0_2) - p.y * p.y;\n " - " if (t >= 0.0) {\n t = p.x + sqrt(t);\n } else " - "{\n v = -1.0;\n }\n }\n break;\n case " - "0:\n {\n half r0 = %s.x;\n @if (%s) {\n " - " t = length(p) - float(r0);\n } else {\n t = " - "-length(p) - float(r0);\n ", + R"SkSL(float2 p = %s; +float t = -1.0; +half v = 1.0; +@switch (%d) { + case 1: + { + half r0_2 = %s.y; + t = float(r0_2) - p.y * p.y; + if (t >= 0.0) { + t = p.x + sqrt(t); + } else { + v = -1.0; + } + } + break; + case 0: + { + half r0 = %s.x; + @if (%s) { + t = length(p) - float(r0); + } else { + t = -length(p) - float(r0); + } + } + break; + case 2: + { + half invR1 = %s.x; + half fx = %s.y; + float x_t = -1.0; + @if (%s) { + x_t = dot(p, p) / p.x; + } else if (%s) { + x_t = length(p) - p.x * float(invR1); + } else { + float temp = p.x * p.x - p.y * p.y; + if (temp >= 0.0) { + @if (%s || !%s) { + x_t = -sqrt(temp) - p.x * float(invR1); + } else { + x_t = sqrt(temp) - p.x * float(invR1); + } + } + } + @if (!%s) { + if (x_t <= 0.0) { + v = -1.0; + } + } + @if (%s) { + @if (%s) { + t = x_t; + } else { + t = x_t + float(fx); + } + } else { + @if (%s) { + t = -x_t; + } else { + t = -x_t + float(fx); + } + } + @if (%s) { + t = 1.0 - t; + } + } + break; +} +%s = half4(half(t), v, 0.0, 0.0); +)SkSL", sk_TransformedCoords2D_0.c_str(), (int)_outer.type, args.fUniformHandler->getUniformCStr(focalParamsVar), args.fUniformHandler->getUniformCStr(focalParamsVar), - (_outer.isRadiusIncreasing ? "true" : "false")); - fragBuilder->codeAppendf( - " }\n }\n break;\n case 2:\n {\n half invR1 " - "= %s.x;\n half fx = %s.y;\n float x_t = -1.0;\n " - "@if (%s) {\n x_t = dot(p, p) / p.x;\n } else if (%s) " - "{\n x_t = length(p) - p.x * float(invR1);\n } else {\n " - " float temp = p.x * p.x - p.y * p.y;\n if (temp >= " - "0.0) {\n @if (%s || !%s) {\n x_t = " - "-sqrt(temp) - p.x * float(invR1)", + (_outer.isRadiusIncreasing ? "true" : "false"), args.fUniformHandler->getUniformCStr(focalParamsVar), args.fUniformHandler->getUniformCStr(focalParamsVar), (_outer.isFocalOnCircle ? "true" : "false"), (_outer.isWellBehaved ? "true" : "false"), (_outer.isSwapped ? "true" : "false"), - (_outer.isRadiusIncreasing ? "true" : "false")); - fragBuilder->codeAppendf( - ";\n } else {\n x_t = sqrt(temp) - p.x * " - "float(invR1);\n }\n }\n }\n " - " @if (!%s) {\n if (x_t <= 0.0) {\n v = -1.0;\n " - " }\n }\n @if (%s) {\n @if (%s) " - "{\n t = x_t;\n } else {\n t " - "= x_t + float(fx);\n }\n } else {\n @if " - "(%s) {\n ", + (_outer.isRadiusIncreasing ? "true" : "false"), (_outer.isWellBehaved ? "true" : "false"), (_outer.isRadiusIncreasing ? "true" : "false"), (_outer.isNativelyFocal ? "true" : "false"), - (_outer.isNativelyFocal ? "true" : "false")); - fragBuilder->codeAppendf( - " t = -x_t;\n } else {\n t = -x_t + " - "float(fx);\n }\n }\n @if (%s) {\n " - " t = 1.0 - t;\n }\n }\n break;\n}\n%s = " - "half4(half(t), v, 0.0, 0.0);\n", - (_outer.isSwapped ? "true" : "false"), args.fOutputColor); + (_outer.isNativelyFocal ? "true" : "false"), (_outer.isSwapped ? "true" : "false"), + args.fOutputColor); } private: diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrTwoPointConicalGradientLayout.h b/chromium/third_party/skia/src/gpu/gradients/generated/GrTwoPointConicalGradientLayout.h index 4a08aea9831..afd93db24f3 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrTwoPointConicalGradientLayout.h +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrTwoPointConicalGradientLayout.h @@ -10,14 +10,16 @@ **************************************************************************************************/ #ifndef GrTwoPointConicalGradientLayout_DEFINED #define GrTwoPointConicalGradientLayout_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/gradients/GrGradientShader.h" #include "src/shaders/gradients/SkTwoPointConicalGradient.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrTwoPointConicalGradientLayout : public GrFragmentProcessor { public: enum class Type { kFocal = 2, kRadial = 0, kStrip = 1 }; diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrUnrolledBinaryGradientColorizer.cpp b/chromium/third_party/skia/src/gpu/gradients/generated/GrUnrolledBinaryGradientColorizer.cpp index 3f5c5aca95d..38368dbb505 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrUnrolledBinaryGradientColorizer.cpp +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrUnrolledBinaryGradientColorizer.cpp @@ -127,13 +127,47 @@ public: thresholds9_13Var = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag, kHalf4_GrSLType, "thresholds9_13"); fragBuilder->codeAppendf( - "half t = %s.x;\nfloat4 scale, bias;\nif (%d <= 4 || t < %s.w) {\n if (%d <= 2 " - "|| t < %s.y) {\n if (%d <= 1 || t < %s.x) {\n scale = %s;\n " - " bias = %s;\n } else {\n scale = %s;\n bias = " - "%s;\n }\n } else {\n if (%d <= 3 || t < %s.z) {\n " - "scale = %s;\n bias = %s;\n } else {\n scale = %s;\n " - " bias = %s;\n }\n }\n} else {\n if (%d <= 6 || t < %s.y) " - "{\n if (%d <= 5 || t <", + R"SkSL(half t = %s.x; +float4 scale, bias; +if (%d <= 4 || t < %s.w) { + if (%d <= 2 || t < %s.y) { + if (%d <= 1 || t < %s.x) { + scale = %s; + bias = %s; + } else { + scale = %s; + bias = %s; + } + } else { + if (%d <= 3 || t < %s.z) { + scale = %s; + bias = %s; + } else { + scale = %s; + bias = %s; + } + } +} else { + if (%d <= 6 || t < %s.y) { + if (%d <= 5 || t < %s.x) { + scale = %s; + bias = %s; + } else { + scale = %s; + bias = %s; + } + } else { + if (%d <= 7 || t < %s.z) { + scale = %s; + bias = %s; + } else { + scale = %s; + bias = %s; + } + } +} +%s = half4(float(t) * scale + bias); +)SkSL", args.fInputColor, _outer.intervalCount, args.fUniformHandler->getUniformCStr(thresholds1_7Var), _outer.intervalCount, args.fUniformHandler->getUniformCStr(thresholds1_7Var), _outer.intervalCount, @@ -154,14 +188,7 @@ public: bias6_7Var.isValid() ? args.fUniformHandler->getUniformCStr(bias6_7Var) : "float4(0)", _outer.intervalCount, args.fUniformHandler->getUniformCStr(thresholds9_13Var), - _outer.intervalCount); - fragBuilder->codeAppendf( - " %s.x) {\n scale = %s;\n bias = %s;\n } else {\n " - " scale = %s;\n bias = %s;\n }\n } else {\n if " - "(%d <= 7 || t < %s.z) {\n scale = %s;\n bias = %s;\n " - "} else {\n scale = %s;\n bias = %s;\n }\n " - "}\n}\n%s = half4(float(t) * scale + bias);\n", - args.fUniformHandler->getUniformCStr(thresholds9_13Var), + _outer.intervalCount, args.fUniformHandler->getUniformCStr(thresholds9_13Var), scale8_9Var.isValid() ? args.fUniformHandler->getUniformCStr(scale8_9Var) : "float4(0)", bias8_9Var.isValid() ? args.fUniformHandler->getUniformCStr(bias8_9Var) diff --git a/chromium/third_party/skia/src/gpu/gradients/generated/GrUnrolledBinaryGradientColorizer.h b/chromium/third_party/skia/src/gpu/gradients/generated/GrUnrolledBinaryGradientColorizer.h index 9c9ecea611f..144cd8c0447 100644 --- a/chromium/third_party/skia/src/gpu/gradients/generated/GrUnrolledBinaryGradientColorizer.h +++ b/chromium/third_party/skia/src/gpu/gradients/generated/GrUnrolledBinaryGradientColorizer.h @@ -10,11 +10,13 @@ **************************************************************************************************/ #ifndef GrUnrolledBinaryGradientColorizer_DEFINED #define GrUnrolledBinaryGradientColorizer_DEFINED -#include "include/core/SkTypes.h" + #include "include/core/SkM44.h" +#include "include/core/SkTypes.h" #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrFragmentProcessor.h" + class GrUnrolledBinaryGradientColorizer : public GrFragmentProcessor { public: static const int kMaxColorCount = 16; diff --git a/chromium/third_party/skia/src/gpu/mock/GrMockCaps.h b/chromium/third_party/skia/src/gpu/mock/GrMockCaps.h index 42a97144593..6548aa634ba 100644 --- a/chromium/third_party/skia/src/gpu/mock/GrMockCaps.h +++ b/chromium/third_party/skia/src/gpu/mock/GrMockCaps.h @@ -35,7 +35,7 @@ public: fShaderCaps->fShaderDerivativeSupport = options.fShaderDerivativeSupport; fShaderCaps->fDualSourceBlendingSupport = options.fDualSourceBlendingSupport; fShaderCaps->fSampleMaskSupport = true; - fShaderCaps->fTessellationSupport = options.fTessellationSupport; + fShaderCaps->fMaxTessellationSegments = options.fMaxTessellationSegments; this->finishInitialization(contextOptions); } @@ -50,10 +50,6 @@ public: return GrGetColorTypeDesc(ct).encoding() == GrColorTypeEncoding::kSRGBUnorm; } - SkImage::CompressionType compressionType(const GrBackendFormat& format) const override { - return format.asMockCompressionType(); - } - bool isFormatTexturable(const GrBackendFormat& format) const override { SkImage::CompressionType compression = format.asMockCompressionType(); if (compression != SkImage::CompressionType::kNone) { @@ -155,10 +151,6 @@ public: return {}; } - GrSwizzle getReadSwizzle(const GrBackendFormat& format, GrColorType ct) const override { - SkASSERT(this->areColorTypeAndFormatCompatible(ct, format)); - return GrSwizzle("rgba"); - } GrSwizzle getWriteSwizzle(const GrBackendFormat& format, GrColorType ct) const override { SkASSERT(this->areColorTypeAndFormatCompatible(ct, format)); return GrSwizzle("rgba"); @@ -205,6 +197,11 @@ private: return SupportedRead{srcColorType, 1}; } + GrSwizzle onGetReadSwizzle(const GrBackendFormat& format, GrColorType ct) const override { + SkASSERT(this->areColorTypeAndFormatCompatible(ct, format)); + return GrSwizzle("rgba"); + } + static const int kMaxSampleCnt = 16; GrMockOptions fOptions; diff --git a/chromium/third_party/skia/src/gpu/mock/GrMockGpu.cpp b/chromium/third_party/skia/src/gpu/mock/GrMockGpu.cpp index 3348c4bbdb7..ccd1157cf89 100644 --- a/chromium/third_party/skia/src/gpu/mock/GrMockGpu.cpp +++ b/chromium/third_party/skia/src/gpu/mock/GrMockGpu.cpp @@ -53,7 +53,8 @@ sk_sp<GrGpu> GrMockGpu::Make(const GrMockOptions* mockOptions, } GrOpsRenderPass* GrMockGpu::getOpsRenderPass( - GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds, + GrRenderTarget* rt, GrStencilAttachment*, + GrSurfaceOrigin origin, const SkIRect& bounds, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo&, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { diff --git a/chromium/third_party/skia/src/gpu/mock/GrMockGpu.h b/chromium/third_party/skia/src/gpu/mock/GrMockGpu.h index 05fdda7599a..29dda81d2b3 100644 --- a/chromium/third_party/skia/src/gpu/mock/GrMockGpu.h +++ b/chromium/third_party/skia/src/gpu/mock/GrMockGpu.h @@ -25,7 +25,10 @@ public: ~GrMockGpu() override {} GrOpsRenderPass* getOpsRenderPass( - GrRenderTarget*, GrSurfaceOrigin, const SkIRect&, + GrRenderTarget*, + GrStencilAttachment*, + GrSurfaceOrigin, + const SkIRect&, const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; diff --git a/chromium/third_party/skia/src/gpu/mock/GrMockOpsRenderPass.h b/chromium/third_party/skia/src/gpu/mock/GrMockOpsRenderPass.h index 5a45a3e9713..703eac21333 100644 --- a/chromium/third_party/skia/src/gpu/mock/GrMockOpsRenderPass.h +++ b/chromium/third_party/skia/src/gpu/mock/GrMockOpsRenderPass.h @@ -45,8 +45,10 @@ private: void onDrawIndexedInstanced(int, int, int, int, int) override { this->dummyDraw(); } void onDrawIndirect(const GrBuffer*, size_t, int) override { this->dummyDraw(); } void onDrawIndexedIndirect(const GrBuffer*, size_t, int) override { this->dummyDraw(); } - void onClear(const GrFixedClip&, const SkPMColor4f&) override { this->markRenderTargetDirty(); } - void onClearStencilClip(const GrFixedClip&, bool insideStencilMask) override {} + void onClear(const GrScissorState& scissor, const SkPMColor4f&) override { + this->markRenderTargetDirty(); + } + void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override {} void dummyDraw() { this->markRenderTargetDirty(); ++fNumDraws; diff --git a/chromium/third_party/skia/src/gpu/mtl/GrMtlCaps.h b/chromium/third_party/skia/src/gpu/mtl/GrMtlCaps.h index 09ae534a9b6..0650c5a9b61 100644 --- a/chromium/third_party/skia/src/gpu/mtl/GrMtlCaps.h +++ b/chromium/third_party/skia/src/gpu/mtl/GrMtlCaps.h @@ -27,7 +27,6 @@ public: MTLFeatureSet featureSet); bool isFormatSRGB(const GrBackendFormat&) const override; - SkImage::CompressionType compressionType(const GrBackendFormat&) const override; bool isFormatTexturable(const GrBackendFormat&) const override; bool isFormatTexturable(MTLPixelFormat) const; @@ -82,7 +81,6 @@ public: return fColorTypeToFormatTable[idx]; } - GrSwizzle getReadSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getWriteSwizzle(const GrBackendFormat&, GrColorType) const override; uint64_t computeFormatKey(const GrBackendFormat&) const override; @@ -113,6 +111,8 @@ private: SupportedRead onSupportedReadPixelsColorType(GrColorType, const GrBackendFormat&, GrColorType) const override; + GrSwizzle onGetReadSwizzle(const GrBackendFormat&, GrColorType) const override; + // ColorTypeInfo for a specific format struct ColorTypeInfo { GrColorType fColorType = GrColorType::kUnknown; diff --git a/chromium/third_party/skia/src/gpu/mtl/GrMtlCaps.mm b/chromium/third_party/skia/src/gpu/mtl/GrMtlCaps.mm index 4b28bf7034b..2fb81021f4e 100644 --- a/chromium/third_party/skia/src/gpu/mtl/GrMtlCaps.mm +++ b/chromium/third_party/skia/src/gpu/mtl/GrMtlCaps.mm @@ -10,6 +10,7 @@ #include "include/core/SkRect.h" #include "include/gpu/GrBackendSurface.h" #include "src/core/SkCompressedDataUtils.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrProcessor.h" #include "src/gpu/GrProgramDesc.h" #include "src/gpu/GrProgramInfo.h" @@ -318,24 +319,6 @@ bool GrMtlCaps::isFormatSRGB(const GrBackendFormat& format) const { return format_is_srgb(GrBackendFormatAsMTLPixelFormat(format)); } -SkImage::CompressionType GrMtlCaps::compressionType(const GrBackendFormat& format) const { - - switch (GrBackendFormatAsMTLPixelFormat(format)) { -#ifdef SK_BUILD_FOR_IOS - case MTLPixelFormatETC2_RGB8: - // ETC2 uses the same compression layout as ETC1 - return SkImage::CompressionType::kETC2_RGB8_UNORM; -#else - case MTLPixelFormatBC1_RGBA: - return SkImage::CompressionType::kBC1_RGBA8_UNORM; -#endif - default: - return SkImage::CompressionType::kNone; - } - - SkUNREACHABLE; -} - bool GrMtlCaps::isFormatTexturable(const GrBackendFormat& format) const { MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format); return this->isFormatTexturable(mtlFormat); @@ -900,12 +883,6 @@ bool GrMtlCaps::onAreColorTypeAndFormatCompatible(GrColorType ct, const GrBackendFormat& format) const { MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format); - SkImage::CompressionType compression = GrMtlFormatToCompressionType(mtlFormat); - if (compression != SkImage::CompressionType::kNone) { - return ct == (SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x - : GrColorType::kRGBA_8888); - } - const auto& info = this->getFormatInfo(mtlFormat); for (int i = 0; i < info.fColorTypeInfoCount; ++i) { if (info.fColorTypeInfos[i].fColorType == ct) { @@ -948,7 +925,7 @@ GrBackendFormat GrMtlCaps::getBackendFormatFromCompressionType( SK_ABORT("Invalid compression type"); } -GrSwizzle GrMtlCaps::getReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const { +GrSwizzle GrMtlCaps::onGetReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const { MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format); SkASSERT(mtlFormat != MTLPixelFormatInvalid); const auto& info = this->getFormatInfo(mtlFormat); @@ -1008,9 +985,7 @@ GrCaps::SupportedWrite GrMtlCaps::supportedWritePixelsColorType( GrCaps::SupportedRead GrMtlCaps::onSupportedReadPixelsColorType( GrColorType srcColorType, const GrBackendFormat& srcBackendFormat, GrColorType dstColorType) const { - MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(srcBackendFormat); - - SkImage::CompressionType compression = GrMtlFormatToCompressionType(mtlFormat); + SkImage::CompressionType compression = GrBackendFormatToCompressionType(srcBackendFormat); if (compression != SkImage::CompressionType::kNone) { #ifdef SK_BUILD_FOR_IOS // Reading back to kRGB_888x doesn't work on Metal/iOS (skbug.com/9839) @@ -1024,6 +999,7 @@ GrCaps::SupportedRead GrMtlCaps::onSupportedReadPixelsColorType( // Metal requires the destination offset for copyFromTexture to be a multiple of the textures // pixels size. size_t offsetAlignment = GrColorTypeBytesPerPixel(srcColorType); + MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(srcBackendFormat); const auto& info = this->getFormatInfo(mtlFormat); for (int i = 0; i < info.fColorTypeInfoCount; ++i) { diff --git a/chromium/third_party/skia/src/gpu/mtl/GrMtlCppUtil.h b/chromium/third_party/skia/src/gpu/mtl/GrMtlCppUtil.h index f431ec81076..bcbdbdd4b14 100644 --- a/chromium/third_party/skia/src/gpu/mtl/GrMtlCppUtil.h +++ b/chromium/third_party/skia/src/gpu/mtl/GrMtlCppUtil.h @@ -8,14 +8,19 @@ #ifndef GrMtlCppUtil_DEFINED #define GrMtlCppUtil_DEFINED +#include "include/core/SkImage.h" #include "include/gpu/mtl/GrMtlTypes.h" +class GrBackendFormat; + // Utilities that can be used from cpp files (rather than .mm). GrMTLPixelFormat GrGetMTLPixelFormatFromMtlTextureInfo(const GrMtlTextureInfo&); uint32_t GrMtlFormatChannels(GrMTLPixelFormat); +SkImage::CompressionType GrMtlBackendFormatToCompressionType(const GrBackendFormat& format); + #if GR_TEST_UTILS const char* GrMtlFormatToStr(GrMTLPixelFormat mtlFormat); bool GrMtlFormatIsBGRA8(GrMTLPixelFormat mtlFormat); diff --git a/chromium/third_party/skia/src/gpu/mtl/GrMtlGpu.h b/chromium/third_party/skia/src/gpu/mtl/GrMtlGpu.h index 191c0bacf37..16bd0fe8442 100644 --- a/chromium/third_party/skia/src/gpu/mtl/GrMtlGpu.h +++ b/chromium/third_party/skia/src/gpu/mtl/GrMtlGpu.h @@ -68,6 +68,10 @@ public: void deleteTestingOnlyBackendRenderTarget(const GrBackendRenderTarget&) override; void testingOnly_flushGpuAndSync() override; + + void resetShaderCacheForTesting() const override { + fResourceProvider.resetShaderCacheForTesting(); + } #endif void copySurfaceAsResolve(GrSurface* dst, GrSurface* src); @@ -79,7 +83,8 @@ public: const SkIPoint& dstPoint) override; GrOpsRenderPass* getOpsRenderPass( - GrRenderTarget*, GrSurfaceOrigin, const SkIRect& bounds, + GrRenderTarget*, GrStencilAttachment*, + GrSurfaceOrigin, const SkIRect& bounds, const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; diff --git a/chromium/third_party/skia/src/gpu/mtl/GrMtlGpu.mm b/chromium/third_party/skia/src/gpu/mtl/GrMtlGpu.mm index 420bb896679..dced04f7b58 100644 --- a/chromium/third_party/skia/src/gpu/mtl/GrMtlGpu.mm +++ b/chromium/third_party/skia/src/gpu/mtl/GrMtlGpu.mm @@ -11,6 +11,7 @@ #include "src/core/SkCompressedDataUtils.h" #include "src/core/SkConvertPixels.h" #include "src/core/SkMipMap.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrDataUtils.h" #include "src/gpu/GrRenderTargetPriv.h" #include "src/gpu/GrTexturePriv.h" @@ -159,7 +160,8 @@ void GrMtlGpu::destroyResources() { } GrOpsRenderPass* GrMtlGpu::getOpsRenderPass( - GrRenderTarget* renderTarget, GrSurfaceOrigin origin, const SkIRect& bounds, + GrRenderTarget* renderTarget, GrStencilAttachment*, + GrSurfaceOrigin origin, const SkIRect& bounds, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { @@ -545,7 +547,7 @@ sk_sp<GrTexture> GrMtlGpu::onCreateCompressedTexture(SkISize dimensions, id<MTLTexture> mtlTexture = tex->mtlTexture(); SkASSERT(mtlTexture); - auto compressionType = GrMtlFormatToCompressionType(mtlTexture.pixelFormat); + auto compressionType = GrBackendFormatToCompressionType(format); SkASSERT(compressionType != SkImage::CompressionType::kNone); SkTArray<size_t> individualMipOffsets(numMipLevels); @@ -844,7 +846,8 @@ bool GrMtlGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture, int numMipLevels = mtlTexture.mipmapLevelCount; GrMipMapped mipMapped = numMipLevels > 1 ? GrMipMapped::kYes : GrMipMapped::kNo; - SkImage::CompressionType compression = GrMtlFormatToCompressionType(mtlFormat); + SkImage::CompressionType compression = GrBackendFormatToCompressionType( + backendTexture.getBackendFormat()); // Create a transfer buffer and fill with data. SkSTArray<16, size_t> individualMipOffsets; @@ -1349,6 +1352,7 @@ std::unique_ptr<GrSemaphore> GrMtlGpu::wrapBackendSemaphore( void GrMtlGpu::insertSemaphore(GrSemaphore* semaphore) { if (@available(macOS 10.14, iOS 12.0, *)) { + SkASSERT(semaphore); GrMtlSemaphore* mtlSem = static_cast<GrMtlSemaphore*>(semaphore); this->commandBuffer()->encodeSignalEvent(mtlSem->event(), mtlSem->value()); @@ -1357,6 +1361,7 @@ void GrMtlGpu::insertSemaphore(GrSemaphore* semaphore) { void GrMtlGpu::waitSemaphore(GrSemaphore* semaphore) { if (@available(macOS 10.14, iOS 12.0, *)) { + SkASSERT(semaphore); GrMtlSemaphore* mtlSem = static_cast<GrMtlSemaphore*>(semaphore); this->commandBuffer()->encodeWaitForEvent(mtlSem->event(), mtlSem->value()); diff --git a/chromium/third_party/skia/src/gpu/mtl/GrMtlOpsRenderPass.h b/chromium/third_party/skia/src/gpu/mtl/GrMtlOpsRenderPass.h index 77229ce8487..c4cf385ef0d 100644 --- a/chromium/third_party/skia/src/gpu/mtl/GrMtlOpsRenderPass.h +++ b/chromium/third_party/skia/src/gpu/mtl/GrMtlOpsRenderPass.h @@ -49,9 +49,9 @@ private: void onDrawIndexedInstanced(int indexCount, int baseIndex, int instanceCount, int baseInstance, int baseVertex) override; - void onClear(const GrFixedClip& clip, const SkPMColor4f& color) override; + void onClear(const GrScissorState& scissor, const SkPMColor4f& color) override; - void onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) override; + void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override; void setupRenderPass(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo); @@ -80,4 +80,3 @@ private: }; #endif - diff --git a/chromium/third_party/skia/src/gpu/mtl/GrMtlOpsRenderPass.mm b/chromium/third_party/skia/src/gpu/mtl/GrMtlOpsRenderPass.mm index 576a1349c3b..13ef3a3bce8 100644 --- a/chromium/third_party/skia/src/gpu/mtl/GrMtlOpsRenderPass.mm +++ b/chromium/third_party/skia/src/gpu/mtl/GrMtlOpsRenderPass.mm @@ -8,7 +8,6 @@ #include "src/gpu/mtl/GrMtlOpsRenderPass.h" #include "src/gpu/GrColor.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrRenderTargetPriv.h" #include "src/gpu/mtl/GrMtlCommandBuffer.h" #include "src/gpu/mtl/GrMtlPipelineState.h" @@ -123,7 +122,10 @@ bool GrMtlOpsRenderPass::onBindTextures(const GrPrimitiveProcessor& primProc, return true; } -void GrMtlOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) { +void GrMtlOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) { + // Partial clears are not supported + SkASSERT(!scissor.enabled()); + // Ideally we should never end up here since all clears should either be done as draws or // load ops in metal. However, if a client inserts a wait op we need to handle it. fRenderPassDesc.colorAttachments[0].clearColor = @@ -135,8 +137,9 @@ void GrMtlOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& col fGpu->commandBuffer()->getRenderCommandEncoder(fRenderPassDesc, nullptr, this); } -void GrMtlOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) { - SkASSERT(!clip.hasWindowRectangles()); +void GrMtlOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) { + // Partial clears are not supported + SkASSERT(!scissor.enabled()); GrStencilAttachment* sb = fRenderTarget->renderTargetPriv().getStencilAttachment(); // this should only be called internally when we know we have a diff --git a/chromium/third_party/skia/src/gpu/mtl/GrMtlPipelineStateBuilder.h b/chromium/third_party/skia/src/gpu/mtl/GrMtlPipelineStateBuilder.h index cd1d1021523..eed06eb2c54 100644 --- a/chromium/third_party/skia/src/gpu/mtl/GrMtlPipelineStateBuilder.h +++ b/chromium/third_party/skia/src/gpu/mtl/GrMtlPipelineStateBuilder.h @@ -21,7 +21,7 @@ class GrProgramInfo; class GrMtlCaps; class GrMtlGpu; class GrMtlPipelineState; -class SkReader32; +class SkReadBuffer; class GrMtlPipelineStateBuilder : public GrGLSLProgramBuilder { public: @@ -58,7 +58,7 @@ private: SkSL::Program::Inputs inputs); void storeShadersInCache(const SkSL::String shaders[], const SkSL::Program::Inputs inputs[], bool isSkSL); - void loadShadersFromCache(SkReader32* cached, __strong id<MTLLibrary> outLibraries[]); + bool loadShadersFromCache(SkReadBuffer* cached, __strong id<MTLLibrary> outLibraries[]); GrGLSLUniformHandler* uniformHandler() override { return &fUniformHandler; } const GrGLSLUniformHandler* uniformHandler() const override { return &fUniformHandler; } diff --git a/chromium/third_party/skia/src/gpu/mtl/GrMtlPipelineStateBuilder.mm b/chromium/third_party/skia/src/gpu/mtl/GrMtlPipelineStateBuilder.mm index 3c2c91bb039..0bfd4ee7976 100644 --- a/chromium/third_party/skia/src/gpu/mtl/GrMtlPipelineStateBuilder.mm +++ b/chromium/third_party/skia/src/gpu/mtl/GrMtlPipelineStateBuilder.mm @@ -8,7 +8,7 @@ #include "src/gpu/mtl/GrMtlPipelineStateBuilder.h" #include "include/gpu/GrContext.h" -#include "src/core/SkReader32.h" +#include "src/core/SkReadBuffer.h" #include "src/core/SkTraceEvent.h" #include "src/gpu/GrAutoLocaleSetter.h" #include "src/gpu/GrContextPriv.h" @@ -66,12 +66,14 @@ static constexpr SkFourByteTag kMSL_Tag = SkSetFourByteTag('M', 'S', 'L', ' '); static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L'); -void GrMtlPipelineStateBuilder::loadShadersFromCache(SkReader32* cached, +bool GrMtlPipelineStateBuilder::loadShadersFromCache(SkReadBuffer* cached, __strong id<MTLLibrary> outLibraries[]) { SkSL::String shaders[kGrShaderTypeCount]; SkSL::Program::Inputs inputs[kGrShaderTypeCount]; - GrPersistentCacheUtils::UnpackCachedShaders(cached, shaders, inputs, kGrShaderTypeCount); + if (!GrPersistentCacheUtils::UnpackCachedShaders(cached, shaders, inputs, kGrShaderTypeCount)) { + return false; + } outLibraries[kVertex_GrShaderType] = this->compileMtlShaderLibrary( shaders[kVertex_GrShaderType], @@ -80,11 +82,9 @@ void GrMtlPipelineStateBuilder::loadShadersFromCache(SkReader32* cached, shaders[kFragment_GrShaderType], inputs[kFragment_GrShaderType]); - // Geometry shaders are not supported - SkASSERT(shaders[kGeometry_GrShaderType].empty()); - - SkASSERT(outLibraries[kVertex_GrShaderType]); - SkASSERT(outLibraries[kFragment_GrShaderType]); + return outLibraries[kVertex_GrShaderType] && + outLibraries[kFragment_GrShaderType] && + shaders[kGeometry_GrShaderType].empty(); // Geometry shaders are not supported } void GrMtlPipelineStateBuilder::storeShadersInCache(const SkSL::String shaders[], @@ -399,7 +399,7 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(GrRenderTarget* renderTa SkASSERT(!this->fragColorIsInOut()); sk_sp<SkData> cached; - SkReader32 reader; + SkReadBuffer reader; SkFourByteTag shaderType = 0; auto persistentCache = fGpu->getContext()->priv().getPersistentCache(); if (persistentCache) { @@ -414,10 +414,10 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(GrRenderTarget* renderTa } } - SkSL::String shaders[kGrShaderTypeCount]; - if (kMSL_Tag == shaderType) { - this->loadShadersFromCache(&reader, shaderLibraries); + if (kMSL_Tag == shaderType && this->loadShadersFromCache(&reader, shaderLibraries)) { + // We successfully loaded and compiled MSL } else { + SkSL::String shaders[kGrShaderTypeCount]; SkSL::Program::Inputs inputs[kGrShaderTypeCount]; SkSL::String* sksl[kGrShaderTypeCount] = { @@ -427,10 +427,11 @@ GrMtlPipelineState* GrMtlPipelineStateBuilder::finalize(GrRenderTarget* renderTa }; SkSL::String cached_sksl[kGrShaderTypeCount]; if (kSKSL_Tag == shaderType) { - GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, inputs, - kGrShaderTypeCount); - for (int i = 0; i < kGrShaderTypeCount; ++i) { - sksl[i] = &cached_sksl[i]; + if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, inputs, + kGrShaderTypeCount)) { + for (int i = 0; i < kGrShaderTypeCount; ++i) { + sksl[i] = &cached_sksl[i]; + } } } diff --git a/chromium/third_party/skia/src/gpu/mtl/GrMtlResourceProvider.h b/chromium/third_party/skia/src/gpu/mtl/GrMtlResourceProvider.h index 5d1f213b154..20e6eb29aa1 100644 --- a/chromium/third_party/skia/src/gpu/mtl/GrMtlResourceProvider.h +++ b/chromium/third_party/skia/src/gpu/mtl/GrMtlResourceProvider.h @@ -41,6 +41,10 @@ public: // Destroy any cached resources. To be called before releasing the MtlDevice. void destroyResources(); +#if GR_TEST_UTILS + void resetShaderCacheForTesting() const { fPipelineStateCache->release(); } +#endif + private: #ifdef SK_DEBUG #define GR_PIPELINE_STATE_CACHE_STATS diff --git a/chromium/third_party/skia/src/gpu/mtl/GrMtlUtil.mm b/chromium/third_party/skia/src/gpu/mtl/GrMtlUtil.mm index c890e4b8991..df519b3037a 100644 --- a/chromium/third_party/skia/src/gpu/mtl/GrMtlUtil.mm +++ b/chromium/third_party/skia/src/gpu/mtl/GrMtlUtil.mm @@ -7,6 +7,7 @@ #include "src/gpu/mtl/GrMtlUtil.h" +#include "include/gpu/GrBackendSurface.h" #include "include/private/GrTypesPriv.h" #include "include/private/SkMutex.h" #include "src/gpu/GrSurface.h" @@ -269,6 +270,12 @@ uint32_t GrMtlFormatChannels(GrMTLPixelFormat mtlFormat) { } } +SkImage::CompressionType GrMtlBackendFormatToCompressionType(const GrBackendFormat& format) { + MTLPixelFormat mtlFormat = GrBackendFormatAsMTLPixelFormat(format); + return GrMtlFormatToCompressionType(mtlFormat); +} + + bool GrMtlFormatIsCompressed(MTLPixelFormat mtlFormat) { switch (mtlFormat) { #ifdef SK_BUILD_FOR_IOS diff --git a/chromium/third_party/skia/src/gpu/ops/GrAAConvexPathRenderer.cpp b/chromium/third_party/skia/src/gpu/ops/GrAAConvexPathRenderer.cpp index e427a4a7383..2dc3e1add28 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrAAConvexPathRenderer.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrAAConvexPathRenderer.cpp @@ -213,6 +213,7 @@ static void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) { data->fStage = DegenerateTestData::kNonDegenerate; } + break; case DegenerateTestData::kNonDegenerate: break; default: @@ -576,14 +577,11 @@ public: // Setup position this->writeOutputPosition(vertBuilder, gpArgs, qe.fInPosition.name()); - - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - qe.fInPosition.asShaderVar(), - qe.fLocalMatrix, - args.fFPCoordTransformHandler); + if (qe.fUsesLocalCoords) { + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, + qe.fInPosition.asShaderVar(), qe.fLocalMatrix, + &fLocalMatrixUniform); + } fragBuilder->codeAppendf("half edgeAlpha;"); @@ -610,18 +608,24 @@ public: const GrShaderCaps&, GrProcessorKeyBuilder* b) { const QuadEdgeEffect& qee = gp.cast<QuadEdgeEffect>(); - b->add32(SkToBool(qee.fUsesLocalCoords && qee.fLocalMatrix.hasPerspective())); + uint32_t key = (uint32_t) qee.fUsesLocalCoords; + key |= ComputeMatrixKey(qee.fLocalMatrix) << 1; + b->add32(key); } void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& gp, const CoordTransformRange& transformRange) override { const QuadEdgeEffect& qe = gp.cast<QuadEdgeEffect>(); - this->setTransformDataHelper(qe.fLocalMatrix, pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); + this->setTransform(pdman, fLocalMatrixUniform, qe.fLocalMatrix, &fLocalMatrix); } private: typedef GrGLSLGeometryProcessor INHERITED; + + SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix(); + UniformHandle fLocalMatrixUniform; }; void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override { @@ -915,7 +919,7 @@ bool GrAAConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { std::unique_ptr<GrDrawOp> op = AAConvexPathOp::Make(args.fContext, std::move(args.fPaint), *args.fViewMatrix, path, args.fUserStencilSettings); - args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); + args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op)); return true; } diff --git a/chromium/third_party/skia/src/gpu/ops/GrAAHairLinePathRenderer.cpp b/chromium/third_party/skia/src/gpu/ops/GrAAHairLinePathRenderer.cpp index 537d0f1c62d..b87d2f6a8d6 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrAAHairLinePathRenderer.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrAAHairLinePathRenderer.cpp @@ -15,12 +15,12 @@ #include "src/gpu/GrAuditTrail.h" #include "src/gpu/GrBuffer.h" #include "src/gpu/GrCaps.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrDefaultGeoProcFactory.h" #include "src/gpu/GrDrawOpTest.h" #include "src/gpu/GrOpFlushState.h" #include "src/gpu/GrProcessor.h" #include "src/gpu/GrProgramInfo.h" +#include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/GrResourceProvider.h" #include "src/gpu/GrStyle.h" #include "src/gpu/effects/GrBezierEffect.h" @@ -1011,7 +1011,6 @@ void AAHairlineOp::makeQuadProgramInfo(const GrCaps& caps, SkArenaAlloc* arena, GrGeometryProcessor* quadGP = GrQuadEffect::Make(arena, this->color(), *geometryProcessorViewM, - GrClipEdgeType::kHairlineAA, caps, *geometryProcessorLocalM, fHelper.usesLocalCoords(), @@ -1034,7 +1033,6 @@ void AAHairlineOp::makeConicProgramInfo(const GrCaps& caps, SkArenaAlloc* arena, GrGeometryProcessor* conicGP = GrConicEffect::Make(arena, this->color(), *geometryProcessorViewM, - GrClipEdgeType::kHairlineAA, caps, *geometryProcessorLocalM, fHelper.usesLocalCoords(), @@ -1117,7 +1115,7 @@ void AAHairlineOp::onPrePrepareDraws(GrRecordingContext* context, const GrCaps* caps = context->priv().caps(); // This is equivalent to a GrOpFlushState::detachAppliedClip - GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip(); + GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled(); // Conservatively predict which programs will be required fCharacterization = this->predictPrograms(caps); @@ -1272,14 +1270,13 @@ bool GrAAHairLinePathRenderer::onDrawPath(const DrawPathArgs& args) { "GrAAHairlinePathRenderer::onDrawPath"); SkASSERT(args.fRenderTargetContext->numSamples() <= 1); - SkIRect devClipBounds = args.fClip->getConservativeBounds(args.fRenderTargetContext->width(), - args.fRenderTargetContext->height()); SkPath path; args.fShape->asPath(&path); std::unique_ptr<GrDrawOp> op = AAHairlineOp::Make(args.fContext, std::move(args.fPaint), *args.fViewMatrix, path, - args.fShape->style(), devClipBounds, args.fUserStencilSettings); - args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); + args.fShape->style(), *args.fClipConservativeBounds, + args.fUserStencilSettings); + args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op)); return true; } diff --git a/chromium/third_party/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp b/chromium/third_party/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp index d6d644986d1..9c67fd8c3a0 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp @@ -405,7 +405,7 @@ bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) { std::unique_ptr<GrDrawOp> op = AAFlatteningConvexPathOp::Make( args.fContext, std::move(args.fPaint), *args.fViewMatrix, path, strokeWidth, stroke.getStyle(), join, miterLimit, args.fUserStencilSettings); - args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); + args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op)); return true; } diff --git a/chromium/third_party/skia/src/gpu/ops/GrAtlasTextOp.cpp b/chromium/third_party/skia/src/gpu/ops/GrAtlasTextOp.cpp index 80a34c66b1b..4e4e7f7e2e6 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrAtlasTextOp.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrAtlasTextOp.cpp @@ -16,6 +16,7 @@ #include "src/gpu/GrMemoryPool.h" #include "src/gpu/GrOpFlushState.h" #include "src/gpu/GrRecordingContextPriv.h" +#include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/GrResourceProvider.h" #include "src/gpu/effects/GrBitmapTextGeoProc.h" #include "src/gpu/effects/GrDistanceFieldGeoProc.h" @@ -23,6 +24,10 @@ #include "src/gpu/text/GrAtlasManager.h" #include "src/gpu/text/GrDistanceFieldAdjustTable.h" +#if GR_TEST_UTILS +#include "src/gpu/GrDrawOpTest.h" +#endif + /////////////////////////////////////////////////////////////////////////////////////////////////// GrAtlasTextOp::GrAtlasTextOp(MaskType maskType, @@ -43,7 +48,7 @@ GrAtlasTextOp::GrAtlasTextOp(MaskType maskType, , fDFGPFlags{DFGPFlags} , fGeoDataAllocSize{kMinGeometryAllocated} , fProcessors{std::move(paint)} - , fNumGlyphs{SkTo<int>(subrun->fGlyphs.size())} { + , fNumGlyphs{subrun->glyphCount()} { GrAtlasTextOp::Geometry& geometry = fGeoData[0]; // Unref handled in ~GrAtlasTextOp(). @@ -62,6 +67,11 @@ GrAtlasTextOp::GrAtlasTextOp(MaskType maskType, this->setBounds(bounds, HasAABloat::kNo, IsHairline::kNo); } +void GrAtlasTextOp::Geometry::fillVertexData(void *dst, int offset, int count) const { + fSubRunPtr->fillVertexData(dst, offset, count, fColor.toBytes_RGBA(), + fDrawMatrix, fDrawOrigin, fClipRect); +} + std::unique_ptr<GrAtlasTextOp> GrAtlasTextOp::MakeBitmap(GrRecordingContext* context, GrPaint&& paint, GrTextBlob::SubRun* subrun, @@ -193,113 +203,6 @@ GrProcessorSet::Analysis GrAtlasTextOp::finalize( return analysis; } -static void clip_quads(const SkIRect& clipRect, char* currVertex, const char* blobVertices, - size_t vertexStride, int glyphCount) { - for (int i = 0; i < glyphCount; ++i) { - const SkPoint* blobPositionLT = reinterpret_cast<const SkPoint*>(blobVertices); - const SkPoint* blobPositionRB = - reinterpret_cast<const SkPoint*>(blobVertices + 3 * vertexStride); - - // positions for bitmap glyphs are pixel boundary aligned - SkIRect positionRect = SkIRect::MakeLTRB(SkScalarRoundToInt(blobPositionLT->fX), - SkScalarRoundToInt(blobPositionLT->fY), - SkScalarRoundToInt(blobPositionRB->fX), - SkScalarRoundToInt(blobPositionRB->fY)); - if (clipRect.contains(positionRect)) { - memcpy(currVertex, blobVertices, 4 * vertexStride); - currVertex += 4 * vertexStride; - } else { - // Pull out some more data that we'll need. - // In the LCD case the color will be garbage, but we'll overwrite it with the texcoords - // and it avoids a lot of conditionals. - auto color = *reinterpret_cast<const SkColor*>(blobVertices + sizeof(SkPoint)); - size_t coordOffset = vertexStride - 2*sizeof(uint16_t); - auto* blobCoordsLT = reinterpret_cast<const uint16_t*>(blobVertices + coordOffset); - auto* blobCoordsRB = reinterpret_cast<const uint16_t*>(blobVertices + 3 * vertexStride + - coordOffset); - // Pull out the texel coordinates and texture index bits - uint16_t coordsRectL = blobCoordsLT[0]; - uint16_t coordsRectT = blobCoordsLT[1]; - uint16_t coordsRectR = blobCoordsRB[0]; - uint16_t coordsRectB = blobCoordsRB[1]; - int index0, index1; - std::tie(coordsRectL, coordsRectT, index0) = - GrDrawOpAtlas::UnpackIndexFromTexCoords(coordsRectL, coordsRectT); - std::tie(coordsRectR, coordsRectB, index1) = - GrDrawOpAtlas::UnpackIndexFromTexCoords(coordsRectR, coordsRectB); - SkASSERT(index0 == index1); - - int positionRectWidth = positionRect.width(); - int positionRectHeight = positionRect.height(); - SkASSERT(positionRectWidth == (coordsRectR - coordsRectL)); - SkASSERT(positionRectHeight == (coordsRectB - coordsRectT)); - - // Clip position and texCoords to the clipRect - unsigned int delta; - delta = std::min(std::max(clipRect.fLeft - positionRect.fLeft, 0), positionRectWidth); - coordsRectL += delta; - positionRect.fLeft += delta; - - delta = std::min(std::max(clipRect.fTop - positionRect.fTop, 0), positionRectHeight); - coordsRectT += delta; - positionRect.fTop += delta; - - delta = std::min(std::max(positionRect.fRight - clipRect.fRight, 0), positionRectWidth); - coordsRectR -= delta; - positionRect.fRight -= delta; - - delta = std::min(std::max(positionRect.fBottom - clipRect.fBottom, 0), positionRectHeight); - coordsRectB -= delta; - positionRect.fBottom -= delta; - - // Repack texel coordinates and index - std::tie(coordsRectL, coordsRectT) = - GrDrawOpAtlas::PackIndexInTexCoords(coordsRectL, coordsRectT, index0); - std::tie(coordsRectR, coordsRectB) = - GrDrawOpAtlas::PackIndexInTexCoords(coordsRectR, coordsRectB, index1); - - // Set new positions and coords - SkPoint* currPosition = reinterpret_cast<SkPoint*>(currVertex); - currPosition->fX = positionRect.fLeft; - currPosition->fY = positionRect.fTop; - *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color; - uint16_t* currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset); - currCoords[0] = coordsRectL; - currCoords[1] = coordsRectT; - currVertex += vertexStride; - - currPosition = reinterpret_cast<SkPoint*>(currVertex); - currPosition->fX = positionRect.fLeft; - currPosition->fY = positionRect.fBottom; - *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color; - currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset); - currCoords[0] = coordsRectL; - currCoords[1] = coordsRectB; - currVertex += vertexStride; - - currPosition = reinterpret_cast<SkPoint*>(currVertex); - currPosition->fX = positionRect.fRight; - currPosition->fY = positionRect.fTop; - *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color; - currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset); - currCoords[0] = coordsRectR; - currCoords[1] = coordsRectT; - currVertex += vertexStride; - - currPosition = reinterpret_cast<SkPoint*>(currVertex); - currPosition->fX = positionRect.fRight; - currPosition->fY = positionRect.fBottom; - *(reinterpret_cast<SkColor*>(currVertex + sizeof(SkPoint))) = color; - currCoords = reinterpret_cast<uint16_t*>(currVertex + coordOffset); - currCoords[0] = coordsRectR; - currCoords[1] = coordsRectB; - currVertex += vertexStride; - } - - blobVertices += 4 * vertexStride; - } -} - void GrAtlasTextOp::onPrepareDraws(Target* target) { auto resourceProvider = target->resourceProvider(); @@ -381,8 +284,6 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { SkASSERT((int)subRun->vertexStride() == vertexStride); subRun->prepareGrGlyphs(target->strikeCache()); - subRun->updateVerticesColorIfNeeded(args.fColor.toBytes_RGBA()); - subRun->translateVerticesIfNeeded(args.fDrawMatrix, args.fDrawOrigin); // TODO4F: Preserve float colors GrTextBlob::VertexRegenerator regenerator(resourceProvider, subRun, @@ -390,7 +291,7 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { // Where the subRun begins and ends relative to totalGlyphsRegened. int subRunBegin = totalGlyphsRegened; - int subRunEnd = subRunBegin + subRun->fGlyphs.count(); + int subRunEnd = subRunBegin + subRun->glyphCount(); // Draw all the glyphs in the subRun. while (totalGlyphsRegened < subRunEnd) { @@ -409,39 +310,10 @@ void GrAtlasTextOp::onPrepareDraws(Target* target) { // Update all the vertices for glyphsRegenerate glyphs. if (glyphsRegenerated > 0) { int quadBufferIndex = totalGlyphsRegened - quadBufferBegin; - int subRunIndex = totalGlyphsRegened - subRunBegin; auto regeneratedQuadBuffer = SkTAddOffset<char>(vertices, subRun->quadOffset(quadBufferIndex)); - if (args.fClipRect.isEmpty()) { - memcpy(regeneratedQuadBuffer, - subRun->quadStart(subRunIndex), - glyphsRegenerated * quadSize); - } else { - SkASSERT(!vmPerspective); - clip_quads(args.fClipRect, - regeneratedQuadBuffer, - subRun->quadStart(subRunIndex), - vertexStride, - glyphsRegenerated); - } - if (fNeedsGlyphTransform && !args.fDrawMatrix.isIdentity()) { - // We always do the distance field view matrix transformation after copying - // rather than during blob vertex generation time in the blob as handling - // successive arbitrary transformations would be complicated and accumulate - // error. - if (args.fDrawMatrix.hasPerspective()) { - auto* pos = reinterpret_cast<SkPoint3*>(regeneratedQuadBuffer); - SkMatrixPriv::MapHomogeneousPointsWithStride( - args.fDrawMatrix, pos, - vertexStride, pos, - vertexStride, - glyphsRegenerated * kVerticesPerGlyph); - } else { - auto* pos = reinterpret_cast<SkPoint*>(regeneratedQuadBuffer); - SkMatrixPriv::MapPointsWithStride(args.fDrawMatrix, pos, vertexStride, - glyphsRegenerated * kVerticesPerGlyph); - } - } + int subRunIndex = totalGlyphsRegened - subRunBegin; + args.fillVertexData(regeneratedQuadBuffer, subRunIndex, glyphsRegenerated); } totalGlyphsRegened += glyphsRegenerated; @@ -619,7 +491,6 @@ GrOp::CombineResult GrAtlasTextOp::onCombineIfPossible(GrOp* t, GrRecordingConte static const int kDistanceAdjustLumShift = 5; // TODO trying to figure out why lcd is so whack -// (see comments in GrTextContext::ComputeCanonicalColor) GrGeometryProcessor* GrAtlasTextOp::setupDfProcessor(SkArenaAlloc* arena, const GrShaderCaps& caps, const GrSurfaceProxyView* views, @@ -672,3 +543,78 @@ GrGeometryProcessor* GrAtlasTextOp::setupDfProcessor(SkArenaAlloc* arena, } } +#if GR_TEST_UTILS +std::unique_ptr<GrDrawOp> GrAtlasTextOp::CreateOpTestingOnly(GrRenderTargetContext* rtc, + const SkPaint& skPaint, + const SkFont& font, + const SkMatrixProvider& mtxProvider, + const char* text, + int x, + int y) { + static SkSurfaceProps surfaceProps(SkSurfaceProps::kLegacyFontHost_InitType); + + size_t textLen = (int)strlen(text); + + const SkMatrix& drawMatrix(mtxProvider.localToDevice()); + + auto drawOrigin = SkPoint::Make(x, y); + SkGlyphRunBuilder builder; + builder.drawTextUTF8(skPaint, font, text, textLen, drawOrigin); + + auto glyphRunList = builder.useGlyphRunList(); + + const GrRecordingContextPriv& contextPriv = rtc->fContext->priv(); + GrSDFTOptions SDFOptions = rtc->fContext->priv().SDFTOptions(); + + if (glyphRunList.empty()) { + return nullptr; + } + sk_sp<GrTextBlob> blob = GrTextBlob::Make(glyphRunList, drawMatrix); + SkGlyphRunListPainter* painter = &rtc->fGlyphPainter; + painter->processGlyphRunList( + glyphRunList, drawMatrix, surfaceProps, + contextPriv.caps()->shaderCaps()->supportsDistanceFieldText(), + SDFOptions, blob.get()); + + return blob->firstSubRun()->makeOp(mtxProvider, + drawOrigin, + SkIRect::MakeEmpty(), + skPaint, + surfaceProps, + rtc->textTarget()); +} + +GR_DRAW_OP_TEST_DEFINE(GrAtlasTextOp) { + // Setup dummy SkPaint / GrPaint / GrRenderTargetContext + auto rtc = GrRenderTargetContext::Make( + context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox, {1024, 1024}); + + SkSimpleMatrixProvider matrixProvider(GrTest::TestMatrixInvertible(random)); + + SkPaint skPaint; + skPaint.setColor(random->nextU()); + + SkFont font; + if (random->nextBool()) { + font.setEdging(SkFont::Edging::kSubpixelAntiAlias); + } else { + font.setEdging(random->nextBool() ? SkFont::Edging::kAntiAlias : SkFont::Edging::kAlias); + } + font.setSubpixel(random->nextBool()); + + const char* text = "The quick brown fox jumps over the lazy dog."; + + // create some random x/y offsets, including negative offsets + static const int kMaxTrans = 1024; + int xPos = (random->nextU() % 2) * 2 - 1; + int yPos = (random->nextU() % 2) * 2 - 1; + int xInt = (random->nextU() % kMaxTrans) * xPos; + int yInt = (random->nextU() % kMaxTrans) * yPos; + + return GrAtlasTextOp::CreateOpTestingOnly( + rtc.get(), skPaint, font, matrixProvider, text, xInt, yInt); +} + +#endif + + diff --git a/chromium/third_party/skia/src/gpu/ops/GrAtlasTextOp.h b/chromium/third_party/skia/src/gpu/ops/GrAtlasTextOp.h index 451de49aec4..e4e9af9b20a 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrAtlasTextOp.h +++ b/chromium/third_party/skia/src/gpu/ops/GrAtlasTextOp.h @@ -12,7 +12,6 @@ #include "src/gpu/text/GrTextBlob.h" class GrRecordingContext; -class SkAtlasTextTarget; class GrAtlasTextOp final : public GrMeshDrawOp { public: @@ -34,6 +33,8 @@ public: SkPoint fDrawOrigin; GrTextBlob::SubRun* fSubRunPtr; SkPMColor4f fColor; + + void fillVertexData(void* dst, int offset, int count) const; }; static std::unique_ptr<GrAtlasTextOp> MakeBitmap(GrRecordingContext* context, @@ -81,8 +82,15 @@ public: MaskType maskType() const { return fMaskType; } - void finalizeForTextTarget(uint32_t color, const GrCaps&); - void executeForTextTarget(SkAtlasTextTarget*); +#if GR_TEST_UTILS + static std::unique_ptr<GrDrawOp> CreateOpTestingOnly(GrRenderTargetContext* rtc, + const SkPaint& skPaint, + const SkFont& font, + const SkMatrixProvider& mtxProvider, + const char* text, + int x, + int y); +#endif private: friend class GrOpMemoryPool; // for ctor diff --git a/chromium/third_party/skia/src/gpu/ops/GrClearOp.cpp b/chromium/third_party/skia/src/gpu/ops/GrClearOp.cpp index 28529f47a0e..7f82206654c 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrClearOp.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrClearOp.cpp @@ -14,52 +14,74 @@ #include "src/gpu/GrProxyProvider.h" #include "src/gpu/GrRecordingContextPriv.h" -std::unique_ptr<GrClearOp> GrClearOp::Make(GrRecordingContext* context, - const GrFixedClip& clip, - const SkPMColor4f& color, - GrSurfaceProxy* dstProxy) { - const SkIRect rect = SkIRect::MakeSize(dstProxy->dimensions()); - if (clip.scissorEnabled() && !SkIRect::Intersects(clip.scissorRect(), rect)) { - return nullptr; - } +static bool contains_scissor(const GrScissorState& a, const GrScissorState& b) { + return !a.enabled() || (b.enabled() && a.rect().contains(b.rect())); +} +std::unique_ptr<GrClearOp> GrClearOp::MakeColor(GrRecordingContext* context, + const GrScissorState& scissor, + const SkPMColor4f& color) { GrOpMemoryPool* pool = context->priv().opMemoryPool(); - - return pool->allocate<GrClearOp>(clip, color, dstProxy); + return pool->allocate<GrClearOp>(Buffer::kColor, scissor, color, false); } -std::unique_ptr<GrClearOp> GrClearOp::Make(GrRecordingContext* context, - const SkIRect& rect, - const SkPMColor4f& color, - bool fullScreen) { - SkASSERT(fullScreen || !rect.isEmpty()); - +std::unique_ptr<GrClearOp> GrClearOp::MakeStencilClip(GrRecordingContext* context, + const GrScissorState& scissor, + bool insideMask) { GrOpMemoryPool* pool = context->priv().opMemoryPool(); - - return pool->allocate<GrClearOp>(rect, color, fullScreen); + return pool->allocate<GrClearOp>(Buffer::kStencilClip, scissor, SkPMColor4f(), insideMask); } -GrClearOp::GrClearOp(const GrFixedClip& clip, const SkPMColor4f& color, GrSurfaceProxy* proxy) +GrClearOp::GrClearOp(Buffer buffer, const GrScissorState& scissor, + const SkPMColor4f& color, bool insideMask) : INHERITED(ClassID()) - , fClip(clip) - , fColor(color) { - const SkIRect rtRect = SkIRect::MakeSize(proxy->dimensions()); - if (fClip.scissorEnabled()) { - // Don't let scissors extend outside the RT. This may improve op combining. - if (!fClip.intersect(rtRect)) { - SkASSERT(0); // should be caught upstream - fClip = GrFixedClip(SkIRect::MakeEmpty()); - } + , fScissor(scissor) + , fColor(color) + , fStencilInsideMask(insideMask) + , fBuffer(buffer) { + this->setBounds(SkRect::Make(scissor.rect()), HasAABloat::kNo, IsHairline::kNo); +} - if (proxy->isFunctionallyExact() && fClip.scissorRect() == rtRect) { - fClip.disableScissor(); +GrOp::CombineResult GrClearOp::onCombineIfPossible(GrOp* t, GrRecordingContext::Arenas*, + const GrCaps& caps) { + GrClearOp* other = t->cast<GrClearOp>(); + + if (other->fBuffer == fBuffer) { + // This could be much more complicated. Currently we look at cases where the new clear + // contains the old clear, or when the new clear is a subset of the old clear and they clear + // to the same value (color or stencil mask depending on target). + if (contains_scissor(other->fScissor, fScissor)) { + fScissor = other->fScissor; + fColor = other->fColor; + fStencilInsideMask = other->fStencilInsideMask; + return CombineResult::kMerged; + } else if (other->fColor == fColor && other->fStencilInsideMask == fStencilInsideMask && + contains_scissor(fScissor, other->fScissor)) { + return CombineResult::kMerged; + } + } else if (other->fScissor == fScissor) { + // When the scissors are the exact same but the buffers are different, we can combine and + // clear both stencil and clear together in onExecute(). + if (other->fBuffer & Buffer::kColor) { + SkASSERT((fBuffer & Buffer::kStencilClip) && !(fBuffer & Buffer::kColor)); + fColor = other->fColor; + } + if (other->fBuffer & Buffer::kStencilClip) { + SkASSERT(!(fBuffer & Buffer::kStencilClip) && (fBuffer & Buffer::kColor)); + fStencilInsideMask = other->fStencilInsideMask; } + fBuffer = Buffer::kBoth; } - this->setBounds(SkRect::Make(fClip.scissorEnabled() ? fClip.scissorRect() : rtRect), - HasAABloat::kNo, IsHairline::kNo); + return CombineResult::kCannotCombine; } void GrClearOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) { SkASSERT(state->opsRenderPass()); - state->opsRenderPass()->clear(fClip, fColor); + if (fBuffer & Buffer::kColor) { + state->opsRenderPass()->clear(fScissor, fColor); + } + + if (fBuffer & Buffer::kStencilClip) { + state->opsRenderPass()->clearStencilClip(fScissor, fStencilInsideMask); + } } diff --git a/chromium/third_party/skia/src/gpu/ops/GrClearOp.h b/chromium/third_party/skia/src/gpu/ops/GrClearOp.h index fbac02f9a74..5eaff4bb19c 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrClearOp.h +++ b/chromium/third_party/skia/src/gpu/ops/GrClearOp.h @@ -8,7 +8,8 @@ #ifndef GrClearOp_DEFINED #define GrClearOp_DEFINED -#include "src/gpu/GrFixedClip.h" +#include "include/gpu/GrTypes.h" +#include "src/gpu/GrScissorState.h" #include "src/gpu/ops/GrOp.h" class GrOpFlushState; @@ -18,15 +19,14 @@ class GrClearOp final : public GrOp { public: DEFINE_OP_CLASS_ID - static std::unique_ptr<GrClearOp> Make(GrRecordingContext* context, - const GrFixedClip& clip, - const SkPMColor4f& color, - GrSurfaceProxy* dstProxy); + // A fullscreen or scissored clear, depending on the clip and proxy dimensions + static std::unique_ptr<GrClearOp> MakeColor(GrRecordingContext* context, + const GrScissorState& scissor, + const SkPMColor4f& color); - static std::unique_ptr<GrClearOp> Make(GrRecordingContext* context, - const SkIRect& rect, - const SkPMColor4f& color, - bool fullScreen); + static std::unique_ptr<GrClearOp> MakeStencilClip(GrRecordingContext* context, + const GrScissorState& scissor, + bool insideMask); const char* name() const override { return "Clear"; } @@ -35,8 +35,8 @@ public: SkString string; string.append(INHERITED::dumpInfo()); string.appendf("Scissor [ "); - if (fClip.scissorEnabled()) { - const SkIRect& r = fClip.scissorRect(); + if (fScissor.enabled()) { + const SkIRect& r = fScissor.rect(); string.appendf("L: %d, T: %d, R: %d, B: %d", r.fLeft, r.fTop, r.fRight, r.fBottom); } else { string.append("disabled"); @@ -46,64 +46,37 @@ public: } #endif - const SkPMColor4f& color() const { return fColor; } - void setColor(const SkPMColor4f& color) { fColor = color; } - private: friend class GrOpMemoryPool; // for ctors - GrClearOp(const GrFixedClip& clip, const SkPMColor4f& color, GrSurfaceProxy* proxy); + enum class Buffer { + kColor = 0b01, + kStencilClip = 0b10, - GrClearOp(const SkIRect& rect, const SkPMColor4f& color, bool fullScreen) - : INHERITED(ClassID()) - , fClip(GrFixedClip(rect)) - , fColor(color) { + kBoth = 0b11, + }; + GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(Buffer); - if (fullScreen) { - fClip.disableScissor(); - } - this->setBounds(SkRect::Make(rect), HasAABloat::kNo, IsHairline::kNo); - } + GrClearOp(Buffer buffer, const GrScissorState& scissor, const SkPMColor4f& color, bool stencil); CombineResult onCombineIfPossible(GrOp* t, GrRecordingContext::Arenas*, - const GrCaps& caps) override { - // This could be much more complicated. Currently we look at cases where the new clear - // contains the old clear, or when the new clear is a subset of the old clear and is the - // same color. - GrClearOp* cb = t->cast<GrClearOp>(); - if (fClip.windowRectsState() != cb->fClip.windowRectsState()) { - return CombineResult::kCannotCombine; - } - if (cb->contains(this)) { - fClip = cb->fClip; - fColor = cb->fColor; - return CombineResult::kMerged; - } else if (cb->fColor == fColor && this->contains(cb)) { - return CombineResult::kMerged; - } - return CombineResult::kCannotCombine; - } - - bool contains(const GrClearOp* that) const { - // The constructor ensures that scissor gets disabled on any clip that fills the entire RT. - return !fClip.scissorEnabled() || - (that->fClip.scissorEnabled() && - fClip.scissorRect().contains(that->fClip.scissorRect())); - } + const GrCaps& caps) override; - void onPrePrepare(GrRecordingContext*, - const GrSurfaceProxyView* writeView, - GrAppliedClip*, + void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView* writeView, GrAppliedClip*, const GrXferProcessor::DstProxyView&) override {} void onPrepare(GrOpFlushState*) override {} void onExecute(GrOpFlushState* state, const SkRect& chainBounds) override; - GrFixedClip fClip; - SkPMColor4f fColor; + GrScissorState fScissor; + SkPMColor4f fColor; + bool fStencilInsideMask; + Buffer fBuffer; typedef GrOp INHERITED; }; +GR_MAKE_BITFIELD_CLASS_OPS(GrClearOp::Buffer) + #endif diff --git a/chromium/third_party/skia/src/gpu/ops/GrClearStencilClipOp.cpp b/chromium/third_party/skia/src/gpu/ops/GrClearStencilClipOp.cpp deleted file mode 100644 index 7ca4063b967..00000000000 --- a/chromium/third_party/skia/src/gpu/ops/GrClearStencilClipOp.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2018 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "src/gpu/ops/GrClearStencilClipOp.h" - -#include "include/private/GrRecordingContext.h" -#include "src/gpu/GrMemoryPool.h" -#include "src/gpu/GrOpFlushState.h" -#include "src/gpu/GrOpsRenderPass.h" -#include "src/gpu/GrRecordingContextPriv.h" - -std::unique_ptr<GrOp> GrClearStencilClipOp::Make(GrRecordingContext* context, - const GrFixedClip& clip, - bool insideStencilMask, - GrRenderTargetProxy* proxy) { - GrOpMemoryPool* pool = context->priv().opMemoryPool(); - - return pool->allocate<GrClearStencilClipOp>(clip, insideStencilMask, proxy); -} - -void GrClearStencilClipOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) { - SkASSERT(state->opsRenderPass()); - state->opsRenderPass()->clearStencilClip(fClip, fInsideStencilMask); -} diff --git a/chromium/third_party/skia/src/gpu/ops/GrClearStencilClipOp.h b/chromium/third_party/skia/src/gpu/ops/GrClearStencilClipOp.h deleted file mode 100644 index 68f825a7e40..00000000000 --- a/chromium/third_party/skia/src/gpu/ops/GrClearStencilClipOp.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2016 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrClearStencilClipOp_DEFINED -#define GrClearStencilClipOp_DEFINED - -#include "src/gpu/GrFixedClip.h" -#include "src/gpu/GrRenderTargetProxy.h" -#include "src/gpu/ops/GrOp.h" - -class GrOpFlushState; -class GrRecordingContext; - -class GrClearStencilClipOp final : public GrOp { -public: - DEFINE_OP_CLASS_ID - - static std::unique_ptr<GrOp> Make(GrRecordingContext* context, - const GrFixedClip& clip, - bool insideStencilMask, - GrRenderTargetProxy* proxy); - - const char* name() const override { return "ClearStencilClip"; } - -#ifdef SK_DEBUG - SkString dumpInfo() const override { - SkString string("Scissor ["); - if (fClip.scissorEnabled()) { - const SkIRect& r = fClip.scissorRect(); - string.appendf("L: %d, T: %d, R: %d, B: %d", r.fLeft, r.fTop, r.fRight, r.fBottom); - } else { - string.append("disabled"); - } - string.appendf("], insideMask: %s\n", fInsideStencilMask ? "true" : "false"); - string.append(INHERITED::dumpInfo()); - return string; - } -#endif - -private: - friend class GrOpMemoryPool; // for ctor - - GrClearStencilClipOp(const GrFixedClip& clip, bool insideStencilMask, - GrRenderTargetProxy* proxy) - : INHERITED(ClassID()) - , fClip(clip) - , fInsideStencilMask(insideStencilMask) { - const SkRect& bounds = - fClip.scissorEnabled() ? SkRect::Make(fClip.scissorRect()) : proxy->getBoundsRect(); - this->setBounds(bounds, HasAABloat::kNo, IsHairline::kNo); - } - - void onPrePrepare(GrRecordingContext*, - const GrSurfaceProxyView* writeView, - GrAppliedClip*, - const GrXferProcessor::DstProxyView&) override {} - - void onPrepare(GrOpFlushState*) override {} - - void onExecute(GrOpFlushState*, const SkRect& chainBounds) override; - - const GrFixedClip fClip; - const bool fInsideStencilMask; - - typedef GrOp INHERITED; -}; - -#endif diff --git a/chromium/third_party/skia/src/gpu/ops/GrDashLinePathRenderer.cpp b/chromium/third_party/skia/src/gpu/ops/GrDashLinePathRenderer.cpp index 96fc06cde17..e5cf9e4038b 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrDashLinePathRenderer.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrDashLinePathRenderer.cpp @@ -53,6 +53,6 @@ bool GrDashLinePathRenderer::onDrawPath(const DrawPathArgs& args) { if (!op) { return false; } - args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); + args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op)); return true; } diff --git a/chromium/third_party/skia/src/gpu/ops/GrDashOp.cpp b/chromium/third_party/skia/src/gpu/ops/GrDashOp.cpp index 7e1b63fdc82..5ee04a42a2a 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrDashOp.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrDashOp.cpp @@ -167,9 +167,9 @@ static void setup_dashed_rect(const SkRect& rect, // 'dashRect' gets interpolated over the rendered 'rect'. For y we want the perpendicular signed // distance from the stroke center line in device space. 'perpScale' is the scale factor applied // to the y dimension of 'rect' isolated from 'matrix'. - SkScalar halfDevRectHeight = rect.height()*perpScale/2.f; + SkScalar halfDevRectHeight = rect.height() * perpScale / 2.f; SkRect dashRect = { offset - bloatX, -halfDevRectHeight, - offset + len + bloatX, halfDevRectHeight}; + offset + len + bloatX, halfDevRectHeight }; if (kRound_DashCap == cap) { SkScalar radius = SkScalarHalf(strokeWidth) - 0.5f; @@ -311,9 +311,8 @@ private: SkMatrix& combinedMatrix = fLines[0].fSrcRotInv; combinedMatrix.postConcat(geometry.fViewMatrix); - IsHairline zeroArea = geometry.fSrcStrokeWidth ? IsHairline::kNo - : IsHairline::kYes; - HasAABloat aaBloat = (aaMode == AAMode::kNone) ? HasAABloat ::kNo : HasAABloat::kYes; + IsHairline zeroArea = geometry.fSrcStrokeWidth ? IsHairline::kNo : IsHairline::kYes; + HasAABloat aaBloat = (aaMode == AAMode::kNone) ? HasAABloat::kNo : HasAABloat::kYes; this->setTransformedBounds(bounds, combinedMatrix, aaBloat, zeroArea); } @@ -418,18 +417,15 @@ private: bool hasCap = SkPaint::kButt_Cap != cap; - // We always want to at least stroke out half a pixel on each side in device space - // so 0.5f / perpScale gives us this min in src space - SkScalar halfSrcStroke = - std::max(args.fSrcStrokeWidth * 0.5f, 0.5f / args.fPerpendicularScale); - - SkScalar strokeAdj; - if (!hasCap) { - strokeAdj = 0.f; - } else { - strokeAdj = halfSrcStroke; + SkScalar halfSrcStroke = args.fSrcStrokeWidth * 0.5f; + if (halfSrcStroke == 0.0f || this->aaMode() != AAMode::kCoverageWithMSAA) { + // In the non-MSAA case, we always want to at least stroke out half a pixel on each + // side in device space. 0.5f / fPerpendicularScale gives us this min in src space. + // This is also necessary when the stroke width is zero, to allow hairlines to draw. + halfSrcStroke = std::max(halfSrcStroke, 0.5f / args.fPerpendicularScale); } + SkScalar strokeAdj = hasCap ? halfSrcStroke : 0.0f; SkScalar startAdj = 0; bool lineDone = false; @@ -536,14 +532,20 @@ private: } SkScalar startOffset = devIntervals[1] * 0.5f + devPhase; - // For EdgeAA, we bloat in X & Y for both square and round caps. - // For MSAA, we don't bloat at all for square caps, and bloat in Y only for round caps. - SkScalar devBloatX = this->aaMode() == AAMode::kCoverage ? 0.5f : 0.0f; - SkScalar devBloatY; - if (SkPaint::kRound_Cap == cap && this->aaMode() == AAMode::kCoverageWithMSAA) { - devBloatY = 0.5f; - } else { - devBloatY = devBloatX; + SkScalar devBloatX = 0.0f; + SkScalar devBloatY = 0.0f; + switch (this->aaMode()) { + case AAMode::kNone: + break; + case AAMode::kCoverage: + // For EdgeAA, we bloat in X & Y for both square and round caps. + devBloatX = 0.5f; + devBloatY = 0.5f; + break; + case AAMode::kCoverageWithMSAA: + // For MSAA, we only bloat in Y for round caps. + devBloatY = (cap == SkPaint::kRound_Cap) ? 0.5f : 0.0f; + break; } SkScalar bloatX = devBloatX / args.fParallelScale; @@ -782,7 +784,7 @@ std::unique_ptr<GrDrawOp> GrDashOp::MakeDashLineOp(GrRecordingContext* context, SkScalar strokeWidth = lineData.fSrcStrokeWidth * lineData.fPerpendicularScale; if (SkPaint::kSquare_Cap == cap && 0 != lineData.fSrcStrokeWidth) { - // add cap to on interveal and remove from off interval + // add cap to on interval and remove from off interval offInterval -= strokeWidth; } @@ -874,14 +876,19 @@ public: private: UniformHandle fParamUniform; UniformHandle fColorUniform; + UniformHandle fLocalMatrixUniform; + + SkMatrix fLocalMatrix; SkPMColor4f fColor; SkScalar fPrevRadius; SkScalar fPrevCenterX; SkScalar fPrevIntervalLength; + typedef GrGLSLGeometryProcessor INHERITED; }; GLDashingCircleEffect::GLDashingCircleEffect() { + fLocalMatrix = SkMatrix::InvalidMatrix(); fColor = SK_PMColor4fILLEGAL; fPrevRadius = SK_ScalarMin; fPrevCenterX = SK_ScalarMin; @@ -913,14 +920,10 @@ void GLDashingCircleEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { // Setup position this->writeOutputPosition(vertBuilder, gpArgs, dce.fInPosition.name()); - - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - dce.fInPosition.asShaderVar(), - dce.localMatrix(), - args.fFPCoordTransformHandler); + if (dce.usesLocalCoords()) { + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, dce.fInPosition.asShaderVar(), + dce.localMatrix(), &fLocalMatrixUniform); + } // transforms all points so that we can compare them to our test circle fragBuilder->codeAppendf("half xShifted = half(%s.x - floor(%s.x / %s.z) * %s.z);", @@ -949,7 +952,8 @@ void GLDashingCircleEffect::setData(const GrGLSLProgramDataManager& pdman, pdman.set4fv(fColorUniform, 1, dce.color().vec()); fColor = dce.color(); } - this->setTransformDataHelper(dce.localMatrix(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); + this->setTransform(pdman, fLocalMatrixUniform, dce.localMatrix(), &fLocalMatrix); } void GLDashingCircleEffect::GenKey(const GrGeometryProcessor& gp, @@ -957,8 +961,9 @@ void GLDashingCircleEffect::GenKey(const GrGeometryProcessor& gp, GrProcessorKeyBuilder* b) { const DashingCircleEffect& dce = gp.cast<DashingCircleEffect>(); uint32_t key = 0; - key |= dce.usesLocalCoords() && dce.localMatrix().hasPerspective() ? 0x1 : 0x0; + key |= dce.usesLocalCoords() ? 0x1 : 0x0; key |= static_cast<uint32_t>(dce.aaMode()) << 1; + key |= ComputeMatrixKey(dce.localMatrix()) << 3; b->add32(key); } @@ -1084,6 +1089,10 @@ public: private: SkPMColor4f fColor; UniformHandle fColorUniform; + + SkMatrix fLocalMatrix; + UniformHandle fLocalMatrixUniform; + typedef GrGLSLGeometryProcessor INHERITED; }; @@ -1116,14 +1125,10 @@ void GLDashingLineEffect::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) { // Setup position this->writeOutputPosition(vertBuilder, gpArgs, de.fInPosition.name()); - - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - de.fInPosition.asShaderVar(), - de.localMatrix(), - args.fFPCoordTransformHandler); + if (de.usesLocalCoords()) { + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, de.fInPosition.asShaderVar(), + de.localMatrix(), &fLocalMatrixUniform); + } // transforms all points so that we can compare them to our test rect fragBuilder->codeAppendf("half xShifted = half(%s.x - floor(%s.x / %s.z) * %s.z);", @@ -1176,7 +1181,8 @@ void GLDashingLineEffect::setData(const GrGLSLProgramDataManager& pdman, pdman.set4fv(fColorUniform, 1, de.color().vec()); fColor = de.color(); } - this->setTransformDataHelper(de.localMatrix(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); + this->setTransform(pdman, fLocalMatrixUniform, de.localMatrix(), &fLocalMatrix); } void GLDashingLineEffect::GenKey(const GrGeometryProcessor& gp, @@ -1184,8 +1190,9 @@ void GLDashingLineEffect::GenKey(const GrGeometryProcessor& gp, GrProcessorKeyBuilder* b) { const DashingLineEffect& de = gp.cast<DashingLineEffect>(); uint32_t key = 0; - key |= de.usesLocalCoords() && de.localMatrix().hasPerspective() ? 0x1 : 0x0; - key |= static_cast<int>(de.aaMode()) << 8; + key |= de.usesLocalCoords() ? 0x1 : 0x0; + key |= static_cast<int>(de.aaMode()) << 1; + key |= ComputeMatrixKey(de.localMatrix()) << 3; b->add32(key); } diff --git a/chromium/third_party/skia/src/gpu/ops/GrDefaultPathRenderer.cpp b/chromium/third_party/skia/src/gpu/ops/GrDefaultPathRenderer.cpp index 7f4f634b33e..88175db9d20 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrDefaultPathRenderer.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrDefaultPathRenderer.cpp @@ -14,9 +14,9 @@ #include "src/core/SkTraceEvent.h" #include "src/gpu/GrAuditTrail.h" #include "src/gpu/GrCaps.h" +#include "src/gpu/GrClip.h" #include "src/gpu/GrDefaultGeoProcFactory.h" #include "src/gpu/GrDrawOpTest.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrOpFlushState.h" #include "src/gpu/GrProgramInfo.h" #include "src/gpu/GrRenderTargetContextPriv.h" @@ -537,7 +537,7 @@ bool GrDefaultPathRenderer::internalDrawPath(GrRenderTargetContext* renderTarget GrPaint&& paint, GrAAType aaType, const GrUserStencilSettings& userStencilSettings, - const GrClip& clip, + const GrClip* clip, const SkMatrix& viewMatrix, const GrStyledShape& shape, bool stencilOnly) { @@ -583,7 +583,7 @@ bool GrDefaultPathRenderer::internalDrawPath(GrRenderTargetContext* renderTarget switch (path.getFillType()) { case SkPathFillType::kInverseEvenOdd: reverse = true; - // fallthrough + [[fallthrough]]; case SkPathFillType::kEvenOdd: passes[0] = &gEOStencilPass; if (stencilOnly) { @@ -602,7 +602,7 @@ bool GrDefaultPathRenderer::internalDrawPath(GrRenderTargetContext* renderTarget case SkPathFillType::kInverseWinding: reverse = true; - // fallthrough + [[fallthrough]]; case SkPathFillType::kWinding: passes[0] = &gWindStencilPass; passCount = 2; @@ -705,7 +705,7 @@ bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) { return this->internalDrawPath( args.fRenderTargetContext, std::move(args.fPaint), aaType, *args.fUserStencilSettings, - *args.fClip, *args.fViewMatrix, *args.fShape, false); + args.fClip, *args.fViewMatrix, *args.fShape, false); } void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) { @@ -720,7 +720,7 @@ void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) { this->internalDrawPath( args.fRenderTargetContext, std::move(paint), aaType, GrUserStencilSettings::kUnused, - *args.fClip, *args.fViewMatrix, *args.fShape, true); + args.fClip, *args.fViewMatrix, *args.fShape, true); } /////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/chromium/third_party/skia/src/gpu/ops/GrDefaultPathRenderer.h b/chromium/third_party/skia/src/gpu/ops/GrDefaultPathRenderer.h index e709964f690..7b0a32d1128 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrDefaultPathRenderer.h +++ b/chromium/third_party/skia/src/gpu/ops/GrDefaultPathRenderer.h @@ -35,7 +35,7 @@ private: GrPaint&&, GrAAType, const GrUserStencilSettings&, - const GrClip&, + const GrClip*, const SkMatrix& viewMatrix, const GrStyledShape&, bool stencilOnly); diff --git a/chromium/third_party/skia/src/gpu/ops/GrDrawVerticesOp.cpp b/chromium/third_party/skia/src/gpu/ops/GrDrawVerticesOp.cpp index f9a42f35cfe..111cc7e7c09 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrDrawVerticesOp.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrDrawVerticesOp.cpp @@ -58,21 +58,29 @@ static GrSLType SkVerticesAttributeToGrSLType(const SkVertices::Attribute& a) { SkUNREACHABLE; } +static bool AttributeUsesViewMatrix(const SkVertices::Attribute& attr) { + return (attr.fMarkerID == 0) && (attr.fUsage == SkVertices::Attribute::Usage::kVector || + attr.fUsage == SkVertices::Attribute::Usage::kNormalVector || + attr.fUsage == SkVertices::Attribute::Usage::kPosition); +} + // Container for a collection of [uint32_t, Matrix] pairs. For a GrDrawVerticesOp whose custom // attributes reference some set of IDs, this stores the actual values of those matrices, // at the time the Op is created. class MarkedMatrices { public: - // For each ID required by 'info', fetch the value of that matrix from 'matrixProvider' + // For each ID required by 'info', fetch the value of that matrix from 'matrixProvider'. + // For vectors/normals/positions, we let ID 0 refer to the canvas CTM matrix. void gather(const SkVerticesPriv& info, const SkMatrixProvider& matrixProvider) { for (int i = 0; i < info.attributeCount(); ++i) { - if (uint32_t id = info.attributes()[i].fMarkerID) { + uint32_t id = info.attributes()[i].fMarkerID; + if (id != 0 || AttributeUsesViewMatrix(info.attributes()[i])) { if (std::none_of(fMatrices.begin(), fMatrices.end(), [id](const auto& m) { return m.first == id; })) { SkM44 matrix; - // SkCanvas should guarantee that this succeeds + // SkCanvas should guarantee that this succeeds. SkAssertResult(matrixProvider.getLocalToMarker(id, &matrix)); - fMatrices.push_back({id, matrix}); + fMatrices.emplace_back(id, matrix); } } } @@ -177,12 +185,7 @@ public: // emit transforms using either explicit local coords or positions const auto& coordsAttr = gp.localCoordsAttr().isInitialized() ? gp.localCoordsAttr() : gp.positionAttr(); - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - coordsAttr.asShaderVar(), - SkMatrix::I(), - args.fFPCoordTransformHandler); + gpArgs->fLocalCoordVar = coordsAttr.asShaderVar(); // Add varyings and globals for all custom attributes using Usage = SkVertices::Attribute::Usage; @@ -195,7 +198,7 @@ public: SkString varyingIn(attr.name()); UniformHandle matrixHandle; - if (customAttr.fMarkerID) { + if (customAttr.fMarkerID || AttributeUsesViewMatrix(customAttr)) { bool normal = customAttr.fUsage == Usage::kNormalVector; for (const MarkedUniform& matrixUni : fCustomMatrixUniforms) { if (matrixUni.fID == customAttr.fMarkerID && matrixUni.fNormal == normal) { @@ -214,10 +217,6 @@ public: } } - // TODO: For now, vectors/normals/positions with a 0 markerID get no transform. - // Those should use localToDevice instead. That means we need to change batching - // logic and then guarantee that we have the view matrix as a uniform here. - switch (customAttr.fUsage) { case Usage::kRaw: break; @@ -302,7 +301,7 @@ public: const VerticesGP& vgp = gp.cast<VerticesGP>(); uint32_t key = 0; key |= (vgp.fColorArrayType == ColorArrayType::kSkColor) ? 0x1 : 0; - key |= ComputePosKey(vgp.viewMatrix()) << 20; + key |= ComputeMatrixKey(vgp.viewMatrix()) << 20; b->add32(key); b->add32(GrColorSpaceXform::XformKey(vgp.fColorSpaceXform.get())); @@ -319,19 +318,14 @@ public: const CoordTransformRange& transformRange) override { const VerticesGP& vgp = gp.cast<VerticesGP>(); - if (!vgp.viewMatrix().isIdentity() && - !SkMatrixPriv::CheapEqual(fViewMatrix, vgp.viewMatrix())) { - fViewMatrix = vgp.viewMatrix(); - pdman.setSkMatrix(fViewMatrixUniform, fViewMatrix); - } + this->setTransform(pdman, fViewMatrixUniform, vgp.viewMatrix(), &fViewMatrix); + this->setTransformDataHelper(pdman, transformRange); if (!vgp.colorAttr().isInitialized() && vgp.color() != fColor) { pdman.set4fv(fColorUniform, 1, vgp.color().vec()); fColor = vgp.color(); } - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); - fColorSpaceHelper.setData(pdman, vgp.fColorSpaceXform.get()); for (const auto& matrixUni : fCustomMatrixUniforms) { diff --git a/chromium/third_party/skia/src/gpu/ops/GrFillRRectOp.cpp b/chromium/third_party/skia/src/gpu/ops/GrFillRRectOp.cpp index 76122e576ce..630955fe042 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrFillRRectOp.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrFillRRectOp.cpp @@ -680,15 +680,13 @@ class FillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor { v->codeAppend("float2 aa_outset = aa_bloat_direction.xy * aa_bloatradius;"); v->codeAppend("float2 vertexpos = corner + radius_outset * radii + aa_outset;"); - // Emit transforms. + // Write positions GrShaderVar localCoord("", kFloat2_GrSLType); if (proc.fFlags & ProcessorFlags::kHasLocalCoords) { v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + " "local_rect.zw * (1 + vertexpos)) * .5;"); - localCoord.set(kFloat2_GrSLType, "localcoord"); + gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord"); } - this->emitTransforms(v, varyings, args.fUniformHandler, localCoord, - args.fFPCoordTransformHandler); // Transform to device space. SkASSERT(!(proc.fFlags & ProcessorFlags::kHasPerspective)); @@ -743,7 +741,7 @@ class FillRRectOp::Processor::CoverageImpl : public GrGLSLGeometryProcessor { void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&, const CoordTransformRange& transformRange) override { - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); } }; @@ -781,15 +779,13 @@ class FillRRectOp::Processor::MSAAImpl : public GrGLSLGeometryProcessor { // [-1,-1,+1,+1] space. v->codeAppend("float2 vertexpos = corner + radius_outset * radii;"); - // Emit transforms. + // Write positions GrShaderVar localCoord("", kFloat2_GrSLType); if (hasLocalCoords) { v->codeAppend("float2 localcoord = (local_rect.xy * (1 - vertexpos) + " "local_rect.zw * (1 + vertexpos)) * .5;"); - localCoord.set(kFloat2_GrSLType, "localcoord"); + gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord"); } - this->emitTransforms(v, varyings, args.fUniformHandler, localCoord, - args.fFPCoordTransformHandler); // Transform to device space. if (!hasPerspective) { @@ -849,7 +845,7 @@ class FillRRectOp::Processor::MSAAImpl : public GrGLSLGeometryProcessor { void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor&, const CoordTransformRange& transformRange) override { - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); } }; diff --git a/chromium/third_party/skia/src/gpu/ops/GrFillRectOp.cpp b/chromium/third_party/skia/src/gpu/ops/GrFillRectOp.cpp index 9e27f9dfe77..5d20400675b 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrFillRectOp.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrFillRectOp.cpp @@ -250,7 +250,7 @@ private: SkArenaAlloc* arena = context->priv().recordTimeAllocator(); // This is equivalent to a GrOpFlushState::detachAppliedClip - GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip(); + GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled(); this->createProgramInfo(context->priv().caps(), arena, writeView, std::move(appliedClip), dstProxyView); @@ -524,7 +524,7 @@ std::unique_ptr<GrDrawOp> GrFillRectOp::MakeOp(GrRecordingContext* context, } void GrFillRectOp::AddFillRectOps(GrRenderTargetContext* rtc, - const GrClip& clip, + const GrClip* clip, GrRecordingContext* context, GrPaint&& paint, GrAAType aaType, diff --git a/chromium/third_party/skia/src/gpu/ops/GrFillRectOp.h b/chromium/third_party/skia/src/gpu/ops/GrFillRectOp.h index 947ee7c8a3f..4a8f211ee05 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrFillRectOp.h +++ b/chromium/third_party/skia/src/gpu/ops/GrFillRectOp.h @@ -49,7 +49,7 @@ public: // Bulk API for drawing quads with a single op // TODO(michaelludwig) - remove if the bulk API is not useful for SkiaRenderer static void AddFillRectOps(GrRenderTargetContext*, - const GrClip& clip, + const GrClip* clip, GrRecordingContext*, GrPaint&&, GrAAType, diff --git a/chromium/third_party/skia/src/gpu/ops/GrLatticeOp.cpp b/chromium/third_party/skia/src/gpu/ops/GrLatticeOp.cpp index 7efe3a322fa..fe9983fb51d 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrLatticeOp.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrLatticeOp.cpp @@ -49,7 +49,7 @@ public: void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc, const CoordTransformRange& transformRange) override { const auto& latticeGP = proc.cast<LatticeGP>(); - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); fColorSpaceXformHelper.setData(pdman, latticeGP.fColorSpaceXform.get()); } @@ -62,11 +62,8 @@ public: args.fVaryingHandler->emitAttributes(latticeGP); this->writeOutputPosition(args.fVertBuilder, gpArgs, latticeGP.fInPosition.name()); - this->emitTransforms(args.fVertBuilder, - args.fVaryingHandler, - args.fUniformHandler, - latticeGP.fInTextureCoords.asShaderVar(), - args.fFPCoordTransformHandler); + gpArgs->fLocalCoordVar = latticeGP.fInTextureCoords.asShaderVar(); + args.fFragBuilder->codeAppend("float2 textureCoords;"); args.fVaryingHandler->addPassThroughAttribute(latticeGP.fInTextureCoords, "textureCoords"); diff --git a/chromium/third_party/skia/src/gpu/ops/GrMeshDrawOp.cpp b/chromium/third_party/skia/src/gpu/ops/GrMeshDrawOp.cpp index f5a8c040477..809620b91b7 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrMeshDrawOp.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrMeshDrawOp.cpp @@ -33,7 +33,7 @@ void GrMeshDrawOp::onPrePrepareDraws(GrRecordingContext* context, SkArenaAlloc* arena = context->priv().recordTimeAllocator(); // This is equivalent to a GrOpFlushState::detachAppliedClip - GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip(); + GrAppliedClip appliedClip = clip ? std::move(*clip) : GrAppliedClip::Disabled(); this->createProgramInfo(context->priv().caps(), arena, writeView, std::move(appliedClip), dstProxyView); diff --git a/chromium/third_party/skia/src/gpu/ops/GrOvalOpFactory.cpp b/chromium/third_party/skia/src/gpu/ops/GrOvalOpFactory.cpp index d85755781bf..f720f638607 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrOvalOpFactory.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrOvalOpFactory.cpp @@ -155,14 +155,9 @@ private: // Setup position this->writeOutputPosition(vertBuilder, gpArgs, cgp.fInPosition.name()); - - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - cgp.fInPosition.asShaderVar(), - cgp.fLocalMatrix, - args.fFPCoordTransformHandler); + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, + cgp.fInPosition.asShaderVar(), cgp.fLocalMatrix, + &fLocalMatrixUniform); fragBuilder->codeAppend("float d = length(circleEdge.xy);"); fragBuilder->codeAppend("half distanceToOuterEdge = half(circleEdge.z * (1.0 - d));"); @@ -210,24 +205,29 @@ private: const GrShaderCaps&, GrProcessorKeyBuilder* b) { const CircleGeometryProcessor& cgp = gp.cast<CircleGeometryProcessor>(); - uint16_t key; + uint32_t key; key = cgp.fStroke ? 0x01 : 0x0; - key |= cgp.fLocalMatrix.hasPerspective() ? 0x02 : 0x0; - key |= cgp.fInClipPlane.isInitialized() ? 0x04 : 0x0; - key |= cgp.fInIsectPlane.isInitialized() ? 0x08 : 0x0; - key |= cgp.fInUnionPlane.isInitialized() ? 0x10 : 0x0; - key |= cgp.fInRoundCapCenters.isInitialized() ? 0x20 : 0x0; + key |= cgp.fInClipPlane.isInitialized() ? 0x02 : 0x0; + key |= cgp.fInIsectPlane.isInitialized() ? 0x04 : 0x0; + key |= cgp.fInUnionPlane.isInitialized() ? 0x08 : 0x0; + key |= cgp.fInRoundCapCenters.isInitialized() ? 0x10 : 0x0; + key |= (ComputeMatrixKey(cgp.fLocalMatrix) << 16); b->add32(key); } void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc, const CoordTransformRange& transformRange) override { - this->setTransformDataHelper(primProc.cast<CircleGeometryProcessor>().fLocalMatrix, - pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); + this->setTransform(pdman, fLocalMatrixUniform, + primProc.cast<CircleGeometryProcessor>().fLocalMatrix, + &fLocalMatrix); } private: typedef GrGLSLGeometryProcessor INHERITED; + + SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix(); + UniformHandle fLocalMatrixUniform; }; SkMatrix fLocalMatrix; @@ -389,14 +389,10 @@ private: // Setup position this->writeOutputPosition(vertBuilder, gpArgs, bcscgp.fInPosition.name()); + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, + bcscgp.fInPosition.asShaderVar(), bcscgp.fLocalMatrix, + &fLocalMatrixUniform); - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - bcscgp.fInPosition.asShaderVar(), - bcscgp.fLocalMatrix, - args.fFPCoordTransformHandler); GrShaderVar fnArgs[] = { GrShaderVar("angleToEdge", kFloat_GrSLType), GrShaderVar("diameter", kFloat_GrSLType), @@ -477,18 +473,22 @@ private: GrProcessorKeyBuilder* b) { const ButtCapDashedCircleGeometryProcessor& bcscgp = gp.cast<ButtCapDashedCircleGeometryProcessor>(); - b->add32(bcscgp.fLocalMatrix.hasPerspective()); + b->add32(ComputeMatrixKey(bcscgp.fLocalMatrix)); } void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc, const CoordTransformRange& transformRange) override { - this->setTransformDataHelper( - primProc.cast<ButtCapDashedCircleGeometryProcessor>().fLocalMatrix, pdman, - transformRange); + this->setTransformDataHelper(pdman, transformRange); + this->setTransform(pdman, fLocalMatrixUniform, + primProc.cast<ButtCapDashedCircleGeometryProcessor>().fLocalMatrix, + &fLocalMatrix); } private: typedef GrGLSLGeometryProcessor INHERITED; + + SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix(); + UniformHandle fLocalMatrixUniform; }; SkMatrix fLocalMatrix; @@ -588,14 +588,10 @@ private: // Setup position this->writeOutputPosition(vertBuilder, gpArgs, egp.fInPosition.name()); + this->writeLocalCoord(vertBuilder, uniformHandler, gpArgs, + egp.fInPosition.asShaderVar(), egp.fLocalMatrix, + &fLocalMatrixUniform); - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - egp.fInPosition.asShaderVar(), - egp.fLocalMatrix, - args.fFPCoordTransformHandler); // For stroked ellipses, we use the full ellipse equation (x^2/a^2 + y^2/b^2 = 1) // to compute both the edges because we need two separate test equations for // the single offset. @@ -666,19 +662,23 @@ private: const GrShaderCaps&, GrProcessorKeyBuilder* b) { const EllipseGeometryProcessor& egp = gp.cast<EllipseGeometryProcessor>(); - uint16_t key = egp.fStroke ? 0x1 : 0x0; - key |= egp.fLocalMatrix.hasPerspective() ? 0x2 : 0x0; + uint32_t key = egp.fStroke ? 0x1 : 0x0; + key |= ComputeMatrixKey(egp.fLocalMatrix) << 1; b->add32(key); } void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& primProc, const CoordTransformRange& transformRange) override { const EllipseGeometryProcessor& egp = primProc.cast<EllipseGeometryProcessor>(); - this->setTransformDataHelper(egp.fLocalMatrix, pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); + this->setTransform(pdman, fLocalMatrixUniform, egp.fLocalMatrix, &fLocalMatrix); } private: typedef GrGLSLGeometryProcessor INHERITED; + + SkMatrix fLocalMatrix = SkMatrix::InvalidMatrix(); + UniformHandle fLocalMatrixUniform; }; Attribute fInPosition; @@ -791,13 +791,7 @@ private: diegp.fInPosition.name(), diegp.fViewMatrix, &fViewMatrixUniform); - - // emit transforms - this->emitTransforms(vertBuilder, - varyingHandler, - uniformHandler, - diegp.fInPosition.asShaderVar(), - args.fFPCoordTransformHandler); + gpArgs->fLocalCoordVar = diegp.fInPosition.asShaderVar(); // for outer curve fragBuilder->codeAppendf("float2 scaledOffset = %s.xy;", offsets0.fsIn()); @@ -862,8 +856,8 @@ private: const GrShaderCaps&, GrProcessorKeyBuilder* b) { const DIEllipseGeometryProcessor& diegp = gp.cast<DIEllipseGeometryProcessor>(); - uint16_t key = static_cast<uint16_t>(diegp.fStyle); - key |= ComputePosKey(diegp.fViewMatrix) << 10; + uint32_t key = static_cast<uint32_t>(diegp.fStyle); + key |= ComputeMatrixKey(diegp.fViewMatrix) << 10; b->add32(key); } @@ -871,17 +865,12 @@ private: const CoordTransformRange& transformRange) override { const DIEllipseGeometryProcessor& diegp = gp.cast<DIEllipseGeometryProcessor>(); - if (!diegp.fViewMatrix.isIdentity() && - !SkMatrixPriv::CheapEqual(fViewMatrix, diegp.fViewMatrix)) - { - fViewMatrix = diegp.fViewMatrix; - pdman.setSkMatrix(fViewMatrixUniform, fViewMatrix); - } - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); + this->setTransform(pdman, fViewMatrixUniform, diegp.fViewMatrix, &fViewMatrix); + this->setTransformDataHelper(pdman, transformRange); } private: - SkMatrix fViewMatrix; + SkMatrix fViewMatrix; UniformHandle fViewMatrixUniform; typedef GrGLSLGeometryProcessor INHERITED; diff --git a/chromium/third_party/skia/src/gpu/ops/GrQuadPerEdgeAA.cpp b/chromium/third_party/skia/src/gpu/ops/GrQuadPerEdgeAA.cpp index bc5de24d968..ca420dd839f 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrQuadPerEdgeAA.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrQuadPerEdgeAA.cpp @@ -571,7 +571,7 @@ public: void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc, const CoordTransformRange& transformRange) override { const auto& gp = proc.cast<QuadPerEdgeAAGeometryProcessor>(); - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); fTextureColorSpaceXformHelper.setData(pdman, gp.fTextureColorSpaceXform.get()); } @@ -604,18 +604,10 @@ public: gpArgs->fPositionVar = gp.fPosition.asShaderVar(); } - // Handle local coordinates if they exist. This is required even when the op - // isn't providing local coords but there are FPs called with explicit coords. - // It installs the uniforms that transform their coordinates in the fragment - // shader. - // NOTE: If the only usage of local coordinates is for the inline texture fetch - // before FPs, then there are no registered FPCoordTransforms and this ends up - // emitting nothing, so there isn't a duplication of local coordinates - this->emitTransforms(args.fVertBuilder, - args.fVaryingHandler, - args.fUniformHandler, - gp.fLocalCoord.asShaderVar(), - args.fFPCoordTransformHandler); + // This attribute will be uninitialized if earlier FP analysis determined no + // local coordinates are needed (and this will not include the inline texture + // fetch this GP does before invoking FPs). + gpArgs->fLocalCoordVar = gp.fLocalCoord.asShaderVar(); // Solid color before any texturing gets modulated in if (gp.fColor.isInitialized()) { diff --git a/chromium/third_party/skia/src/gpu/ops/GrSmallPathRenderer.cpp b/chromium/third_party/skia/src/gpu/ops/GrSmallPathRenderer.cpp index 075376d7f18..0f3ab8ae4fb 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrSmallPathRenderer.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrSmallPathRenderer.cpp @@ -885,7 +885,7 @@ bool GrSmallPathRenderer::onDrawPath(const DrawPathArgs& args) { std::unique_ptr<GrDrawOp> op = SmallPathOp::Make( args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix, fAtlas.get(), &fShapeCache, &fShapeList, args.fGammaCorrect, args.fUserStencilSettings); - args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); + args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op)); return true; } diff --git a/chromium/third_party/skia/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp b/chromium/third_party/skia/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp index 59a8bf75a7a..fcff78cf6f0 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrStencilAndCoverPathRenderer.cpp @@ -7,7 +7,6 @@ #include "include/private/GrRecordingContext.h" #include "src/gpu/GrCaps.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrGpu.h" #include "src/gpu/GrPath.h" #include "src/gpu/GrRenderTargetContextPriv.h" @@ -101,7 +100,7 @@ void GrStencilAndCoverPathRenderer::onStencilPath(const StencilPathArgs& args) { "GrStencilAndCoverPathRenderer::onStencilPath"); sk_sp<GrPath> p(get_gr_path(fResourceProvider, *args.fShape)); args.fRenderTargetContext->priv().stencilPath( - *args.fClip, args.fDoStencilMSAA, *args.fViewMatrix, std::move(p)); + args.fClip, args.fDoStencilMSAA, *args.fViewMatrix, std::move(p)); } bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { @@ -125,15 +124,16 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { args.fRenderTargetContext->height()); // Inverse fill. // fake inverse with a stencil and cover - GrAppliedClip appliedClip; - if (!args.fClip->apply( + GrAppliedClip appliedClip(args.fRenderTargetContext->dimensions()); + if (args.fClip && !args.fClip->apply( args.fContext, args.fRenderTargetContext, doStencilMSAA, true, &appliedClip, &devBounds)) { return true; } - GrStencilClip stencilClip(appliedClip.stencilStackID()); + GrStencilClip stencilClip(args.fRenderTargetContext->dimensions(), + appliedClip.stencilStackID()); if (appliedClip.scissorState().enabled()) { - stencilClip.fixedClip().setScissor(appliedClip.scissorState().rect()); + SkAssertResult(stencilClip.fixedClip().setScissor(appliedClip.scissorState().rect())); } if (appliedClip.windowRectsState().enabled()) { stencilClip.fixedClip().setWindowRectangles(appliedClip.windowRectsState().windows(), @@ -142,7 +142,7 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { // Just ignore the analytic FPs (if any) during the stencil pass. They will still clip the // final draw and it is meaningless to multiply by coverage when drawing to stencil. args.fRenderTargetContext->priv().stencilPath( - stencilClip, GrAA(doStencilMSAA), viewMatrix, std::move(path)); + &stencilClip, GrAA(doStencilMSAA), viewMatrix, std::move(path)); { static constexpr GrUserStencilSettings kInvertedCoverPass( @@ -179,14 +179,14 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) { doStencilMSAA = GrAA::kYes; } args.fRenderTargetContext->priv().stencilRect( - *args.fClip, &kInvertedCoverPass, std::move(args.fPaint), doStencilMSAA, + args.fClip, &kInvertedCoverPass, std::move(args.fPaint), doStencilMSAA, coverMatrix, coverBounds, &localMatrix); } } else { std::unique_ptr<GrDrawOp> op = GrDrawPathOp::Make( args.fContext, viewMatrix, std::move(args.fPaint), GrAA(doStencilMSAA), std::move(path)); - args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); + args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op)); } return true; diff --git a/chromium/third_party/skia/src/gpu/ops/GrTextureOp.cpp b/chromium/third_party/skia/src/gpu/ops/GrTextureOp.cpp index 92904e97fad..ee712911f95 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrTextureOp.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrTextureOp.cpp @@ -95,7 +95,7 @@ static bool filter_has_effect(const GrQuad& srcQuad, const GrQuad& dstQuad) { // regular and rectangular textures, w/ or w/o origin correction. struct NormalizationParams { float fIW; // 1 / width of texture, or 1.0 for texture rectangles - float fIH; // 1 / height of texture, or 1.0 for tex rects, X -1 if bottom-left origin + float fInvH; // 1 / height of texture, or 1.0 for tex rects, X -1 if bottom-left origin float fYOffset; // 0 for top-left origin, height of [normalized] tex if bottom-left }; static NormalizationParams proxy_normalization_params(const GrSurfaceProxy* proxy, @@ -120,21 +120,13 @@ static NormalizationParams proxy_normalization_params(const GrSurfaceProxy* prox } } -static SkRect inset_subset_for_bilerp(const NormalizationParams& params, const SkRect& subsetRect) { - // Normalized pixel size is also equal to iw and ih, so the insets for bilerp are just - // in those units and can be applied safely after normalization. However, if the subset is - // smaller than a texel, it should clamp to the center of that axis. - float dw = subsetRect.width() < params.fIW ? subsetRect.width() : params.fIW; - float dh = subsetRect.height() < params.fIH ? subsetRect.height() : params.fIH; - return subsetRect.makeInset(0.5f * dw, 0.5f * dh); -} - // Normalize the subset. If 'subsetRect' is null, it is assumed no subset constraint is desired, // so a sufficiently large rect is returned even if the quad ends up batched with an op that uses -// subsets overall. -static SkRect normalize_subset(GrSamplerState::Filter filter, - const NormalizationParams& params, - const SkRect* subsetRect) { +// subsets overall. When there is a subset it will be inset based on the filter mode. Normalization +// and y-flipping are applied as indicated by NormalizationParams. +static SkRect normalize_and_inset_subset(GrSamplerState::Filter filter, + const NormalizationParams& params, + const SkRect* subsetRect) { static constexpr SkRect kLargeRect = {-100000, -100000, 1000000, 1000000}; if (!subsetRect) { // Either the quad has no subset constraint and is batched with a subset constrained op @@ -144,10 +136,20 @@ static SkRect normalize_subset(GrSamplerState::Filter filter, } auto ltrb = skvx::Vec<4, float>::Load(subsetRect); + auto flipHi = skvx::Vec<4, float>({1.f, 1.f, -1.f, -1.f}); + if (filter == GrSamplerState::Filter::kNearest) { + // Make sure our insetting puts us at pixel centers. + ltrb = skvx::floor(ltrb*flipHi)*flipHi; + } + // Inset with pin to the rect center. + ltrb += skvx::Vec<4, float>({.5f, .5f, -.5f, -.5f}); + auto mid = (skvx::shuffle<2, 3, 0, 1>(ltrb) + ltrb)*0.5f; + ltrb = skvx::min(ltrb*flipHi, mid*flipHi)*flipHi; + // Normalize and offset - ltrb = mad(ltrb, {params.fIW, params.fIH, params.fIW, params.fIH}, + ltrb = mad(ltrb, {params.fIW, params.fInvH, params.fIW, params.fInvH}, {0.f, params.fYOffset, 0.f, params.fYOffset}); - if (params.fIH < 0.f) { + if (params.fInvH < 0.f) { // Flip top and bottom to keep the rect sorted when loaded back to SkRect. ltrb = skvx::shuffle<0, 3, 2, 1>(ltrb); } @@ -163,7 +165,7 @@ static void normalize_src_quad(const NormalizationParams& params, // The src quad should not have any perspective SkASSERT(!srcQuad->hasPerspective()); skvx::Vec<4, float> xs = srcQuad->x4f() * params.fIW; - skvx::Vec<4, float> ys = mad(srcQuad->y4f(), params.fIH, params.fYOffset); + skvx::Vec<4, float> ys = mad(srcQuad->y4f(), params.fInvH, params.fYOffset); xs.store(srcQuad->xs()); ys.store(srcQuad->ys()); } @@ -183,6 +185,32 @@ static int proxy_run_count(const GrRenderTargetContext::TextureSetEntry set[], i return actualProxyRunCount; } +static bool safe_to_ignore_subset_rect(GrAAType aaType, GrSamplerState::Filter filter, + const DrawQuad& quad, const SkRect& subsetRect) { + // If both the device and local quad are both axis-aligned, and filtering is off, the local quad + // can push all the way up to the edges of the the subset rect and the sampler shouldn't + // overshoot. Unfortunately, antialiasing adds enough jitter that we can only rely on this in + // the non-antialiased case. + SkRect localBounds = quad.fLocal.bounds(); + if (aaType == GrAAType::kNone && + filter == GrSamplerState::Filter::kNearest && + quad.fDevice.quadType() == GrQuad::Type::kAxisAligned && + quad.fLocal.quadType() == GrQuad::Type::kAxisAligned && + subsetRect.contains(localBounds)) { + + return true; + } + + // If the subset rect is inset by at least 0.5 pixels into the local quad's bounds, the + // sampler shouldn't overshoot, even when antialiasing and filtering is taken into account. + if (subsetRect.makeInset(0.5f, 0.5f).contains(localBounds)) { + return true; + } + + // The subset rect cannot be ignored safely. + return false; +} + /** * 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. @@ -415,9 +443,7 @@ private: void allocatePrePreparedVertices(SkArenaAlloc* arena) { fPrePreparedVertices = arena->makeArrayDefault<char>(this->totalSizeInBytes()); } - }; - // If subsetRect is not null it will be used to apply a strict src rect-style constraint. TextureOp(GrSurfaceProxyView proxyView, sk_sp<GrColorSpaceXform> textureColorSpaceXform, @@ -444,19 +470,19 @@ private: !subsetRect->contains(proxyView.proxy()->backingStoreBoundsRect())); // We may have had a strict constraint with nearest filter solely due to possible AA bloat. - // If we don't have (or determined we don't need) coverage AA then we can skip using a - // subset. - if (subsetRect && filter == GrSamplerState::Filter::kNearest && - aaType != GrAAType::kCoverage) { - subsetRect = nullptr; - fMetadata.fSubset = static_cast<uint16_t>(Subset::kNo); + // Try to identify cases where the subsetting isn't actually necessary, and skip it. + if (subsetRect) { + if (safe_to_ignore_subset_rect(aaType, filter, *quad, *subsetRect)) { + subsetRect = nullptr; + fMetadata.fSubset = static_cast<uint16_t>(Subset::kNo); + } } // Normalize src coordinates and the subset (if set) NormalizationParams params = proxy_normalization_params(proxyView.proxy(), proxyView.origin()); normalize_src_quad(params, &quad->fLocal); - SkRect subset = normalize_subset(filter, params, subsetRect); + SkRect subset = normalize_and_inset_subset(filter, params, subsetRect); // Set bounds before clipping so we don't have to worry about unioning the bounds of // the two potential quads (GrQuad::bounds() is perspective-safe). @@ -542,11 +568,6 @@ private: netFilter = GrSamplerState::Filter::kBilerp; } - // Normalize the src quads and apply origin - NormalizationParams proxyParams = proxy_normalization_params( - curProxy, set[q].fProxyView.origin()); - normalize_src_quad(proxyParams, &quad.fLocal); - // Update overall bounds of the op as the union of all quads bounds.joinPossiblyEmptyRect(quad.fDevice.bounds()); @@ -554,6 +575,7 @@ private: GrAAType aaForQuad; GrQuadUtils::ResolveAAType(aaType, set[q].fAAFlags, quad.fDevice, &aaForQuad, &quad.fEdgeFlags); + // Resolve sets aaForQuad to aaType or None, there is never a change between aa methods SkASSERT(aaForQuad == GrAAType::kNone || aaForQuad == aaType); if (netAAType == GrAAType::kNone && aaForQuad != GrAAType::kNone) { @@ -563,27 +585,29 @@ private: // Calculate metadata for the entry const SkRect* subsetForQuad = nullptr; if (constraint == SkCanvas::kStrict_SrcRectConstraint) { - // Check (briefly) if the strict constraint is needed for this set entry - if (!set[q].fSrcRect.contains(curProxy->backingStoreBoundsRect()) && - (filter == GrSamplerState::Filter::kBilerp || - aaForQuad == GrAAType::kCoverage)) { - // Can't rely on hardware clamping and the draw will access outer texels - // for AA and/or bilerp. Unlike filter quality, this op still has per-quad - // control over AA so that can check aaForQuad, not netAAType. - netSubset = Subset::kYes; - subsetForQuad = &set[q].fSrcRect; + // Check (briefly) if the subset rect is actually needed for this set entry. + SkRect* subsetRect = &set[q].fSrcRect; + if (!subsetRect->contains(curProxy->backingStoreBoundsRect())) { + if (!safe_to_ignore_subset_rect(aaForQuad, filter, quad, *subsetRect)) { + netSubset = Subset::kYes; + subsetForQuad = subsetRect; + } } } + + // Normalize the src quads and apply origin + NormalizationParams proxyParams = proxy_normalization_params( + curProxy, set[q].fProxyView.origin()); + normalize_src_quad(proxyParams, &quad.fLocal); + // This subset may represent a no-op, otherwise it will have the origin and dimensions // of the texture applied to it. Insetting for bilinear filtering is deferred until // on[Pre]Prepare so that the overall filter can be lazily determined. - SkRect subset = normalize_subset(filter, proxyParams, subsetForQuad); + SkRect subset = normalize_and_inset_subset(filter, proxyParams, subsetForQuad); // Always append a quad (or 2 if perspective clipped), it just may refer back to a prior // ViewCountPair (this frequently happens when Chrome draws 9-patches). - float alpha = SkTPin(set[q].fAlpha, 0.f, 1.f); - fViewCountPairs[p].fQuadCnt += this->appendQuad( - &quad, {alpha, alpha, alpha, alpha}, subset); + fViewCountPairs[p].fQuadCnt += this->appendQuad(&quad, set[q].fColor, subset); } // The # of proxy switches should match what was provided (+1 because we incremented p // when a new proxy was encountered). @@ -689,21 +713,12 @@ private: const int quadCnt = op.fViewCountPairs[p].fQuadCnt; SkDEBUGCODE(int meshVertexCnt = quadCnt * desc->fVertexSpec.verticesPerQuad()); - // Can just use top-left for origin here since we only need the dimensions to - // determine the texel size for insetting. - NormalizationParams params = proxy_normalization_params( - op.fViewCountPairs[p].fProxy.get(), kTopLeft_GrSurfaceOrigin); - - bool inset = texOp->fMetadata.filter() != GrSamplerState::Filter::kNearest; - for (int i = 0; i < quadCnt && iter.next(); ++i) { SkASSERT(iter.isLocalValid()); const ColorSubsetAndAA& info = iter.metadata(); tessellator.append(iter.deviceQuad(), iter.localQuad(), info.fColor, - inset ? inset_subset_for_bilerp(params, info.fSubsetRect) - : info.fSubsetRect, - info.aaFlags()); + info.fSubsetRect, info.aaFlags()); } SkASSERT((totVerticesSeen + meshVertexCnt) * vertexSize @@ -1041,21 +1056,20 @@ std::unique_ptr<GrDrawOp> GrTextureOp::Make(GrRecordingContext* context, const auto& caps = *context->priv().caps(); SkRect localRect; if (quad->fLocal.asRect(&localRect)) { - fp = GrTextureEffect::MakeSubset(std::move(proxyView), alphaType, SkMatrix::I(), filter, - *subset, localRect, caps); + fp = GrTextureEffect::MakeSubset(std::move(proxyView), alphaType, SkMatrix::I(), + filter, *subset, localRect, caps); } else { - fp = GrTextureEffect::MakeSubset(std::move(proxyView), alphaType, SkMatrix::I(), filter, - *subset, caps); + fp = GrTextureEffect::MakeSubset(std::move(proxyView), alphaType, SkMatrix::I(), + filter, *subset, caps); } } else { fp = GrTextureEffect::Make(std::move(proxyView), alphaType, SkMatrix::I(), filter); } fp = GrColorSpaceXformEffect::Make(std::move(fp), std::move(textureXform)); - paint.addColorFragmentProcessor(std::move(fp)); if (saturate == GrTextureOp::Saturate::kYes) { - paint.addColorFragmentProcessor(GrClampFragmentProcessor::Make(false)); + fp = GrClampFragmentProcessor::Make(std::move(fp), /*clampToPremul=*/false); } - + paint.addColorFragmentProcessor(std::move(fp)); return GrFillRectOp::Make(context, std::move(paint), aaType, quad); } } @@ -1064,7 +1078,7 @@ std::unique_ptr<GrDrawOp> GrTextureOp::Make(GrRecordingContext* context, class GrTextureOp::BatchSizeLimiter { public: BatchSizeLimiter(GrRenderTargetContext* rtc, - const GrClip& clip, + const GrClip* clip, GrRecordingContext* context, int numEntries, GrSamplerState::Filter filter, @@ -1102,7 +1116,7 @@ public: private: GrRenderTargetContext* fRTC; - const GrClip& fClip; + const GrClip* fClip; GrRecordingContext* fContext; GrSamplerState::Filter fFilter; GrTextureOp::Saturate fSaturate; @@ -1116,7 +1130,7 @@ private: // Greedily clump quad draws together until the index buffer limit is exceeded. void GrTextureOp::AddTextureSetOps(GrRenderTargetContext* rtc, - const GrClip& clip, + const GrClip* clip, GrRecordingContext* context, GrRenderTargetContext::TextureSetEntry set[], int cnt, @@ -1141,7 +1155,6 @@ void GrTextureOp::AddTextureSetOps(GrRenderTargetContext* rtc, // automatically creates the appropriate GrFillRectOp to emulate GrTextureOp. SkMatrix ctm; for (int i = 0; i < cnt; ++i) { - float alpha = set[i].fAlpha; ctm = viewMatrix; if (set[i].fPreViewMatrix) { ctm.preConcat(*set[i].fPreViewMatrix); @@ -1164,7 +1177,7 @@ void GrTextureOp::AddTextureSetOps(GrRenderTargetContext* rtc, ? &set[i].fSrcRect : nullptr; auto op = Make(context, set[i].fProxyView, set[i].fSrcAlphaType, textureColorSpaceXform, - filter, {alpha, alpha, alpha, alpha}, saturate, blendMode, aaType, + filter, set[i].fColor, saturate, blendMode, aaType, &quad, subset); rtc->addDrawOp(clip, std::move(op)); } diff --git a/chromium/third_party/skia/src/gpu/ops/GrTextureOp.h b/chromium/third_party/skia/src/gpu/ops/GrTextureOp.h index 404535b68f4..2c1f48e16cd 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrTextureOp.h +++ b/chromium/third_party/skia/src/gpu/ops/GrTextureOp.h @@ -56,7 +56,7 @@ public: // supported, or if the blend mode is not src-over. 'cnt' is the size of the entry array. // 'proxyCnt' <= 'cnt' and represents the number of proxy switches within the array. static void AddTextureSetOps(GrRenderTargetContext*, - const GrClip& clip, + const GrClip* clip, GrRecordingContext*, GrRenderTargetContext::TextureSetEntry[], int cnt, diff --git a/chromium/third_party/skia/src/gpu/ops/GrTriangulatingPathRenderer.cpp b/chromium/third_party/skia/src/gpu/ops/GrTriangulatingPathRenderer.cpp index 67f829827ae..7e696c4ae2f 100644 --- a/chromium/third_party/skia/src/gpu/ops/GrTriangulatingPathRenderer.cpp +++ b/chromium/third_party/skia/src/gpu/ops/GrTriangulatingPathRenderer.cpp @@ -11,12 +11,12 @@ #include "src/core/SkGeometry.h" #include "src/gpu/GrAuditTrail.h" #include "src/gpu/GrCaps.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrDefaultGeoProcFactory.h" #include "src/gpu/GrDrawOpTest.h" #include "src/gpu/GrEagerVertexAllocator.h" #include "src/gpu/GrOpFlushState.h" #include "src/gpu/GrProgramInfo.h" +#include "src/gpu/GrRenderTargetContext.h" #include "src/gpu/GrResourceCache.h" #include "src/gpu/GrResourceProvider.h" #include "src/gpu/GrSimpleMesh.h" @@ -419,12 +419,11 @@ private: bool GrTriangulatingPathRenderer::onDrawPath(const DrawPathArgs& args) { GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(), "GrTriangulatingPathRenderer::onDrawPath"); - SkIRect clipBoundsI = args.fClip->getConservativeBounds(args.fRenderTargetContext->width(), - args.fRenderTargetContext->height()); + std::unique_ptr<GrDrawOp> op = TriangulatingPathOp::Make( - args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix, clipBoundsI, - args.fAAType, args.fUserStencilSettings); - args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); + args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix, + *args.fClipConservativeBounds, args.fAAType, args.fUserStencilSettings); + args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op)); return true; } diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrDrawAtlasPathOp.cpp b/chromium/third_party/skia/src/gpu/tessellate/GrDrawAtlasPathOp.cpp index 142e20cb5fb..cda13bea6f6 100644 --- a/chromium/third_party/skia/src/gpu/tessellate/GrDrawAtlasPathOp.cpp +++ b/chromium/third_party/skia/src/gpu/tessellate/GrDrawAtlasPathOp.cpp @@ -18,8 +18,8 @@ namespace { constexpr static GrGeometryProcessor::Attribute kInstanceAttribs[] = { - {"devibounds", kInt4_GrVertexAttribType, kInt4_GrSLType}, - {"dev_to_atlas_offset", kInt2_GrVertexAttribType, kInt2_GrSLType}, + {"dev_xywh", kInt4_GrVertexAttribType, kInt4_GrSLType}, + {"atlas_xy", kInt2_GrVertexAttribType, kInt2_GrSLType}, {"color", kFloat4_GrVertexAttribType, kHalf4_GrSLType}, {"viewmatrix_scaleskew", kFloat4_GrVertexAttribType, kFloat4_GrSLType}, {"viewmatrix_trans", kFloat2_GrVertexAttribType, kFloat2_GrSLType}}; @@ -73,22 +73,24 @@ class DrawAtlasPathShader::Impl : public GrGLSLGeometryProcessor { args.fVertBuilder->codeAppendf(R"( float2 T = float2(sk_VertexID & 1, sk_VertexID >> 1); - float2 devcoord = mix(float2(devibounds.xy), float2(devibounds.zw), T); - float2 atlascoord = devcoord + float2(dev_to_atlas_offset); + float2 devtopleft = float2(dev_xywh.xy); + float2 devcoord = abs(float2(dev_xywh.zw)) * T + devtopleft; + float2 atlascoord = devcoord - devtopleft; + if (dev_xywh.w < 0) { // Negative height indicates that the path is transposed. + atlascoord = atlascoord.yx; + } + atlascoord += atlas_xy; %s = atlascoord * %s;)", atlasCoord.vsOut(), atlasAdjust); gpArgs->fPositionVar.set(kFloat2_GrSLType, "devcoord"); - GrShaderVar localCoord = gpArgs->fPositionVar; if (shader.fUsesLocalCoords) { args.fVertBuilder->codeAppendf(R"( float2x2 M = float2x2(viewmatrix_scaleskew); float2 localcoord = inverse(M) * (devcoord - viewmatrix_trans);)"); - localCoord.set(kFloat2_GrSLType, "localcoord"); + gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord"); } - this->emitTransforms(args.fVertBuilder, args.fVaryingHandler, args.fUniformHandler, - localCoord, args.fFPCoordTransformHandler); args.fFragBuilder->codeAppendf("%s = ", args.fOutputCoverage); args.fFragBuilder->appendTextureLookup(args.fTexSamplers[0], atlasCoord.fsIn()); @@ -99,7 +101,7 @@ class DrawAtlasPathShader::Impl : public GrGLSLGeometryProcessor { const CoordTransformRange& transformRange) override { const SkISize& dimensions = primProc.cast<DrawAtlasPathShader>().fAtlasDimensions; pdman.set2f(fAtlasAdjustUniform, 1.f / dimensions.width(), 1.f / dimensions.height()); - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); } GrGLSLUniformHandler::UniformHandle fAtlasAdjustUniform; diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrDrawAtlasPathOp.h b/chromium/third_party/skia/src/gpu/tessellate/GrDrawAtlasPathOp.h index b20583ba41c..43f8671167b 100644 --- a/chromium/third_party/skia/src/gpu/tessellate/GrDrawAtlasPathOp.h +++ b/chromium/third_party/skia/src/gpu/tessellate/GrDrawAtlasPathOp.h @@ -8,6 +8,7 @@ #ifndef GrDrawAtlasPathOp_DEFINED #define GrDrawAtlasPathOp_DEFINED +#include "src/core/SkIPoint16.h" #include "src/gpu/ops/GrDrawOp.h" class GrDrawAtlasPathOp : public GrDrawOp { @@ -15,12 +16,13 @@ public: DEFINE_OP_CLASS_ID GrDrawAtlasPathOp(int numRenderTargetSamples, sk_sp<GrTextureProxy> atlasProxy, - const SkIRect& devIBounds, const SkIVector& devToAtlasOffset, - const SkMatrix& viewMatrix, GrPaint&& paint) + const SkIRect& devIBounds, const SkIPoint16& locationInAtlas, + bool transposedInAtlas, const SkMatrix& viewMatrix, GrPaint&& paint) : GrDrawOp(ClassID()) , fEnableHWAA(numRenderTargetSamples > 1) , fAtlasProxy(std::move(atlasProxy)) - , fInstanceList(devIBounds, devToAtlasOffset, paint.getColor4f(), viewMatrix) + , fInstanceList(devIBounds, locationInAtlas, transposedInAtlas, paint.getColor4f(), + viewMatrix) , fProcessors(std::move(paint)) { this->setBounds(SkRect::Make(devIBounds), HasAABloat::kYes, IsHairline::kNo); } @@ -53,25 +55,27 @@ private: } return stride; } - Instance(const SkIRect& devIBounds, SkIVector devToAtlasOffset, const SkPMColor4f& color, - const SkMatrix& m) - : fDevIBounds(devIBounds) - , fDevToAtlasOffset(devToAtlasOffset) + Instance(const SkIRect& devIBounds, const SkIPoint16& locationInAtlas, + bool transposedInAtlas, const SkPMColor4f& color, const SkMatrix& m) + : fDevXYWH{devIBounds.left(), devIBounds.top(), devIBounds.width(), + // We use negative height to indicate that the path is transposed. + (transposedInAtlas) ? -devIBounds.height() : devIBounds.height()} + , fAtlasXY{locationInAtlas.x(), locationInAtlas.y()} , fColor(color) , fViewMatrixIfUsingLocalCoords{m.getScaleX(), m.getSkewY(), m.getSkewX(), m.getScaleY(), m.getTranslateX(), m.getTranslateY()} { } - SkIRect fDevIBounds; - SkIVector fDevToAtlasOffset; + std::array<int, 4> fDevXYWH; + std::array<int, 2> fAtlasXY; SkPMColor4f fColor; float fViewMatrixIfUsingLocalCoords[6]; }; struct InstanceList { - InstanceList(const SkIRect& devIBounds, SkIVector devToAtlasOffset, - const SkPMColor4f& color, const SkMatrix& viewMatrix) - : fInstance(devIBounds, devToAtlasOffset, color, viewMatrix) { + InstanceList(const SkIRect& devIBounds, const SkIPoint16& locationInAtlas, + bool transposedInAtlas, const SkPMColor4f& color, const SkMatrix& viewMatrix) + : fInstance(devIBounds, locationInAtlas, transposedInAtlas, color, viewMatrix) { } InstanceList* fNext = nullptr; Instance fInstance; diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrFillPathShader.cpp b/chromium/third_party/skia/src/gpu/tessellate/GrFillPathShader.cpp index f87ac4a03ce..93e6e598d5f 100644 --- a/chromium/third_party/skia/src/gpu/tessellate/GrFillPathShader.cpp +++ b/chromium/third_party/skia/src/gpu/tessellate/GrFillPathShader.cpp @@ -26,11 +26,8 @@ public: args.fVertBuilder->codeAppend("float2 localcoord, vertexpos;"); shader.emitVertexCode(this, args.fVertBuilder, viewMatrix, args.fUniformHandler); - this->emitTransforms(args.fVertBuilder, args.fVaryingHandler, args.fUniformHandler, - GrShaderVar("localcoord", kFloat2_GrSLType), - args.fFPCoordTransformHandler); - gpArgs->fPositionVar.set(kFloat2_GrSLType, "vertexpos"); + gpArgs->fLocalCoordVar.set(kFloat2_GrSLType, "localcoord"); const char* color; fColorUniform = args.fUniformHandler->addUniform( @@ -53,7 +50,7 @@ public: pdman.set4f(fPathBoundsUniform, b.left(), b.top(), b.right(), b.bottom()); } - this->setTransformDataHelper(SkMatrix::I(), pdman, transformRange); + this->setTransformDataHelper(pdman, transformRange); } GrGLSLUniformHandler::UniformHandle fViewMatrixUniform; diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h b/chromium/third_party/skia/src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h index 258e175fdbb..482f2e3bb37 100644 --- a/chromium/third_party/skia/src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h +++ b/chromium/third_party/skia/src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h @@ -40,10 +40,12 @@ // recursion, we manipulate an O(log N) stack to determine the correct middle-out triangulation. class GrMiddleOutPolygonTriangulator { public: - GrMiddleOutPolygonTriangulator(SkPoint* vertexData, int maxVertices) - : fTriangleData(reinterpret_cast<std::array<SkPoint, 3>*>(vertexData)) { + GrMiddleOutPolygonTriangulator(SkPoint* vertexData, int perTriangleVertexAdvance, + int maxPushVertexCalls) + : fVertexData(vertexData) + , fPerTriangleVertexAdvance(perTriangleVertexAdvance) { // Determine the deepest our stack can ever go. - int maxStackDepth = SkNextLog2(maxVertices) + 1; + int maxStackDepth = SkNextLog2(maxPushVertexCalls) + 1; if (maxStackDepth > kStackPreallocCount) { fVertexStack.reset(maxStackDepth); } @@ -75,17 +77,15 @@ public: // (This is a stack-based implementation of the recursive example method from the class // comment.) while (vertexIdxDelta == fTop->fVertexIdxDelta) { - *fTriangleData++ = {fTop[-1].fPoint, fTop->fPoint, pt}; + this->popTopTriangle(pt); vertexIdxDelta *= 2; - this->popTop(); } - this->pushTop(); - *fTop = {vertexIdxDelta, pt}; + this->pushVertex(vertexIdxDelta, pt); } int close() { - if (fTop == &fVertexStack[0]) { // The stack only contains one point (the starting point). - return fTotalClosedVertexCount; + if (fTop == fVertexStack) { // The stack only contains one point (the starting point). + return fTotalClosedTriangleCount; } // We will count vertices by walking the stack backwards. int finalVertexCount = 1; @@ -94,24 +94,23 @@ public: // vertexIdxDeltas match. const SkPoint& p0 = fVertexStack[0].fPoint; SkASSERT(fTop->fPoint != p0); // We should have detected and handled this case earlier. - while (fTop > &fVertexStack[1]) { - *fTriangleData++ = {fTop[-1].fPoint, fTop->fPoint, p0}; + while (fTop - 1 > fVertexStack) { finalVertexCount += fTop->fVertexIdxDelta; - this->popTop(); + this->popTopTriangle(p0); } + SkASSERT(fTop == fVertexStack + 1); finalVertexCount += fTop->fVertexIdxDelta; - this->popTop(); - SkASSERT(fTop == &fVertexStack[0]); SkASSERT(fVertexStack[0].fVertexIdxDelta == 0); + fTop = fVertexStack; int numTriangles = finalVertexCount - 2; SkASSERT(numTriangles >= 0); - fTotalClosedVertexCount += numTriangles * 3; - return fTotalClosedVertexCount; + fTotalClosedTriangleCount += numTriangles; + return fTotalClosedTriangleCount; } void closeAndMove(const SkPoint& startPt) { this->close(); - SkASSERT(fTop == &fVertexStack[0]); // The stack should only contain a starting point now. + SkASSERT(fTop == fVertexStack); // The stack should only contain a starting point now. fTop->fPoint = startPt; // Modify the starting point. SkASSERT(fTop->fVertexIdxDelta == 0); // Ensure we are in the initial stack state. } @@ -129,23 +128,30 @@ private: SkPoint fPoint; }; - void pushTop() { + void pushVertex(int vertexIdxDelta, const SkPoint& point) { ++fTop; // We should never push deeper than fStackAllocCount. - SkASSERT(fTop < &fVertexStack[fStackAllocCount]); + SkASSERT(fTop < fVertexStack + fStackAllocCount); + fTop->fVertexIdxDelta = vertexIdxDelta; + fTop->fPoint = point; } - void popTop() { - SkASSERT(fTop > &fVertexStack[0]); // We should never pop the starting point. + void popTopTriangle(const SkPoint& lastPt) { + SkASSERT(fTop > fVertexStack); // We should never pop the starting point. --fTop; + fVertexData[0] = fTop[0].fPoint; + fVertexData[1] = fTop[1].fPoint; + fVertexData[2] = lastPt; + fVertexData += fPerTriangleVertexAdvance; } constexpr static int kStackPreallocCount = 32; SkAutoSTMalloc<kStackPreallocCount, StackVertex> fVertexStack; SkDEBUGCODE(int fStackAllocCount;) StackVertex* fTop; - std::array<SkPoint, 3>* fTriangleData; - int fTotalClosedVertexCount = 0; + SkPoint* fVertexData; + int fPerTriangleVertexAdvance; + int fTotalClosedTriangleCount = 0; }; #endif diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrResolveLevelCounter.h b/chromium/third_party/skia/src/gpu/tessellate/GrResolveLevelCounter.h new file mode 100644 index 00000000000..66b0540fea5 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/tessellate/GrResolveLevelCounter.h @@ -0,0 +1,73 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrResolveLevelCounter_DEFINED +#define GrResolveLevelCounter_DEFINED + +#include "src/core/SkPathPriv.h" +#include "src/gpu/tessellate/GrStencilPathShader.h" +#include "src/gpu/tessellate/GrWangsFormula.h" + +// This class helps bin cubics by log2 "resolveLevel" when we don't use hardware tessellation. It is +// composed of simple counters that track how many cubics we intend to draw at each resolveLevel, +// and how many resolveLevels there are that have at least one cubic. +class GrResolveLevelCounter { +public: + void reset() { + memset(fInstanceCounts, 0, sizeof(fInstanceCounts)); + SkDEBUGCODE(fHasCalledReset = true;) + } + + void reset(const SkPath& path, const SkMatrix& viewMatrix, float intolerance) { + this->reset(); + GrVectorXform xform(viewMatrix); + for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) { + switch (verb) { + case SkPathVerb::kQuad: + // Quadratics get converted to cubics before rendering. + this->countCubic(GrWangsFormula::quadratic_log2(intolerance, pts, xform)); + break; + case SkPathVerb::kCubic: + this->countCubic(GrWangsFormula::cubic_log2(intolerance, pts, xform)); + break; + default: + break; + } + } + } + + void countCubic(int resolveLevel) { + SkASSERT(fHasCalledReset); + SkASSERT(resolveLevel >= 0); + if (resolveLevel == 0) { + // Cubics with 2^0=1 segments are empty (zero area). We ignore them completely. + return; + } + resolveLevel = std::min(resolveLevel, GrMiddleOutCubicShader::kMaxResolveLevel); + if (!fInstanceCounts[resolveLevel]++) { + ++fTotalCubicIndirectDrawCount; + } + ++fTotalCubicInstanceCount; + } + + int operator[](int resolveLevel) const { + SkASSERT(fHasCalledReset); + SkASSERT(resolveLevel > 0); // Empty cubics with 2^0=1 segments do not need to be drawn. + SkASSERT(resolveLevel <= GrMiddleOutCubicShader::kMaxResolveLevel); + return fInstanceCounts[resolveLevel]; + } + int totalCubicInstanceCount() const { return fTotalCubicInstanceCount; } + int totalCubicIndirectDrawCount() const { return fTotalCubicIndirectDrawCount; } + +private: + SkDEBUGCODE(bool fHasCalledReset = false;) + int fInstanceCounts[GrMiddleOutCubicShader::kMaxResolveLevel + 1]; + int fTotalCubicInstanceCount = 0; + int fTotalCubicIndirectDrawCount = 0; +}; + +#endif diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrStencilPathShader.cpp b/chromium/third_party/skia/src/gpu/tessellate/GrStencilPathShader.cpp index 9b36c2ac582..c6e95ef9027 100644 --- a/chromium/third_party/skia/src/gpu/tessellate/GrStencilPathShader.cpp +++ b/chromium/third_party/skia/src/gpu/tessellate/GrStencilPathShader.cpp @@ -35,6 +35,7 @@ constexpr char kEvalCubicFn[] = R"( })"; class GrStencilPathShader::Impl : public GrGLSLGeometryProcessor { +protected: void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { const auto& shader = args.fGP.cast<GrStencilPathShader>(); args.fVaryingHandler->emitAttributes(shader); @@ -45,7 +46,7 @@ class GrStencilPathShader::Impl : public GrGLSLGeometryProcessor { fViewMatrixUniform = args.fUniformHandler->addUniform( nullptr, kVertex_GrShaderFlag, kFloat3x3_GrSLType, "view_matrix", &viewMatrix); args.fVertBuilder->codeAppendf( - "float2 vertexpos = (%s * float3(point, 1)).xy;", viewMatrix); + "float2 vertexpos = (%s * float3(inputPoint, 1)).xy;", viewMatrix); vertexPos.set(kFloat2_GrSLType, "vertexpos"); } @@ -75,8 +76,10 @@ GrGLSLPrimitiveProcessor* GrStencilPathShader::createGLSLInstance(const GrShader return new Impl; } -SkString GrStencilCubicShader::getTessControlShaderGLSL(const char* versionAndExtensionDecls, - const GrShaderCaps&) const { +SkString GrTessellateCubicShader::getTessControlShaderGLSL(const GrGLSLPrimitiveProcessor*, + const char* versionAndExtensionDecls, + const GrGLSLUniformHandler&, + const GrShaderCaps&) const { SkString code(versionAndExtensionDecls); code.append(kWangsFormulaCubicFn); code.append(R"( @@ -115,8 +118,9 @@ SkString GrStencilCubicShader::getTessControlShaderGLSL(const char* versionAndEx return code; } -SkString GrStencilCubicShader::getTessEvaluationShaderGLSL(const char* versionAndExtensionDecls, - const GrShaderCaps&) const { +SkString GrTessellateCubicShader::getTessEvaluationShaderGLSL( + const GrGLSLPrimitiveProcessor*, const char* versionAndExtensionDecls, + const GrGLSLUniformHandler&, const GrShaderCaps&) const { SkString code(versionAndExtensionDecls); code.append(kEvalCubicFn); code.append(R"( @@ -147,8 +151,10 @@ SkString GrStencilCubicShader::getTessEvaluationShaderGLSL(const char* versionAn return code; } -SkString GrStencilWedgeShader::getTessControlShaderGLSL(const char* versionAndExtensionDecls, - const GrShaderCaps&) const { +SkString GrTessellateWedgeShader::getTessControlShaderGLSL(const GrGLSLPrimitiveProcessor*, + const char* versionAndExtensionDecls, + const GrGLSLUniformHandler&, + const GrShaderCaps&) const { SkString code(versionAndExtensionDecls); code.append(kWangsFormulaCubicFn); code.append(R"( @@ -183,8 +189,9 @@ SkString GrStencilWedgeShader::getTessControlShaderGLSL(const char* versionAndEx return code; } -SkString GrStencilWedgeShader::getTessEvaluationShaderGLSL(const char* versionAndExtensionDecls, - const GrShaderCaps&) const { +SkString GrTessellateWedgeShader::getTessEvaluationShaderGLSL( + const GrGLSLPrimitiveProcessor*, const char* versionAndExtensionDecls, + const GrGLSLUniformHandler&, const GrShaderCaps&) const { SkString code(versionAndExtensionDecls); code.append(kEvalCubicFn); code.append(R"( @@ -218,3 +225,109 @@ SkString GrStencilWedgeShader::getTessEvaluationShaderGLSL(const char* versionAn return code; } + +GR_DECLARE_STATIC_UNIQUE_KEY(gMiddleOutIndexBufferKey); + +sk_sp<const GrGpuBuffer> GrMiddleOutCubicShader::FindOrMakeMiddleOutIndexBuffer( + GrResourceProvider* resourceProvider) { + GR_DEFINE_STATIC_UNIQUE_KEY(gMiddleOutIndexBufferKey); + if (auto buffer = resourceProvider->findByUniqueKey<GrGpuBuffer>(gMiddleOutIndexBufferKey)) { + return std::move(buffer); + } + + // One explicit triangle at index 0, and one middle-out cubic with kMaxResolveLevel line + // segments beginning at index 3. + constexpr static int kIndexCount = 3 + NumVerticesAtResolveLevel(kMaxResolveLevel); + auto buffer = resourceProvider->createBuffer( + kIndexCount * sizeof(uint16_t), GrGpuBufferType::kIndex, kStatic_GrAccessPattern); + if (!buffer) { + return nullptr; + } + + // We shouldn't bin and/or cache static buffers. + SkASSERT(buffer->size() == kIndexCount * sizeof(uint16_t)); + SkASSERT(!buffer->resourcePriv().getScratchKey().isValid()); + auto indexData = static_cast<uint16_t*>(buffer->map()); + SkAutoTMalloc<uint16_t> stagingBuffer; + if (!indexData) { + SkASSERT(!buffer->isMapped()); + indexData = stagingBuffer.reset(kIndexCount); + } + + // Indices 0,1,2 contain special values that emit points P0, P1, and P2 respectively. (When the + // vertex shader is fed an index value larger than (1 << kMaxResolveLevel), it emits + // P[index % 4].) + int i = 0; + indexData[i++] = (1 << kMaxResolveLevel) + 4; // % 4 == 0 + indexData[i++] = (1 << kMaxResolveLevel) + 5; // % 4 == 1 + indexData[i++] = (1 << kMaxResolveLevel) + 6; // % 4 == 2 + + // Starting at index 3, we triangulate a cubic with 2^kMaxResolveLevel line segments. Each + // index value corresponds to parametric value T=(index / 2^kMaxResolveLevel). Since the + // triangles are arranged in "middle-out" order, we will be able to conveniently control the + // resolveLevel by changing only the indexCount. + for (uint16_t advance = 1 << (kMaxResolveLevel - 1); advance; advance >>= 1) { + uint16_t T = 0; + do { + indexData[i++] = T; + indexData[i++] = (T += advance); + indexData[i++] = (T += advance); + } while (T != (1 << kMaxResolveLevel)); + } + SkASSERT(i == kIndexCount); + + if (buffer->isMapped()) { + buffer->unmap(); + } else { + buffer->updateData(stagingBuffer, kIndexCount * sizeof(uint16_t)); + } + buffer->resourcePriv().setUniqueKey(gMiddleOutIndexBufferKey); + return std::move(buffer); +} + +class GrMiddleOutCubicShader::Impl : public GrStencilPathShader::Impl { + void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override { + const auto& shader = args.fGP.cast<GrMiddleOutCubicShader>(); + args.fVaryingHandler->emitAttributes(shader); + args.fVertBuilder->defineConstant("kMaxResolveLevel", kMaxResolveLevel); + args.fVertBuilder->codeAppend(R"( + float4x2 P = float4x2(inputPoints_0_1, inputPoints_2_3); + float2 point; + if (sk_VertexID > (1 << kMaxResolveLevel)) { + // This is a special index value that wants us to emit a specific point. + point = P[sk_VertexID & 3]; + } else {)"); + // Evaluate the cubic at T=(sk_VertexID / 2^kMaxResolveLevel). + if (args.fShaderCaps->fpManipulationSupport()) { + args.fVertBuilder->codeAppend(R"( + float T = ldexp(sk_VertexID, -kMaxResolveLevel);)"); + } else { + args.fVertBuilder->codeAppend(R"( + float T = sk_VertexID / float(1 << kMaxResolveLevel);)"); + } + args.fVertBuilder->codeAppend(R"( + float2 ab = mix(P[0], P[1], T); + float2 bc = mix(P[1], P[2], T); + float2 cd = mix(P[2], P[3], T); + float2 abc = mix(ab, bc, T); + float2 bcd = mix(bc, cd, T); + point = mix(abc, bcd, T); + })"); + + GrShaderVar vertexPos("point", kFloat2_GrSLType); + if (!shader.viewMatrix().isIdentity()) { + const char* viewMatrix; + fViewMatrixUniform = args.fUniformHandler->addUniform( + nullptr, kVertex_GrShaderFlag, kFloat3x3_GrSLType, "view_matrix", &viewMatrix); + args.fVertBuilder->codeAppendf(R"( + float2 transformedPoint = (%s * float3(point, 1)).xy;)", viewMatrix); + vertexPos.set(kFloat2_GrSLType, "transformedPoint"); + } + gpArgs->fPositionVar = vertexPos; + // No fragment shader. + } +}; + +GrGLSLPrimitiveProcessor* GrMiddleOutCubicShader::createGLSLInstance(const GrShaderCaps&) const { + return new Impl; +} diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrStencilPathShader.h b/chromium/third_party/skia/src/gpu/tessellate/GrStencilPathShader.h index 0aa0b5983b4..c098f76a8d5 100644 --- a/chromium/third_party/skia/src/gpu/tessellate/GrStencilPathShader.h +++ b/chromium/third_party/skia/src/gpu/tessellate/GrStencilPathShader.h @@ -9,6 +9,7 @@ #define GrStencilPathShader_DEFINED #include "src/gpu/tessellate/GrPathShader.h" +#include "src/gpu/tessellate/GrTessellationPathRenderer.h" // This is the base class for shaders that stencil path elements, namely, triangles, standalone // cubics, and wedges. @@ -17,16 +18,15 @@ public: GrStencilPathShader(ClassID classID, const SkMatrix& viewMatrix, GrPrimitiveType primitiveType, int tessellationPatchVertexCount = 0) : GrPathShader(classID, viewMatrix, primitiveType, tessellationPatchVertexCount) { - constexpr static Attribute kPointAttrib = { - "point", kFloat2_GrVertexAttribType, kFloat2_GrSLType}; - this->setVertexAttributes(&kPointAttrib, 1); } -private: - void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const final { +protected: + constexpr static Attribute kSinglePointAttrib{"inputPoint", kFloat2_GrVertexAttribType, + kFloat2_GrSLType}; + void getGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override { b->add32(this->viewMatrix().isIdentity()); } - GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const final; + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; class Impl; }; @@ -35,23 +35,30 @@ private: class GrStencilTriangleShader : public GrStencilPathShader { public: GrStencilTriangleShader(const SkMatrix& viewMatrix) : GrStencilPathShader( - kTessellate_GrStencilTriangleShader_ClassID, viewMatrix, GrPrimitiveType::kTriangles) {} + kTessellate_GrStencilTriangleShader_ClassID, viewMatrix, GrPrimitiveType::kTriangles) { + this->setVertexAttributes(&kSinglePointAttrib, 1); + } const char* name() const override { return "tessellate_GrStencilTriangleShader"; } }; -// Uses GPU tessellation shaders to linearize, triangulate, and render standalone cubics. Here, a -// "cubic" is a standalone closed contour consisting of a single cubic bezier. +// Uses GPU tessellation shaders to linearize, triangulate, and render standalone closed cubics. // TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics. -class GrStencilCubicShader : public GrStencilPathShader { +class GrTessellateCubicShader : public GrStencilPathShader { public: - GrStencilCubicShader(const SkMatrix& viewMatrix) : GrStencilPathShader( - kTessellate_GrStencilCubicShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 4) {} - const char* name() const override { return "tessellate_GrStencilCubicShader"; } + GrTessellateCubicShader(const SkMatrix& viewMatrix) : GrStencilPathShader( + kTessellate_GrTessellateCubicShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 4) { + this->setVertexAttributes(&kSinglePointAttrib, 1); + } + const char* name() const override { return "tessellate_GrTessellateCubicShader"; } private: - SkString getTessControlShaderGLSL(const char* versionAndExtensionDecls, + SkString getTessControlShaderGLSL(const GrGLSLPrimitiveProcessor*, + const char* versionAndExtensionDecls, + const GrGLSLUniformHandler&, const GrShaderCaps&) const override; - SkString getTessEvaluationShaderGLSL(const char* versionAndExtensionDecls, + SkString getTessEvaluationShaderGLSL(const GrGLSLPrimitiveProcessor*, + const char* versionAndExtensionDecls, + const GrGLSLUniformHandler&, const GrShaderCaps&) const override; }; @@ -59,17 +66,88 @@ private: // wedge is a 5-point patch consisting of 4 cubic control points, plus an anchor point fanning from // the center of the curve's resident contour. // TODO: Eventually we want to use rational cubic wedges in order to support perspective and conics. -class GrStencilWedgeShader : public GrStencilPathShader { +class GrTessellateWedgeShader : public GrStencilPathShader { public: - GrStencilWedgeShader(const SkMatrix& viewMatrix) : GrStencilPathShader( - kTessellate_GrStencilWedgeShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 5) {} - const char* name() const override { return "tessellate_GrStencilWedgeShader"; } + GrTessellateWedgeShader(const SkMatrix& viewMatrix) : GrStencilPathShader( + kTessellate_GrTessellateWedgeShader_ClassID, viewMatrix, GrPrimitiveType::kPatches, 5) { + this->setVertexAttributes(&kSinglePointAttrib, 1); + } + const char* name() const override { return "tessellate_GrTessellateWedgeShader"; } private: - SkString getTessControlShaderGLSL(const char* versionAndExtensionDecls, + SkString getTessControlShaderGLSL(const GrGLSLPrimitiveProcessor*, + const char* versionAndExtensionDecls, + const GrGLSLUniformHandler&, const GrShaderCaps&) const override; - SkString getTessEvaluationShaderGLSL(const char* versionAndExtensionDecls, + SkString getTessEvaluationShaderGLSL(const GrGLSLPrimitiveProcessor*, + const char* versionAndExtensionDecls, + const GrGLSLUniformHandler&, const GrShaderCaps&) const override; }; +// Uses indirect (instanced) draws to triangulate standalone closed cubics with a "middle-out" +// topology. The caller must compute each cubic's resolveLevel on the CPU (i.e., the log2 number of +// line segments it will be divided into; see GrWangsFormula::cubic_log2/quadratic_log2), and then +// sort the instance buffer by resolveLevel for efficient batching of indirect draws. +class GrMiddleOutCubicShader : public GrStencilPathShader { +public: + // Each resolveLevel linearizes the curve into 2^resolveLevel line segments. The finest + // supported resolveLevel is therefore 2^12=4096 line segments. + constexpr static int kMaxResolveLevel = GrTessellationPathRenderer::kMaxResolveLevel; + + // How many vertices do we need to draw in order to triangulate a cubic with 2^resolveLevel + // line segments? + constexpr static int NumVerticesAtResolveLevel(int resolveLevel) { + // resolveLevel=0 -> 0 line segments -> 0 triangles -> 0 vertices + // resolveLevel=1 -> 2 line segments -> 1 triangle -> 3 vertices + // resolveLevel=2 -> 4 line segments -> 3 triangles -> 9 vertices + // resolveLevel=3 -> 8 line segments -> 7 triangles -> 21 vertices + // ... + return ((1 << resolveLevel) - 1) * 3; + } + + // Configures an indirect draw to render cubic instances with 2^resolveLevel evenly-spaced (in + // the parametric sense) line segments. + static GrDrawIndexedIndirectCommand MakeDrawCubicsIndirectCmd(int resolveLevel, + uint32_t instanceCount, + uint32_t baseInstance) { + SkASSERT(resolveLevel > 0 && resolveLevel <= kMaxResolveLevel); + // Starting at baseIndex=3, the index buffer triangulates a cubic with 2^kMaxResolveLevel + // line segments. Each index value corresponds to a parametric T value on the curve. Since + // the triangles are arranged in "middle-out" order, we can conveniently control the + // resolveLevel by changing only the indexCount. + uint32_t indexCount = NumVerticesAtResolveLevel(resolveLevel); + return {indexCount, instanceCount, 3, 0, baseInstance}; + } + + // For performance reasons we can often express triangles as an indirect cubic draw and sneak + // them in alongside the other indirect draws. This method configures an indirect draw to emit + // the triangle [P0, P1, P2] from a 4-point instance. + static GrDrawIndexedIndirectCommand MakeDrawTrianglesIndirectCmd(uint32_t instanceCount, + uint32_t baseInstance) { + // Indices 0,1,2 have special index values that emit points P0, P1, and P2 respectively. + return {3, instanceCount, 0, 0, baseInstance}; + } + + // Returns the index buffer that should be bound when drawing with this shader. + // (Our vertex shader uses raw index values directly, so there is no vertex buffer.) + static sk_sp<const GrGpuBuffer> FindOrMakeMiddleOutIndexBuffer(GrResourceProvider*); + + GrMiddleOutCubicShader(const SkMatrix& viewMatrix) + : GrStencilPathShader(kTessellate_GrMiddleOutCubicShader_ClassID, viewMatrix, + GrPrimitiveType::kTriangles) { + constexpr static Attribute kInputPtsAttribs[] = { + {"inputPoints_0_1", kFloat4_GrVertexAttribType, kFloat4_GrSLType}, + {"inputPoints_2_3", kFloat4_GrVertexAttribType, kFloat4_GrSLType}}; + this->setInstanceAttributes(kInputPtsAttribs, 2); + } + + const char* name() const override { return "tessellate_GrMiddleOutCubicShader"; } + +private: + GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override; + + class Impl; +}; + #endif diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrStrokeGeometry.cpp b/chromium/third_party/skia/src/gpu/tessellate/GrStrokeGeometry.cpp new file mode 100644 index 00000000000..b097c73a2d5 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/tessellate/GrStrokeGeometry.cpp @@ -0,0 +1,583 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/gpu/tessellate/GrStrokeGeometry.h" + +#include "include/core/SkStrokeRec.h" +#include "include/private/SkNx.h" +#include "src/core/SkGeometry.h" +#include "src/core/SkMathPriv.h" + +// This is the maximum distance in pixels that we can stray from the edge of a stroke when +// converting it to flat line segments. +static constexpr float kMaxErrorFromLinearization = 1/8.f; + +static inline float length(const Sk2f& n) { + Sk2f nn = n*n; + return SkScalarSqrt(nn[0] + nn[1]); +} + +static inline Sk2f normalize(const Sk2f& v) { + Sk2f vv = v*v; + vv += SkNx_shuffle<1,0>(vv); + return v * vv.rsqrt(); +} + +static inline void transpose(const Sk2f& a, const Sk2f& b, Sk2f* X, Sk2f* Y) { + float transpose[4]; + a.store(transpose); + b.store(transpose+2); + Sk2f::Load2(transpose, X, Y); +} + +static inline void normalize2(const Sk2f& v0, const Sk2f& v1, SkPoint out[2]) { + Sk2f X, Y; + transpose(v0, v1, &X, &Y); + Sk2f invlength = (X*X + Y*Y).rsqrt(); + Sk2f::Store2(out, Y * invlength, -X * invlength); +} + +static inline float calc_curvature_costheta(const Sk2f& leftTan, const Sk2f& rightTan) { + Sk2f X, Y; + transpose(leftTan, rightTan, &X, &Y); + Sk2f invlength = (X*X + Y*Y).rsqrt(); + Sk2f dotprod = leftTan * rightTan; + return (dotprod[0] + dotprod[1]) * invlength[0] * invlength[1]; +} + +static GrStrokeGeometry::Verb join_verb_from_join(SkPaint::Join join) { + using Verb = GrStrokeGeometry::Verb; + switch (join) { + case SkPaint::kBevel_Join: + return Verb::kBevelJoin; + case SkPaint::kMiter_Join: + return Verb::kMiterJoin; + case SkPaint::kRound_Join: + return Verb::kRoundJoin; + } + SK_ABORT("Invalid SkPaint::Join."); +} + +void GrStrokeGeometry::beginPath(const SkStrokeRec& stroke, float strokeDevWidth, + InstanceTallies* tallies) { + SkASSERT(!fInsideContour); + // Client should have already converted the stroke to device space (i.e. width=1 for hairline). + SkASSERT(strokeDevWidth > 0); + + fCurrStrokeRadius = strokeDevWidth/2; + fCurrStrokeJoinVerb = join_verb_from_join(stroke.getJoin()); + fCurrStrokeCapType = stroke.getCap(); + fCurrStrokeTallies = tallies; + + if (Verb::kMiterJoin == fCurrStrokeJoinVerb) { + // We implement miters by placing a triangle-shaped cap on top of a bevel join. Convert the + // "miter limit" to how tall that triangle cap can be. + float m = stroke.getMiter(); + fMiterMaxCapHeightOverWidth = .5f * SkScalarSqrt(m*m - 1); + } + + // Find the angle of curvature where the arc height above a simple line from point A to point B + // is equal to kMaxErrorFromLinearization. + float r = std::max(1 - kMaxErrorFromLinearization / fCurrStrokeRadius, 0.f); + fMaxCurvatureCosTheta = 2*r*r - 1; + + fCurrContourFirstPtIdx = -1; + fCurrContourFirstNormalIdx = -1; + + fVerbs.push_back(Verb::kBeginPath); +} + +void GrStrokeGeometry::moveTo(SkPoint pt) { + SkASSERT(!fInsideContour); + fCurrContourFirstPtIdx = fPoints.count(); + fCurrContourFirstNormalIdx = fNormals.count(); + fPoints.push_back(pt); + SkDEBUGCODE(fInsideContour = true); +} + +void GrStrokeGeometry::lineTo(SkPoint pt) { + SkASSERT(fInsideContour); + this->lineTo(fCurrStrokeJoinVerb, pt); +} + +void GrStrokeGeometry::lineTo(Verb leftJoinVerb, SkPoint pt) { + Sk2f tan = Sk2f::Load(&pt) - Sk2f::Load(&fPoints.back()); + if ((tan == 0).allTrue()) { + return; + } + + tan = normalize(tan); + SkVector n = SkVector::Make(tan[1], -tan[0]); + + this->recordLeftJoinIfNotEmpty(leftJoinVerb, n); + fNormals.push_back(n); + + this->recordStroke(Verb::kLinearStroke, 0); + fPoints.push_back(pt); +} + +void GrStrokeGeometry::quadraticTo(const SkPoint P[3]) { + SkASSERT(fInsideContour); + this->quadraticTo(fCurrStrokeJoinVerb, P, SkFindQuadMaxCurvature(P)); +} + +// Wang's formula for quadratics (1985) gives us the number of evenly spaced (in the parametric +// sense) line segments that are guaranteed to be within a distance of "kMaxErrorFromLinearization" +// from the actual curve. +static inline float wangs_formula_quadratic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2) { + static constexpr float k = 2 / (8 * kMaxErrorFromLinearization); + float f = SkScalarSqrt(k * length(p2 - p1*2 + p0)); + return SkScalarCeilToInt(f); +} + +void GrStrokeGeometry::quadraticTo(Verb leftJoinVerb, const SkPoint P[3], float maxCurvatureT) { + Sk2f p0 = Sk2f::Load(P); + Sk2f p1 = Sk2f::Load(P+1); + Sk2f p2 = Sk2f::Load(P+2); + + Sk2f tan0 = p1 - p0; + Sk2f tan1 = p2 - p1; + + // Snap to a "lineTo" if the control point is so close to an endpoint that FP error will become + // an issue. + if ((tan0.abs() < SK_ScalarNearlyZero).allTrue() || // p0 ~= p1 + (tan1.abs() < SK_ScalarNearlyZero).allTrue()) { // p1 ~= p2 + this->lineTo(leftJoinVerb, P[2]); + return; + } + + SkPoint normals[2]; + normalize2(tan0, tan1, normals); + + // Decide how many flat line segments to chop the curve into. + int numSegments = wangs_formula_quadratic(p0, p1, p2); + numSegments = std::min(numSegments, 1 << kMaxNumLinearSegmentsLog2); + if (numSegments <= 1) { + this->rotateTo(leftJoinVerb, normals[0]); + this->lineTo(Verb::kInternalRoundJoin, P[2]); + this->rotateTo(Verb::kInternalRoundJoin, normals[1]); + return; + } + + // At + B gives a vector tangent to the quadratic. + Sk2f A = p0 - p1*2 + p2; + Sk2f B = p1 - p0; + + // Find a line segment that crosses max curvature. + float segmentLength = SkScalarInvert(numSegments); + float leftT = maxCurvatureT - segmentLength/2; + float rightT = maxCurvatureT + segmentLength/2; + Sk2f leftTan, rightTan; + if (leftT <= 0) { + leftT = 0; + leftTan = tan0; + rightT = segmentLength; + rightTan = A*rightT + B; + } else if (rightT >= 1) { + leftT = 1 - segmentLength; + leftTan = A*leftT + B; + rightT = 1; + rightTan = tan1; + } else { + leftTan = A*leftT + B; + rightTan = A*rightT + B; + } + + // Check if curvature is too strong for a triangle strip on the line segment that crosses max + // curvature. If it is, we will chop and convert the segment to a "lineTo" with round joins. + // + // FIXME: This is quite costly and the vast majority of curves only have moderate curvature. We + // would benefit significantly from a quick reject that detects curves that don't need special + // treatment for strong curvature. + bool isCurvatureTooStrong = calc_curvature_costheta(leftTan, rightTan) < fMaxCurvatureCosTheta; + if (isCurvatureTooStrong) { + SkPoint ptsBuffer[5]; + const SkPoint* currQuadratic = P; + + if (leftT > 0) { + SkChopQuadAt(currQuadratic, ptsBuffer, leftT); + this->quadraticTo(leftJoinVerb, ptsBuffer, /*maxCurvatureT=*/1); + if (rightT < 1) { + rightT = (rightT - leftT) / (1 - leftT); + } + currQuadratic = ptsBuffer + 2; + } else { + this->rotateTo(leftJoinVerb, normals[0]); + } + + if (rightT < 1) { + SkChopQuadAt(currQuadratic, ptsBuffer, rightT); + this->lineTo(Verb::kInternalRoundJoin, ptsBuffer[2]); + this->quadraticTo(Verb::kInternalRoundJoin, ptsBuffer + 2, /*maxCurvatureT=*/0); + } else { + this->lineTo(Verb::kInternalRoundJoin, currQuadratic[2]); + this->rotateTo(Verb::kInternalRoundJoin, normals[1]); + } + return; + } + + this->recordLeftJoinIfNotEmpty(leftJoinVerb, normals[0]); + fNormals.push_back_n(2, normals); + + this->recordStroke(Verb::kQuadraticStroke, SkNextLog2(numSegments)); + p1.store(&fPoints.push_back()); + p2.store(&fPoints.push_back()); +} + +void GrStrokeGeometry::cubicTo(const SkPoint P[4]) { + SkASSERT(fInsideContour); + float roots[3]; + int numRoots = SkFindCubicMaxCurvature(P, roots); + this->cubicTo(fCurrStrokeJoinVerb, P, + numRoots > 0 ? roots[numRoots/2] : 0, + numRoots > 1 ? roots[0] : kLeftMaxCurvatureNone, + numRoots > 2 ? roots[2] : kRightMaxCurvatureNone); +} + +// Wang's formula for cubics (1985) gives us the number of evenly spaced (in the parametric sense) +// line segments that are guaranteed to be within a distance of "kMaxErrorFromLinearization" +// from the actual curve. +static inline float wangs_formula_cubic(const Sk2f& p0, const Sk2f& p1, const Sk2f& p2, + const Sk2f& p3) { + static constexpr float k = (3 * 2) / (8 * kMaxErrorFromLinearization); + float f = SkScalarSqrt(k * length(Sk2f::Max((p2 - p1*2 + p0).abs(), + (p3 - p2*2 + p1).abs()))); + return SkScalarCeilToInt(f); +} + +void GrStrokeGeometry::cubicTo(Verb leftJoinVerb, const SkPoint P[4], float maxCurvatureT, + float leftMaxCurvatureT, float rightMaxCurvatureT) { + Sk2f p0 = Sk2f::Load(P); + Sk2f p1 = Sk2f::Load(P+1); + Sk2f p2 = Sk2f::Load(P+2); + Sk2f p3 = Sk2f::Load(P+3); + + Sk2f tan0 = p1 - p0; + Sk2f tan1 = p3 - p2; + + // Snap control points to endpoints if they are so close that FP error will become an issue. + if ((tan0.abs() < SK_ScalarNearlyZero).allTrue()) { // p0 ~= p1 + p1 = p0; + tan0 = p2 - p0; + if ((tan0.abs() < SK_ScalarNearlyZero).allTrue()) { // p0 ~= p1 ~= p2 + this->lineTo(leftJoinVerb, P[3]); + return; + } + } + if ((tan1.abs() < SK_ScalarNearlyZero).allTrue()) { // p2 ~= p3 + p2 = p3; + tan1 = p3 - p1; + if ((tan1.abs() < SK_ScalarNearlyZero).allTrue() || // p1 ~= p2 ~= p3 + (p0 == p1).allTrue()) { // p0 ~= p1 AND p2 ~= p3 + this->lineTo(leftJoinVerb, P[3]); + return; + } + } + + SkPoint normals[2]; + normalize2(tan0, tan1, normals); + + // Decide how many flat line segments to chop the curve into. + int numSegments = wangs_formula_cubic(p0, p1, p2, p3); + numSegments = std::min(numSegments, 1 << kMaxNumLinearSegmentsLog2); + if (numSegments <= 1) { + this->rotateTo(leftJoinVerb, normals[0]); + this->lineTo(leftJoinVerb, P[3]); + this->rotateTo(Verb::kInternalRoundJoin, normals[1]); + return; + } + + // At^2 + Bt + C gives a vector tangent to the cubic. (More specifically, it's the derivative + // minus an irrelevant scale by 3, since all we care about is the direction.) + Sk2f A = p3 + (p1 - p2)*3 - p0; + Sk2f B = (p0 - p1*2 + p2)*2; + Sk2f C = p1 - p0; + + // Find a line segment that crosses max curvature. + float segmentLength = SkScalarInvert(numSegments); + float leftT = maxCurvatureT - segmentLength/2; + float rightT = maxCurvatureT + segmentLength/2; + Sk2f leftTan, rightTan; + if (leftT <= 0) { + leftT = 0; + leftTan = tan0; + rightT = segmentLength; + rightTan = A*rightT*rightT + B*rightT + C; + } else if (rightT >= 1) { + leftT = 1 - segmentLength; + leftTan = A*leftT*leftT + B*leftT + C; + rightT = 1; + rightTan = tan1; + } else { + leftTan = A*leftT*leftT + B*leftT + C; + rightTan = A*rightT*rightT + B*rightT + C; + } + + // Check if curvature is too strong for a triangle strip on the line segment that crosses max + // curvature. If it is, we will chop and convert the segment to a "lineTo" with round joins. + // + // FIXME: This is quite costly and the vast majority of curves only have moderate curvature. We + // would benefit significantly from a quick reject that detects curves that don't need special + // treatment for strong curvature. + bool isCurvatureTooStrong = calc_curvature_costheta(leftTan, rightTan) < fMaxCurvatureCosTheta; + if (isCurvatureTooStrong) { + SkPoint ptsBuffer[7]; + p0.store(ptsBuffer); + p1.store(ptsBuffer + 1); + p2.store(ptsBuffer + 2); + p3.store(ptsBuffer + 3); + const SkPoint* currCubic = ptsBuffer; + + if (leftT > 0) { + SkChopCubicAt(currCubic, ptsBuffer, leftT); + this->cubicTo(leftJoinVerb, ptsBuffer, /*maxCurvatureT=*/1, + (kLeftMaxCurvatureNone != leftMaxCurvatureT) + ? leftMaxCurvatureT/leftT : kLeftMaxCurvatureNone, + kRightMaxCurvatureNone); + if (rightT < 1) { + rightT = (rightT - leftT) / (1 - leftT); + } + if (rightMaxCurvatureT < 1 && kRightMaxCurvatureNone != rightMaxCurvatureT) { + rightMaxCurvatureT = (rightMaxCurvatureT - leftT) / (1 - leftT); + } + currCubic = ptsBuffer + 3; + } else { + this->rotateTo(leftJoinVerb, normals[0]); + } + + if (rightT < 1) { + SkChopCubicAt(currCubic, ptsBuffer, rightT); + this->lineTo(Verb::kInternalRoundJoin, ptsBuffer[3]); + currCubic = ptsBuffer + 3; + this->cubicTo(Verb::kInternalRoundJoin, currCubic, /*maxCurvatureT=*/0, + kLeftMaxCurvatureNone, kRightMaxCurvatureNone); + } else { + this->lineTo(Verb::kInternalRoundJoin, currCubic[3]); + this->rotateTo(Verb::kInternalRoundJoin, normals[1]); + } + return; + } + + // Recurse and check the other two points of max curvature, if any. + if (kRightMaxCurvatureNone != rightMaxCurvatureT) { + this->cubicTo(leftJoinVerb, P, rightMaxCurvatureT, leftMaxCurvatureT, + kRightMaxCurvatureNone); + return; + } + if (kLeftMaxCurvatureNone != leftMaxCurvatureT) { + SkASSERT(kRightMaxCurvatureNone == rightMaxCurvatureT); + this->cubicTo(leftJoinVerb, P, leftMaxCurvatureT, kLeftMaxCurvatureNone, + kRightMaxCurvatureNone); + return; + } + + this->recordLeftJoinIfNotEmpty(leftJoinVerb, normals[0]); + fNormals.push_back_n(2, normals); + + this->recordStroke(Verb::kCubicStroke, SkNextLog2(numSegments)); + p1.store(&fPoints.push_back()); + p2.store(&fPoints.push_back()); + p3.store(&fPoints.push_back()); +} + +void GrStrokeGeometry::recordStroke(Verb verb, int numSegmentsLog2) { + SkASSERT(Verb::kLinearStroke != verb || 0 == numSegmentsLog2); + SkASSERT(numSegmentsLog2 <= kMaxNumLinearSegmentsLog2); + fVerbs.push_back(verb); + if (Verb::kLinearStroke != verb) { + SkASSERT(numSegmentsLog2 > 0); + fParams.push_back().fNumLinearSegmentsLog2 = numSegmentsLog2; + } + ++fCurrStrokeTallies->fStrokes[numSegmentsLog2]; +} + +void GrStrokeGeometry::rotateTo(Verb leftJoinVerb, SkVector normal) { + this->recordLeftJoinIfNotEmpty(leftJoinVerb, normal); + fNormals.push_back(normal); +} + +void GrStrokeGeometry::recordLeftJoinIfNotEmpty(Verb joinVerb, SkVector nextNormal) { + if (fNormals.count() <= fCurrContourFirstNormalIdx) { + // The contour is empty. Nothing to join with. + SkASSERT(fNormals.count() == fCurrContourFirstNormalIdx); + return; + } + + if (Verb::kBevelJoin == joinVerb) { + this->recordBevelJoin(Verb::kBevelJoin); + return; + } + + Sk2f n0 = Sk2f::Load(&fNormals.back()); + Sk2f n1 = Sk2f::Load(&nextNormal); + Sk2f base = n1 - n0; + if ((base.abs() * fCurrStrokeRadius < kMaxErrorFromLinearization).allTrue()) { + // Treat any join as a bevel when the outside corners of the two adjoining strokes are + // close enough to each other. This is important because "miterCapHeightOverWidth" becomes + // unstable when n0 and n1 are nearly equal. + this->recordBevelJoin(joinVerb); + return; + } + + // We implement miters and round joins by placing a triangle-shaped cap on top of a bevel join. + // (For round joins this triangle cap comprises the conic control points.) Find how tall to make + // this triangle cap, relative to its width. + // + // NOTE: This value would be infinite at 180 degrees, but we clamp miterCapHeightOverWidth at + // near-infinity. 180-degree round joins still look perfectly acceptable like this (though + // technically not pure arcs). + Sk2f cross = base * SkNx_shuffle<1,0>(n0); + Sk2f dot = base * n0; + float miterCapHeight = SkScalarAbs(dot[0] + dot[1]); + float miterCapWidth = SkScalarAbs(cross[0] - cross[1]) * 2; + + if (Verb::kMiterJoin == joinVerb) { + if (miterCapHeight > fMiterMaxCapHeightOverWidth * miterCapWidth) { + // This join is tighter than the miter limit. Treat it as a bevel. + this->recordBevelJoin(Verb::kMiterJoin); + return; + } + this->recordMiterJoin(miterCapHeight / miterCapWidth); + return; + } + + SkASSERT(Verb::kRoundJoin == joinVerb || Verb::kInternalRoundJoin == joinVerb); + + // Conic arcs become unstable when they approach 180 degrees. When the conic control point + // begins shooting off to infinity (i.e., height/width > 32), split the conic into two. + static constexpr float kAlmost180Degrees = 32; + if (miterCapHeight > kAlmost180Degrees * miterCapWidth) { + Sk2f bisect = normalize(n0 - n1); + this->rotateTo(joinVerb, SkVector::Make(-bisect[1], bisect[0])); + this->recordLeftJoinIfNotEmpty(joinVerb, nextNormal); + return; + } + + float miterCapHeightOverWidth = miterCapHeight / miterCapWidth; + + // Find the heights of this round join's conic control point as well as the arc itself. + Sk2f X, Y; + transpose(base * base, n0 * n1, &X, &Y); + Sk2f r = Sk2f::Max(X + Y + Sk2f(0, 1), 0.f).sqrt(); + Sk2f heights = SkNx_fma(r, Sk2f(miterCapHeightOverWidth, -SK_ScalarRoot2Over2), Sk2f(0, 1)); + float controlPointHeight = SkScalarAbs(heights[0]); + float curveHeight = heights[1]; + if (curveHeight * fCurrStrokeRadius < kMaxErrorFromLinearization) { + // Treat round joins as bevels when their curvature is nearly flat. + this->recordBevelJoin(joinVerb); + return; + } + + float w = curveHeight / (controlPointHeight - curveHeight); + this->recordRoundJoin(joinVerb, miterCapHeightOverWidth, w); +} + +void GrStrokeGeometry::recordBevelJoin(Verb originalJoinVerb) { + if (!IsInternalJoinVerb(originalJoinVerb)) { + fVerbs.push_back(Verb::kBevelJoin); + ++fCurrStrokeTallies->fTriangles; + } else { + fVerbs.push_back(Verb::kInternalBevelJoin); + fCurrStrokeTallies->fTriangles += 2; + } +} + +void GrStrokeGeometry::recordMiterJoin(float miterCapHeightOverWidth) { + fVerbs.push_back(Verb::kMiterJoin); + fParams.push_back().fMiterCapHeightOverWidth = miterCapHeightOverWidth; + fCurrStrokeTallies->fTriangles += 2; +} + +void GrStrokeGeometry::recordRoundJoin(Verb joinVerb, float miterCapHeightOverWidth, + float conicWeight) { + fVerbs.push_back(joinVerb); + fParams.push_back().fConicWeight = conicWeight; + fParams.push_back().fMiterCapHeightOverWidth = miterCapHeightOverWidth; + if (Verb::kRoundJoin == joinVerb) { + ++fCurrStrokeTallies->fTriangles; + ++fCurrStrokeTallies->fConics; + } else { + SkASSERT(Verb::kInternalRoundJoin == joinVerb); + fCurrStrokeTallies->fTriangles += 2; + fCurrStrokeTallies->fConics += 2; + } +} + +void GrStrokeGeometry::closeContour() { + SkASSERT(fInsideContour); + SkASSERT(fPoints.count() > fCurrContourFirstPtIdx); + if (fPoints.back() != fPoints[fCurrContourFirstPtIdx]) { + // Draw a line back to the beginning. + this->lineTo(fCurrStrokeJoinVerb, fPoints[fCurrContourFirstPtIdx]); + } + if (fNormals.count() > fCurrContourFirstNormalIdx) { + // Join the first and last lines. + this->rotateTo(fCurrStrokeJoinVerb,fNormals[fCurrContourFirstNormalIdx]); + } else { + // This contour is empty. Add a bogus normal since the iterator always expects one. + SkASSERT(fNormals.count() == fCurrContourFirstNormalIdx); + fNormals.push_back({0, 0}); + } + fVerbs.push_back(Verb::kEndContour); + SkDEBUGCODE(fInsideContour = false); +} + +void GrStrokeGeometry::capContourAndExit() { + SkASSERT(fInsideContour); + if (fCurrContourFirstNormalIdx >= fNormals.count()) { + // This contour is empty. Add a normal in the direction that caps orient on empty geometry. + SkASSERT(fNormals.count() == fCurrContourFirstNormalIdx); + fNormals.push_back({1, 0}); + } + + this->recordCapsIfAny(); + fVerbs.push_back(Verb::kEndContour); + + SkDEBUGCODE(fInsideContour = false); +} + +void GrStrokeGeometry::recordCapsIfAny() { + SkASSERT(fInsideContour); + SkASSERT(fCurrContourFirstNormalIdx < fNormals.count()); + + if (SkPaint::kButt_Cap == fCurrStrokeCapType) { + return; + } + + Verb capVerb; + if (SkPaint::kSquare_Cap == fCurrStrokeCapType) { + if (fCurrStrokeRadius * SK_ScalarRoot2Over2 < kMaxErrorFromLinearization) { + return; + } + capVerb = Verb::kSquareCap; + fCurrStrokeTallies->fStrokes[0] += 2; + } else { + SkASSERT(SkPaint::kRound_Cap == fCurrStrokeCapType); + if (fCurrStrokeRadius < kMaxErrorFromLinearization) { + return; + } + capVerb = Verb::kRoundCap; + fCurrStrokeTallies->fTriangles += 2; + fCurrStrokeTallies->fConics += 4; + } + + fVerbs.push_back(capVerb); + fVerbs.push_back(Verb::kEndContour); + + fVerbs.push_back(capVerb); + + // Reserve the space first, since push_back() takes the point by reference and might + // invalidate the reference if the array grows. + fPoints.reserve(fPoints.count() + 1); + fPoints.push_back(fPoints[fCurrContourFirstPtIdx]); + + // Reserve the space first, since push_back() takes the normal by reference and might + // invalidate the reference if the array grows. (Although in this case we should be fine + // since there is a negate operator.) + fNormals.reserve(fNormals.count() + 1); + fNormals.push_back(-fNormals[fCurrContourFirstNormalIdx]); +} diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrStrokeGeometry.h b/chromium/third_party/skia/src/gpu/tessellate/GrStrokeGeometry.h new file mode 100644 index 00000000000..98a85fffac9 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/tessellate/GrStrokeGeometry.h @@ -0,0 +1,177 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrGrStrokeGeometry_DEFINED +#define GrGrStrokeGeometry_DEFINED + +#include "include/core/SkPaint.h" +#include "include/core/SkPoint.h" +#include "include/private/SkTArray.h" + +class SkStrokeRec; + +/** + * This class converts post-transform stroked paths into a set of independent strokes, joins, and + * caps that map directly to GPU instances. + */ +class GrStrokeGeometry { +public: + static constexpr int kMaxNumLinearSegmentsLog2 = 15; + + GrStrokeGeometry(int numSkPoints = 0, int numSkVerbs = 0) + : fVerbs(numSkVerbs * 5/2) // Reserve for a 2.5x expansion in verbs. (Joins get their + // own separate verb in our representation.) + , fParams(numSkVerbs * 3) // Somewhere around 1-2 params per verb. + , fPoints(numSkPoints * 5/4) // Reserve for a 1.25x expansion in points and normals. + , fNormals(numSkPoints * 5/4) {} + + // A string of verbs and their corresponding, params, points, and normals are a compact + // representation of what will eventually be independent instances in GPU buffers. + enum class Verb : uint8_t { + kBeginPath, // Instructs the iterator to advance its stroke width, atlas offset, etc. + + // Independent strokes of a single line or curve, with (antialiased) butt caps on the ends. + kLinearStroke, + kQuadraticStroke, + kCubicStroke, + + // Joins are a triangles that connect the outer corners of two adjoining strokes. Miters + // have an additional triangle cap on top of the bevel, and round joins have an arc on top. + kBevelJoin, + kMiterJoin, + kRoundJoin, + + // We use internal joins when we have to internally break up a stroke because its curvature + // is too strong for a triangle strip. They are coverage-counted, self-intersecting + // quadrilaterals that tie the four corners of two adjoining strokes together a like a + // shoelace. (Coverage is negative on the inside half.) We place an arc on both ends of an + // internal round join. + kInternalBevelJoin, + kInternalRoundJoin, + + kSquareCap, + kRoundCap, + + kEndContour // Instructs the iterator to advance its internal point and normal ptrs. + }; + static bool IsInternalJoinVerb(Verb verb); + + // Some verbs require additional parameters(s). + union Parameter { + // For cubic and quadratic strokes: How many flat line segments to chop the curve into? + int fNumLinearSegmentsLog2; + // For miter and round joins: How tall should the triangle cap be on top of the join? + // (This triangle is the conic control points for a round join.) + float fMiterCapHeightOverWidth; + float fConicWeight; // Round joins only. + }; + + const SkTArray<Verb, true>& verbs() const { SkASSERT(!fInsideContour); return fVerbs; } + const SkTArray<Parameter, true>& params() const { SkASSERT(!fInsideContour); return fParams; } + const SkTArray<SkPoint, true>& points() const { SkASSERT(!fInsideContour); return fPoints; } + const SkTArray<SkVector, true>& normals() const { SkASSERT(!fInsideContour); return fNormals; } + + // These track the numbers of instances required to draw all the recorded strokes. + struct InstanceTallies { + int fStrokes[kMaxNumLinearSegmentsLog2 + 1]; + int fTriangles; + int fConics; + + InstanceTallies operator+(const InstanceTallies&) const; + }; + + void beginPath(const SkStrokeRec&, float strokeDevWidth, InstanceTallies*); + void moveTo(SkPoint); + void lineTo(SkPoint); + void quadraticTo(const SkPoint[3]); + void cubicTo(const SkPoint[4]); + void closeContour(); // Connect back to the first point in the contour and exit. + void capContourAndExit(); // Add endcaps (if any) and exit the contour. + +private: + void lineTo(Verb leftJoinVerb, SkPoint); + void quadraticTo(Verb leftJoinVerb, const SkPoint[3], float maxCurvatureT); + + static constexpr float kLeftMaxCurvatureNone = 1; + static constexpr float kRightMaxCurvatureNone = 0; + void cubicTo(Verb leftJoinVerb, const SkPoint[4], float maxCurvatureT, float leftMaxCurvatureT, + float rightMaxCurvatureT); + + // Pushes a new normal to fNormals and records a join, without changing the current position. + void rotateTo(Verb leftJoinVerb, SkVector normal); + + // Records a stroke in fElememts. + void recordStroke(Verb, int numSegmentsLog2); + + // Records a join in fElememts with the previous stroke, if the cuurent contour is not empty. + void recordLeftJoinIfNotEmpty(Verb joinType, SkVector nextNormal); + void recordBevelJoin(Verb originalJoinVerb); + void recordMiterJoin(float miterCapHeightOverWidth); + void recordRoundJoin(Verb roundJoinVerb, float miterCapHeightOverWidth, float conicWeight); + + void recordCapsIfAny(); + + float fCurrStrokeRadius; + Verb fCurrStrokeJoinVerb; + SkPaint::Cap fCurrStrokeCapType; + InstanceTallies* fCurrStrokeTallies = nullptr; + + // We implement miters by placing a triangle-shaped cap on top of a bevel join. This field tells + // us what the miter limit is, restated in terms of how tall that triangle cap can be. + float fMiterMaxCapHeightOverWidth; + + // Any curvature on the original curve gets magnified on the outer edge of the stroke, + // proportional to how thick the stroke radius is. This field tells us the maximum curvature we + // can tolerate using the current stroke radius, before linearization artifacts begin to appear + // on the outer edge. + // + // (Curvature this strong is quite rare in practice, but when it does happen, we decompose the + // section with strong curvature into lineTo's with round joins in between.) + float fMaxCurvatureCosTheta; + + int fCurrContourFirstPtIdx; + int fCurrContourFirstNormalIdx; + + SkDEBUGCODE(bool fInsideContour = false); + + SkSTArray<128, Verb, true> fVerbs; + SkSTArray<128, Parameter, true> fParams; + SkSTArray<128, SkPoint, true> fPoints; + SkSTArray<128, SkVector, true> fNormals; +}; + +inline GrStrokeGeometry::InstanceTallies GrStrokeGeometry::InstanceTallies::operator+( + const InstanceTallies& t) const { + InstanceTallies ret; + for (int i = 0; i <= kMaxNumLinearSegmentsLog2; ++i) { + ret.fStrokes[i] = fStrokes[i] + t.fStrokes[i]; + } + ret.fTriangles = fTriangles + t.fTriangles; + ret.fConics = fConics + t.fConics; + return ret; +} + +inline bool GrStrokeGeometry::IsInternalJoinVerb(Verb verb) { + switch (verb) { + case Verb::kInternalBevelJoin: + case Verb::kInternalRoundJoin: + return true; + case Verb::kBeginPath: + case Verb::kLinearStroke: + case Verb::kQuadraticStroke: + case Verb::kCubicStroke: + case Verb::kBevelJoin: + case Verb::kMiterJoin: + case Verb::kRoundJoin: + case Verb::kSquareCap: + case Verb::kRoundCap: + case Verb::kEndContour: + return false; + } + SK_ABORT("Invalid GrStrokeGeometry::Verb."); +} +#endif diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrTessellatePathOp.cpp b/chromium/third_party/skia/src/gpu/tessellate/GrTessellatePathOp.cpp index 7e0950ac460..4d028b357c4 100644 --- a/chromium/third_party/skia/src/gpu/tessellate/GrTessellatePathOp.cpp +++ b/chromium/third_party/skia/src/gpu/tessellate/GrTessellatePathOp.cpp @@ -14,7 +14,16 @@ #include "src/gpu/tessellate/GrFillPathShader.h" #include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h" #include "src/gpu/tessellate/GrMidpointContourParser.h" +#include "src/gpu/tessellate/GrResolveLevelCounter.h" #include "src/gpu/tessellate/GrStencilPathShader.h" +#include "src/gpu/tessellate/GrTessellationPathRenderer.h" + +constexpr static float kLinearizationIntolerance = + GrTessellationPathRenderer::kLinearizationIntolerance; + +constexpr static int kMaxResolveLevel = GrTessellationPathRenderer::kMaxResolveLevel; + +using OpFlags = GrTessellationPathRenderer::OpFlags; GrTessellatePathOp::FixedFunctionFlags GrTessellatePathOp::fixedFunctionFlags() const { auto flags = FixedFunctionFlags::kUsesStencil; @@ -30,50 +39,68 @@ void GrTessellatePathOp::onPrePrepare(GrRecordingContext*, const GrXferProcessor::DstProxyView&) { } -void GrTessellatePathOp::onPrepare(GrOpFlushState* state) { +void GrTessellatePathOp::onPrepare(GrOpFlushState* flushState) { + int numVerbs = fPath.countVerbs(); + if (numVerbs <= 0) { + return; + } + // First check if the path is large and/or simple enough that we can actually triangulate the // inner polygon(s) on the CPU. This is our fastest approach. It allows us to stencil only the - // curves, and then fill the internal polygons directly to the final render target, thus filling - // in the majority of pixels in a single render pass. + // curves, and then fill the internal polygons directly to the final render target, thus drawing + // the majority of pixels in a single render pass. SkScalar scales[2]; SkAssertResult(fViewMatrix.getMinMaxScales(scales)); // Will fail if perspective. const SkRect& bounds = fPath.getBounds(); - int numVerbs = fPath.countVerbs(); - if (numVerbs <= 0) { - return; - } float gpuFragmentWork = bounds.height() * scales[0] * bounds.width() * scales[1]; float cpuTessellationWork = (float)numVerbs * SkNextLog2(numVerbs); // N log N. if (cpuTessellationWork * 500 + (256 * 256) < gpuFragmentWork) { // Don't try below 256x256. - int numCountedCurves; + int numCountedCubics; // This will fail if the inner triangles do not form a simple polygon (e.g., self // intersection, double winding). - if (this->prepareNonOverlappingInnerTriangles(state, &numCountedCurves)) { - // Prepare cubics on an instance boundary so we can use the buffer to fill local convex - // hulls as well. - this->prepareOuterCubics(state, numCountedCurves, - CubicDataAlignment::kInstanceBoundary); + if (this->prepareNonOverlappingInnerTriangles(flushState, &numCountedCubics)) { + if (!numCountedCubics) { + return; + } + // Always use indirect draws for cubics instead of tessellation here. Our goal in this + // mode is to maximize GPU performance, and the middle-out topology used by our indirect + // draws is easier on the rasterizer than a tessellated fan. There also seems to be a + // small amount of fixed tessellation overhead that this avoids. + GrResolveLevelCounter resolveLevelCounter; + resolveLevelCounter.reset(fPath, fViewMatrix, kLinearizationIntolerance); + this->prepareIndirectOuterCubics(flushState, resolveLevelCounter); return; } } - // Next see if we can split up inner polygon triangles and curves, and triangulate the inner - // polygon(s) more efficiently. This causes greater CPU overhead due to the extra shaders and - // draw calls, but the better triangulation can reduce the rasterizer load by a great deal on - // complex paths. + // When there are only a few verbs, it seems to always be fastest to make a single indirect draw + // that contains both the inner triangles and the outer cubics, instead of using hardware + // tessellation. Also take this path if tessellation is not supported. + bool drawTrianglesAsIndirectCubicDraw = (numVerbs < 50); + if (drawTrianglesAsIndirectCubicDraw || (fOpFlags & OpFlags::kDisableHWTessellation)) { + // Prepare outer cubics with indirect draws. + GrResolveLevelCounter resolveLevelCounter; + this->prepareMiddleOutTrianglesAndCubics(flushState, &resolveLevelCounter, + drawTrianglesAsIndirectCubicDraw); + return; + } + + // The caller should have sent Flags::kDisableHWTessellation if it was not supported. + SkASSERT(flushState->caps().shaderCaps()->tessellationSupport()); + + // Next see if we can split up the inner triangles and outer cubics into two draw calls. This + // allows for a more efficient inner triangle topology that can reduce the rasterizer load by a + // large margin on complex paths, but also causes greater CPU overhead due to the extra shader + // switches and draw calls. // NOTE: Raster-edge work is 1-dimensional, so we sum height and width instead of multiplying. float rasterEdgeWork = (bounds.height() + bounds.width()) * scales[1] * fPath.countVerbs(); - if (rasterEdgeWork > 1000 * 1000) { - int numCountedCurves; - this->prepareMiddleOutInnerTriangles(state, &numCountedCurves); - // We will fill the path with a bounding box instead local cubic convex hulls, so there is - // no need to prepare the cubics on an instance boundary. - this->prepareOuterCubics(state, numCountedCurves, CubicDataAlignment::kVertexBoundary); + if (rasterEdgeWork > 300 * 300) { + this->prepareMiddleOutTrianglesAndCubics(flushState); return; } // Fastest CPU approach: emit one cubic wedge per verb, fanning out from the center. - this->prepareCubicWedges(state); + this->prepareTessellatedCubicWedges(flushState); } bool GrTessellatePathOp::prepareNonOverlappingInnerTriangles(GrMeshDrawOp::Target* target, @@ -93,52 +120,88 @@ bool GrTessellatePathOp::prepareNonOverlappingInnerTriangles(GrMeshDrawOp::Targe // simple. return false; } - if (((Flags::kStencilOnly | Flags::kWireframe) & fFlags) || GrAAType::kCoverage == fAAType || + if (((OpFlags::kStencilOnly | OpFlags::kWireframe) & fOpFlags) || + GrAAType::kCoverage == fAAType || (target->appliedClip() && target->appliedClip()->hasStencilClip())) { // If we have certain flags, mixed samples, or a stencil clip then we unfortunately // can't fill the inner polygon directly. Indicate that these triangles need to be // stencilled. fDoStencilTriangleBuffer = true; } - if (!(Flags::kStencilOnly & fFlags)) { + if (!(OpFlags::kStencilOnly & fOpFlags)) { fDoFillTriangleBuffer = true; } return true; } -void GrTessellatePathOp::prepareMiddleOutInnerTriangles(GrMeshDrawOp::Target* target, - int* numCountedCurves) { +void GrTessellatePathOp::prepareMiddleOutTrianglesAndCubics( + GrMeshDrawOp::Target* target, GrResolveLevelCounter* resolveLevelCounter, + bool drawTrianglesAsIndirectCubicDraw) { SkASSERT(!fTriangleBuffer); SkASSERT(!fDoStencilTriangleBuffer); SkASSERT(!fDoFillTriangleBuffer); + SkASSERT(!fCubicBuffer); + SkASSERT(!fStencilCubicsShader); + SkASSERT(!fIndirectDrawBuffer); // No initial moveTo, plus an implicit close at the end; n-2 triangles fill an n-gon. - // Each triangle has 3 vertices. - int maxVertices = (fPath.countVerbs() - 1) * 3; - - GrEagerDynamicVertexAllocator vertexAlloc(target, &fTriangleBuffer, &fBaseTriangleVertex); - auto* vertexData = vertexAlloc.lock<SkPoint>(maxVertices); + int maxInnerTriangles = fPath.countVerbs() - 1; + int maxCubics = fPath.countVerbs(); + + SkPoint* vertexData; + int vertexAdvancePerTriangle; + if (drawTrianglesAsIndirectCubicDraw) { + // Allocate the triangles as 4-point instances at the beginning of the cubic buffer. + SkASSERT(resolveLevelCounter); + vertexAdvancePerTriangle = 4; + int baseTriangleInstance; + vertexData = static_cast<SkPoint*>(target->makeVertexSpace( + sizeof(SkPoint) * 4, maxInnerTriangles + maxCubics, &fCubicBuffer, + &baseTriangleInstance)); + fBaseCubicVertex = baseTriangleInstance * 4; + } else { + // Allocate the triangles as normal 3-point instances in the triangle buffer. + vertexAdvancePerTriangle = 3; + vertexData = static_cast<SkPoint*>(target->makeVertexSpace( + sizeof(SkPoint), maxInnerTriangles * 3, &fTriangleBuffer, &fBaseTriangleVertex)); + } if (!vertexData) { return; } - GrMiddleOutPolygonTriangulator middleOut(vertexData, maxVertices); - int localCurveCount = 0; + GrVectorXform xform(fViewMatrix); + GrMiddleOutPolygonTriangulator middleOut(vertexData, vertexAdvancePerTriangle, + fPath.countVerbs()); + if (resolveLevelCounter) { + resolveLevelCounter->reset(); + } + int numCountedCurves = 0; for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) { switch (verb) { case SkPathVerb::kMove: - middleOut.closeAndMove(*pts++); + middleOut.closeAndMove(pts[0]); break; case SkPathVerb::kLine: middleOut.pushVertex(pts[1]); break; case SkPathVerb::kQuad: middleOut.pushVertex(pts[2]); - ++localCurveCount; + if (resolveLevelCounter) { + // Quadratics get converted to cubics before rendering. + resolveLevelCounter->countCubic(GrWangsFormula::quadratic_log2( + kLinearizationIntolerance, pts, xform)); + break; + } + ++numCountedCurves; break; case SkPathVerb::kCubic: middleOut.pushVertex(pts[3]); - ++localCurveCount; + if (resolveLevelCounter) { + resolveLevelCounter->countCubic(GrWangsFormula::cubic_log2( + kLinearizationIntolerance, pts, xform)); + break; + } + ++numCountedCurves; break; case SkPathVerb::kClose: middleOut.close(); @@ -147,13 +210,31 @@ void GrTessellatePathOp::prepareMiddleOutInnerTriangles(GrMeshDrawOp::Target* ta SkUNREACHABLE; } } - fTriangleVertexCount = middleOut.close(); - *numCountedCurves = localCurveCount; - - vertexAlloc.unlock(fTriangleVertexCount); - - if (fTriangleVertexCount) { - fDoStencilTriangleBuffer = true; + int triangleCount = middleOut.close(); + SkASSERT(triangleCount <= maxInnerTriangles); + + if (drawTrianglesAsIndirectCubicDraw) { + SkASSERT(resolveLevelCounter); + int totalInstanceCount = triangleCount + resolveLevelCounter->totalCubicInstanceCount(); + SkASSERT(vertexAdvancePerTriangle == 4); + target->putBackVertices(maxInnerTriangles + maxCubics - totalInstanceCount, + sizeof(SkPoint) * 4); + if (totalInstanceCount) { + this->prepareIndirectOuterCubicsAndTriangles(target, *resolveLevelCounter, vertexData, + triangleCount); + } + } else { + SkASSERT(vertexAdvancePerTriangle == 3); + target->putBackVertices(maxInnerTriangles - triangleCount, sizeof(SkPoint) * 3); + fTriangleVertexCount = triangleCount * 3; + if (fTriangleVertexCount) { + fDoStencilTriangleBuffer = true; + } + if (resolveLevelCounter) { + this->prepareIndirectOuterCubics(target, *resolveLevelCounter); + } else { + this->prepareTessellatedOuterCubics(target, numCountedCurves); + } } } @@ -176,8 +257,141 @@ static void quad2cubic(const SkPoint pts[], SkPoint* out) { out[3] = pts[2]; } -void GrTessellatePathOp::prepareOuterCubics(GrMeshDrawOp::Target* target, int numCountedCurves, - CubicDataAlignment alignment) { +void GrTessellatePathOp::prepareIndirectOuterCubics( + GrMeshDrawOp::Target* target, const GrResolveLevelCounter& resolveLevelCounter) { + SkASSERT(resolveLevelCounter.totalCubicInstanceCount() >= 0); + if (resolveLevelCounter.totalCubicInstanceCount() == 0) { + return; + } + // Allocate a buffer to store the cubic data. + SkPoint* cubicData; + int baseInstance; + cubicData = static_cast<SkPoint*>(target->makeVertexSpace( + sizeof(SkPoint) * 4, resolveLevelCounter.totalCubicInstanceCount(), &fCubicBuffer, + &baseInstance)); + if (!cubicData) { + return; + } + fBaseCubicVertex = baseInstance * 4; + this->prepareIndirectOuterCubicsAndTriangles(target, resolveLevelCounter, cubicData, + /*numTrianglesAtBeginningOfData=*/0); +} + +void GrTessellatePathOp::prepareIndirectOuterCubicsAndTriangles( + GrMeshDrawOp::Target* target, const GrResolveLevelCounter& resolveLevelCounter, + SkPoint* cubicData, int numTrianglesAtBeginningOfData) { + SkASSERT(target->caps().drawInstancedSupport()); + SkASSERT(numTrianglesAtBeginningOfData + resolveLevelCounter.totalCubicInstanceCount() > 0); + SkASSERT(!fStencilCubicsShader); + SkASSERT(cubicData); + + fIndirectIndexBuffer = GrMiddleOutCubicShader::FindOrMakeMiddleOutIndexBuffer( + target->resourceProvider()); + if (!fIndirectIndexBuffer) { + return; + } + + // Here we treat fCubicBuffer as an instance buffer. It should have been prepared with the base + // vertex on an instance boundary in order to accommodate this. + SkASSERT(fBaseCubicVertex % 4 == 0); + int baseInstance = fBaseCubicVertex >> 2; + + // Start preparing the indirect draw buffer. + fIndirectDrawCount = resolveLevelCounter.totalCubicIndirectDrawCount(); + if (numTrianglesAtBeginningOfData) { + ++fIndirectDrawCount; // Add an indirect draw for the triangles at the beginning. + } + + // Allocate space for the GrDrawIndexedIndirectCommand structs. + GrDrawIndexedIndirectCommand* indirectData = target->makeDrawIndexedIndirectSpace( + fIndirectDrawCount, &fIndirectDrawBuffer, &fIndirectDrawOffset); + if (!indirectData) { + SkASSERT(!fIndirectDrawBuffer); + return; + } + + // Fill out the GrDrawIndexedIndirectCommand structs and determine the starting instance data + // location at each resolve level. + SkPoint* instanceLocations[kMaxResolveLevel + 1]; + int indirectIdx = 0; + int runningInstanceCount = 0; + if (numTrianglesAtBeginningOfData) { + // The caller has already packed "triangleInstanceCount" triangles into 4-point instances + // at the beginning of the instance buffer. Add a special-case indirect draw here that will + // emit the triangles [P0, P1, P2] from these 4-point instances. + indirectData[0] = GrMiddleOutCubicShader::MakeDrawTrianglesIndirectCmd( + numTrianglesAtBeginningOfData, baseInstance); + indirectIdx = 1; + runningInstanceCount = numTrianglesAtBeginningOfData; + } + for (int resolveLevel = 1; resolveLevel <= kMaxResolveLevel; ++resolveLevel) { + instanceLocations[resolveLevel] = cubicData + runningInstanceCount * 4; + if (int instanceCountAtCurrLevel = resolveLevelCounter[resolveLevel]) { + indirectData[indirectIdx++] = GrMiddleOutCubicShader::MakeDrawCubicsIndirectCmd( + resolveLevel, instanceCountAtCurrLevel, baseInstance + runningInstanceCount); + runningInstanceCount += instanceCountAtCurrLevel; + } + } + +#ifdef SK_DEBUG + SkASSERT(indirectIdx == fIndirectDrawCount); + SkASSERT(runningInstanceCount == numTrianglesAtBeginningOfData + + resolveLevelCounter.totalCubicInstanceCount()); + SkASSERT(fIndirectDrawCount > 0); + + SkPoint* endLocations[kMaxResolveLevel + 1]; + memcpy(endLocations, instanceLocations + 1, kMaxResolveLevel * sizeof(SkPoint*)); + int totalInstanceCount = numTrianglesAtBeginningOfData + + resolveLevelCounter.totalCubicInstanceCount(); + endLocations[kMaxResolveLevel] = cubicData + totalInstanceCount * 4; +#endif + + fCubicVertexCount = numTrianglesAtBeginningOfData * 4; + + if (resolveLevelCounter.totalCubicInstanceCount()) { + GrVectorXform xform(fViewMatrix); + for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) { + int level; + switch (verb) { + default: + continue; + case SkPathVerb::kQuad: + level = GrWangsFormula::quadratic_log2(kLinearizationIntolerance, pts, xform); + if (level == 0) { + continue; + } + level = std::min(level, kMaxResolveLevel); + quad2cubic(pts, instanceLocations[level]); + break; + case SkPathVerb::kCubic: + level = GrWangsFormula::cubic_log2(kLinearizationIntolerance, pts, xform); + if (level == 0) { + continue; + } + level = std::min(level, kMaxResolveLevel); + memcpy(instanceLocations[level], pts, sizeof(SkPoint) * 4); + break; + } + instanceLocations[level] += 4; + fCubicVertexCount += 4; + } + } + +#ifdef SK_DEBUG + for (int i = 1; i <= kMaxResolveLevel; ++i) { + SkASSERT(instanceLocations[i] == endLocations[i]); + } + SkASSERT(fCubicVertexCount == (numTrianglesAtBeginningOfData + + resolveLevelCounter.totalCubicInstanceCount()) * 4); +#endif + + fStencilCubicsShader = target->allocator()->make<GrMiddleOutCubicShader>(fViewMatrix); +} + +void GrTessellatePathOp::prepareTessellatedOuterCubics(GrMeshDrawOp::Target* target, + int numCountedCurves) { + SkASSERT(target->caps().shaderCaps()->tessellationSupport()); + SkASSERT(numCountedCurves >= 0); SkASSERT(!fCubicBuffer); SkASSERT(!fStencilCubicsShader); @@ -185,41 +399,35 @@ void GrTessellatePathOp::prepareOuterCubics(GrMeshDrawOp::Target* target, int nu return; } - bool instanceAligned = (alignment == CubicDataAlignment::kInstanceBoundary); - int instanceOrVertexStride = (instanceAligned) ? sizeof(SkPoint) * 4 : sizeof(SkPoint); - int instanceOrVertexCount = (instanceAligned) ? numCountedCurves : numCountedCurves * 4; - int baseInstanceOrVertex; - auto* vertexData = static_cast<SkPoint*>(target->makeVertexSpace( - instanceOrVertexStride, instanceOrVertexCount, &fCubicBuffer, &baseInstanceOrVertex)); + sizeof(SkPoint), numCountedCurves * 4, &fCubicBuffer, &fBaseCubicVertex)); if (!vertexData) { return; } - fBaseCubicVertex = (instanceAligned) ? baseInstanceOrVertex * 4 : baseInstanceOrVertex; fCubicVertexCount = 0; for (auto [verb, pts, w] : SkPathPriv::Iterate(fPath)) { switch (verb) { + default: + continue; case SkPathVerb::kQuad: SkASSERT(fCubicVertexCount < numCountedCurves * 4); quad2cubic(pts, vertexData + fCubicVertexCount); - fCubicVertexCount += 4; break; case SkPathVerb::kCubic: SkASSERT(fCubicVertexCount < numCountedCurves * 4); memcpy(vertexData + fCubicVertexCount, pts, sizeof(SkPoint) * 4); - fCubicVertexCount += 4; - break; - default: break; } + fCubicVertexCount += 4; } SkASSERT(fCubicVertexCount == numCountedCurves * 4); - fStencilCubicsShader = target->allocator()->make<GrStencilCubicShader>(fViewMatrix); + fStencilCubicsShader = target->allocator()->make<GrTessellateCubicShader>(fViewMatrix); } -void GrTessellatePathOp::prepareCubicWedges(GrMeshDrawOp::Target* target) { +void GrTessellatePathOp::prepareTessellatedCubicWedges(GrMeshDrawOp::Target* target) { + SkASSERT(target->caps().shaderCaps()->tessellationSupport()); SkASSERT(!fCubicBuffer); SkASSERT(!fStencilCubicsShader); @@ -274,18 +482,18 @@ void GrTessellatePathOp::prepareCubicWedges(GrMeshDrawOp::Target* target) { vertexAlloc.unlock(fCubicVertexCount); if (fCubicVertexCount) { - fStencilCubicsShader = target->allocator()->make<GrStencilWedgeShader>(fViewMatrix); + fStencilCubicsShader = target->allocator()->make<GrTessellateWedgeShader>(fViewMatrix); } } -void GrTessellatePathOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) { - this->drawStencilPass(state); - if (!(Flags::kStencilOnly & fFlags)) { - this->drawCoverPass(state); +void GrTessellatePathOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) { + this->drawStencilPass(flushState); + if (!(OpFlags::kStencilOnly & fOpFlags)) { + this->drawCoverPass(flushState); } } -void GrTessellatePathOp::drawStencilPass(GrOpFlushState* state) { +void GrTessellatePathOp::drawStencilPass(GrOpFlushState* flushState) { // Increments clockwise triangles and decrements counterclockwise. Used for "winding" fill. constexpr static GrUserStencilSettings kIncrDecrStencil( GrUserStencilSettings::StaticInitSeparate< @@ -310,41 +518,48 @@ void GrTessellatePathOp::drawStencilPass(GrOpFlushState* state) { if (GrAAType::kNone != fAAType) { initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias; } - if (state->caps().wireframeSupport() && (Flags::kWireframe & fFlags)) { + if (flushState->caps().wireframeSupport() && (OpFlags::kWireframe & fOpFlags)) { initArgs.fInputFlags |= GrPipeline::InputFlags::kWireframe; } SkASSERT(SkPathFillType::kWinding == fPath.getFillType() || SkPathFillType::kEvenOdd == fPath.getFillType()); initArgs.fUserStencil = (SkPathFillType::kWinding == fPath.getFillType()) ? &kIncrDecrStencil : &kInvertStencil; - initArgs.fCaps = &state->caps(); + initArgs.fCaps = &flushState->caps(); GrPipeline pipeline(initArgs, GrDisableColorXPFactory::MakeXferProcessor(), - state->appliedHardClip()); + flushState->appliedHardClip()); if (fDoStencilTriangleBuffer) { SkASSERT(fTriangleBuffer); GrStencilTriangleShader stencilTriangleShader(fViewMatrix); - GrPathShader::ProgramInfo programInfo(state->writeView(), &pipeline, + GrPathShader::ProgramInfo programInfo(flushState->writeView(), &pipeline, &stencilTriangleShader); - state->bindPipelineAndScissorClip(programInfo, this->bounds()); - state->bindBuffers(nullptr, nullptr, fTriangleBuffer.get()); - state->draw(fTriangleVertexCount, fBaseTriangleVertex); + flushState->bindPipelineAndScissorClip(programInfo, this->bounds()); + flushState->bindBuffers(nullptr, nullptr, fTriangleBuffer.get()); + flushState->draw(fTriangleVertexCount, fBaseTriangleVertex); } if (fStencilCubicsShader) { - GrPathShader::ProgramInfo programInfo(state->writeView(), &pipeline, fStencilCubicsShader); - state->bindPipelineAndScissorClip(programInfo, this->bounds()); - state->bindBuffers(nullptr, nullptr, fCubicBuffer.get()); - state->draw(fCubicVertexCount, fBaseCubicVertex); - } - - // http://skbug.com/9739 - if (state->caps().requiresManualFBBarrierAfterTessellatedStencilDraw()) { - state->gpu()->insertManualFramebufferBarrier(); + SkASSERT(fCubicBuffer); + GrPathShader::ProgramInfo programInfo(flushState->writeView(), &pipeline, + fStencilCubicsShader); + flushState->bindPipelineAndScissorClip(programInfo, this->bounds()); + if (fIndirectDrawBuffer) { + SkASSERT(fIndirectIndexBuffer); + flushState->bindBuffers(fIndirectIndexBuffer.get(), fCubicBuffer.get(), nullptr); + flushState->drawIndexedIndirect(fIndirectDrawBuffer.get(), fIndirectDrawOffset, + fIndirectDrawCount); + } else { + flushState->bindBuffers(nullptr, nullptr, fCubicBuffer.get()); + flushState->draw(fCubicVertexCount, fBaseCubicVertex); + if (flushState->caps().requiresManualFBBarrierAfterTessellatedStencilDraw()) { + flushState->gpu()->insertManualFramebufferBarrier(); // http://skbug.com/9739 + } + } } } -void GrTessellatePathOp::drawCoverPass(GrOpFlushState* state) { +void GrTessellatePathOp::drawCoverPass(GrOpFlushState* flushState) { // Allows non-zero stencil values to pass and write a color, and resets the stencil value back // to zero; discards immediately on stencil values of zero. // NOTE: It's ok to not check the clip here because the previous stencil pass only wrote to @@ -361,7 +576,7 @@ void GrTessellatePathOp::drawCoverPass(GrOpFlushState* state) { GrPipeline::InitArgs initArgs; if (GrAAType::kNone != fAAType) { initArgs.fInputFlags |= GrPipeline::InputFlags::kHWAntialias; - if (1 == state->proxy()->numSamples()) { + if (1 == flushState->proxy()->numSamples()) { SkASSERT(GrAAType::kCoverage == fAAType); // We are mixed sampled. Use conservative raster to make the sample coverage mask 100% // at every fragment. This way we will still get a double hit on shared edges, but @@ -370,10 +585,10 @@ void GrTessellatePathOp::drawCoverPass(GrOpFlushState* state) { initArgs.fInputFlags |= GrPipeline::InputFlags::kConservativeRaster; } } - initArgs.fCaps = &state->caps(); - initArgs.fDstProxyView = state->drawOpArgs().dstProxyView(); - initArgs.fWriteSwizzle = state->drawOpArgs().writeSwizzle(); - GrPipeline pipeline(initArgs, std::move(fProcessors), state->detachAppliedClip()); + initArgs.fCaps = &flushState->caps(); + initArgs.fDstProxyView = flushState->drawOpArgs().dstProxyView(); + initArgs.fWriteSwizzle = flushState->drawOpArgs().writeSwizzle(); + GrPipeline pipeline(initArgs, std::move(fProcessors), flushState->detachAppliedClip()); if (fDoFillTriangleBuffer) { SkASSERT(fTriangleBuffer); @@ -420,29 +635,32 @@ void GrTessellatePathOp::drawCoverPass(GrOpFlushState* state) { } GrFillTriangleShader fillTriangleShader(fViewMatrix, fColor); - GrPathShader::ProgramInfo programInfo(state->writeView(), &pipeline, &fillTriangleShader); - state->bindPipelineAndScissorClip(programInfo, this->bounds()); - state->bindTextures(fillTriangleShader, nullptr, pipeline); - state->bindBuffers(nullptr, nullptr, fTriangleBuffer.get()); - state->draw(fTriangleVertexCount, fBaseTriangleVertex); + GrPathShader::ProgramInfo programInfo(flushState->writeView(), &pipeline, + &fillTriangleShader); + flushState->bindPipelineAndScissorClip(programInfo, this->bounds()); + flushState->bindTextures(fillTriangleShader, nullptr, pipeline); + flushState->bindBuffers(nullptr, nullptr, fTriangleBuffer.get()); + flushState->draw(fTriangleVertexCount, fBaseTriangleVertex); if (fStencilCubicsShader) { + SkASSERT(fCubicBuffer); + // At this point, every pixel is filled in except the ones touched by curves. Issue a // final cover pass over the curves by drawing their convex hulls. This will fill in any // remaining samples and reset the stencil buffer. pipeline.setUserStencil(&kTestAndResetStencil); GrFillCubicHullShader fillCubicHullShader(fViewMatrix, fColor); - GrPathShader::ProgramInfo programInfo(state->writeView(), &pipeline, + GrPathShader::ProgramInfo programInfo(flushState->writeView(), &pipeline, &fillCubicHullShader); - state->bindPipelineAndScissorClip(programInfo, this->bounds()); - state->bindTextures(fillCubicHullShader, nullptr, pipeline); + flushState->bindPipelineAndScissorClip(programInfo, this->bounds()); + flushState->bindTextures(fillCubicHullShader, nullptr, pipeline); // Here we treat fCubicBuffer as an instance buffer. It should have been prepared with // the base vertex on an instance boundary in order to accommodate this. SkASSERT((fCubicVertexCount % 4) == 0); SkASSERT((fBaseCubicVertex % 4) == 0); - state->bindBuffers(nullptr, fCubicBuffer.get(), nullptr); - state->drawInstanced(fCubicVertexCount >> 2, fBaseCubicVertex >> 2, 4, 0); + flushState->bindBuffers(nullptr, fCubicBuffer.get(), nullptr); + flushState->drawInstanced(fCubicVertexCount >> 2, fBaseCubicVertex >> 2, 4, 0); } return; } @@ -450,9 +668,10 @@ void GrTessellatePathOp::drawCoverPass(GrOpFlushState* state) { // There are no triangles to fill. Just draw a bounding box. pipeline.setUserStencil(&kTestAndResetStencil); GrFillBoundingBoxShader fillBoundingBoxShader(fViewMatrix, fColor, fPath.getBounds()); - GrPathShader::ProgramInfo programInfo(state->writeView(), &pipeline, &fillBoundingBoxShader); - state->bindPipelineAndScissorClip(programInfo, this->bounds()); - state->bindTextures(fillBoundingBoxShader, nullptr, pipeline); - state->bindBuffers(nullptr, nullptr, nullptr); - state->draw(4, 0); + GrPathShader::ProgramInfo programInfo(flushState->writeView(), &pipeline, + &fillBoundingBoxShader); + flushState->bindPipelineAndScissorClip(programInfo, this->bounds()); + flushState->bindTextures(fillBoundingBoxShader, nullptr, pipeline); + flushState->bindBuffers(nullptr, nullptr, nullptr); + flushState->draw(4, 0); } diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrTessellatePathOp.h b/chromium/third_party/skia/src/gpu/tessellate/GrTessellatePathOp.h index 8ee6d21bd65..c53e194a7f1 100644 --- a/chromium/third_party/skia/src/gpu/tessellate/GrTessellatePathOp.h +++ b/chromium/third_party/skia/src/gpu/tessellate/GrTessellatePathOp.h @@ -9,28 +9,23 @@ #define GrTessellatePathOp_DEFINED #include "src/gpu/ops/GrMeshDrawOp.h" +#include "src/gpu/tessellate/GrTessellationPathRenderer.h" class GrAppliedHardClip; class GrStencilPathShader; +class GrResolveLevelCounter; -// Renders paths using a hybrid Red Book "stencil, then cover" method. Curves get linearized by -// GPU tessellation shaders. This Op doesn't apply analytic AA, so it requires a render target that -// supports either MSAA or mixed samples if AA is desired. +// Renders paths using a hybrid "Red Book" (stencil, then cover) method. Curves get linearized by +// either GPU tessellation shaders or indirect draws. This Op doesn't apply analytic AA, so it +// requires a render target that supports either MSAA or mixed samples if AA is desired. class GrTessellatePathOp : public GrDrawOp { -public: - enum class Flags { - kNone = 0, - kStencilOnly = (1 << 0), - kWireframe = (1 << 1) - }; - private: DEFINE_OP_CLASS_ID GrTessellatePathOp(const SkMatrix& viewMatrix, const SkPath& path, GrPaint&& paint, - GrAAType aaType, Flags flags = Flags::kNone) + GrAAType aaType, GrTessellationPathRenderer::OpFlags opFlags) : GrDrawOp(ClassID()) - , fFlags(flags) + , fOpFlags(opFlags) , fViewMatrix(viewMatrix) , fPath(path) , fAAType(aaType) @@ -66,25 +61,41 @@ private: // and this is not an option as it would introduce T-junctions with the outer cubics. bool prepareNonOverlappingInnerTriangles(GrMeshDrawOp::Target*, int* numCountedCurves); - // Produces a "Red Book" style triangulation of the SkPath's inner polygon(s). The inner - // polygons connect the endpoints of each verb. (i.e., they are the path that would result from - // collapsing all curves to single lines.) Stencilled together with the outer cubics, these - // define the complete path. + // Produces a "Red Book" style triangulation of the SkPath's inner polygon(s) using a + // "middle-out" topology (See GrMiddleOutPolygonTriangulator), and then prepares outer cubics in + // the cubic buffer. The inner triangles and outer cubics stencilled together define the + // complete path. // - // This method emits the inner triangles with a "middle-out" topology. Middle-out can reduce - // the load on the rasterizer by a great deal as compared to a linear triangle strip or fan. - // See GrMiddleOutPolygonTriangulator. - void prepareMiddleOutInnerTriangles(GrMeshDrawOp::Target*, int* numCountedCurves); - - enum class CubicDataAlignment : bool { - kVertexBoundary, - kInstanceBoundary - }; - - // Writes an array of "outer" cubics from each bezier in the SkPath, converting any quadratics - // to cubics. An outer cubic is an independent, 4-point closed contour consisting of a single - // cubic curve. Stencilled together with the inner triangles, these define the complete path. - void prepareOuterCubics(GrMeshDrawOp::Target*, int numCountedCurves, CubicDataAlignment); + // If a resolveLevel counter is provided, this method resets it and uses it to count and + // prepares the outer cubics as indirect draws. Otherwise they are prepared as hardware + // tessellation patches. + // + // If drawTrianglesAsIndirectCubicDraw is true, then the resolveLevel counter must be non-null, + // and we express the inner triangles as an indirect cubic draw and sneak them in alongside the + // other cubic draws. + void prepareMiddleOutTrianglesAndCubics(GrMeshDrawOp::Target*, GrResolveLevelCounter* = nullptr, + bool drawTrianglesAsIndirectCubicDraw = false); + + // Prepares a list of indirect draw commands and instance data for the path's "outer cubics", + // converting any quadratics to cubics. An outer cubic is an independent, 4-point closed contour + // consisting of a single cubic curve. Stencilled together with the inner triangles, these + // define the complete path. + void prepareIndirectOuterCubics(GrMeshDrawOp::Target*, const GrResolveLevelCounter&); + + // For performance reasons we can often express triangles as an indirect cubic draw and sneak + // them in alongside the other indirect draws. This prepareIndirectOuterCubics variant allows + // the caller to provide a mapped cubic buffer with triangles already written into 4-point + // instances at the beginning. If numTrianglesAtBeginningOfData is nonzero, we add an extra + // indirect draw that renders these triangles. + void prepareIndirectOuterCubicsAndTriangles(GrMeshDrawOp::Target*, const GrResolveLevelCounter&, + SkPoint* cubicData, + int numTrianglesAtBeginningOfData); + + // Writes an array of "outer cubic" tessellation patches from each bezier in the SkPath, + // converting any quadratics to cubics. An outer cubic is an independent, 4-point closed contour + // consisting of a single cubic curve. Stencilled together with the inner triangles, these + // define the complete path. + void prepareTessellatedOuterCubics(GrMeshDrawOp::Target*, int numCountedCurves); // Writes an array of cubic "wedges" from the SkPath, converting any lines or quadratics to // cubics. A wedge is an independent, 5-point closed contour consisting of 4 cubic control @@ -92,13 +103,13 @@ private: // stencilled, these wedges alone define the complete path. // // TODO: Eventually we want to use rational cubic wedges in order to support conics. - void prepareCubicWedges(GrMeshDrawOp::Target*); + void prepareTessellatedCubicWedges(GrMeshDrawOp::Target*); void onExecute(GrOpFlushState*, const SkRect& chainBounds) override; void drawStencilPass(GrOpFlushState*); void drawCoverPass(GrOpFlushState*); - const Flags fFlags; + const GrTessellationPathRenderer::OpFlags fOpFlags; const SkMatrix fViewMatrix; const SkPath fPath; const GrAAType fAAType; @@ -137,6 +148,14 @@ private: int fCubicVertexCount; GrStencilPathShader* fStencilCubicsShader = nullptr; + // If fIndirectDrawBuffer is non-null, then we issue an indexed-indirect draw instead of using + // hardware tessellation. This is oftentimes faster than tessellation, and other times it serves + // as a polyfill when tessellation just isn't supported. + sk_sp<const GrBuffer> fIndirectDrawBuffer; + size_t fIndirectDrawOffset; + int fIndirectDrawCount; + sk_sp<const GrBuffer> fIndirectIndexBuffer; + friend class GrOpMemoryPool; // For ctor. public: @@ -144,6 +163,4 @@ public: class TestingOnly_Benchmark; }; -GR_MAKE_BITFIELD_CLASS_OPS(GrTessellatePathOp::Flags); - #endif diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrTessellationPathRenderer.cpp b/chromium/third_party/skia/src/gpu/tessellate/GrTessellationPathRenderer.cpp index e632c23a6f9..482a1ef7849 100644 --- a/chromium/third_party/skia/src/gpu/tessellate/GrTessellationPathRenderer.cpp +++ b/chromium/third_party/skia/src/gpu/tessellate/GrTessellationPathRenderer.cpp @@ -7,6 +7,8 @@ #include "src/gpu/tessellate/GrTessellationPathRenderer.h" +#include "include/pathops/SkPathOps.h" +#include "src/core/SkIPoint16.h" #include "src/core/SkPathPriv.h" #include "src/gpu/GrClip.h" #include "src/gpu/GrMemoryPool.h" @@ -17,19 +19,87 @@ #include "src/gpu/ops/GrFillRectOp.h" #include "src/gpu/tessellate/GrDrawAtlasPathOp.h" #include "src/gpu/tessellate/GrTessellatePathOp.h" +#include "src/gpu/tessellate/GrWangsFormula.h" constexpr static SkISize kAtlasInitialSize{512, 512}; constexpr static int kMaxAtlasSize = 2048; -GrTessellationPathRenderer::GrTessellationPathRenderer(const GrCaps& caps) : fAtlas( - GrColorType::kAlpha_8, GrDynamicAtlas::InternalMultisample::kYes, kAtlasInitialSize, - std::min(kMaxAtlasSize, caps.maxPreferredRenderTargetSize()), caps) { +// The atlas is only used for small-area paths, which means at least one dimension of every path is +// guaranteed to be quite small. So if we transpose tall paths, then every path will have a small +// height, which lends very well to efficient pow2 atlas packing. +constexpr static auto kAtlasAlgorithm = GrDynamicAtlas::RectanizerAlgorithm::kPow2; + +// Ensure every path in the atlas falls in or below the 128px high rectanizer band. +constexpr static int kMaxAtlasPathHeight = 128; + +GrTessellationPathRenderer::GrTessellationPathRenderer(const GrCaps& caps) + : fAtlas(GrColorType::kAlpha_8, GrDynamicAtlas::InternalMultisample::kYes, + kAtlasInitialSize, std::min(kMaxAtlasSize, caps.maxPreferredRenderTargetSize()), + caps, kAtlasAlgorithm) { + this->initAtlasFlags(*caps.shaderCaps()); +} + +void GrTessellationPathRenderer::initAtlasFlags(const GrShaderCaps& shaderCaps) { + fStencilAtlasFlags = OpFlags::kStencilOnly | OpFlags::kDisableHWTessellation; + fMaxAtlasPathWidth = fAtlas.maxAtlasSize() / 2; + // The atlas usually does better with hardware tessellation. If hardware tessellation is + // supported, we choose a max atlas path width that is guaranteed to never require more + // tessellation segments than are supported by the hardware. + if (!shaderCaps.tessellationSupport()) { + return; + } + // Since we limit the area of paths in the atlas to kMaxAtlasPathHeight^2, taller paths can't + // get very wide anyway. Find the tallest path whose width is limited by + // GrWangsFormula::worst_case_cubic() rather than the max area constraint, and use that for our + // max atlas path width. + // + // Solve the following equation for w: + // + // GrWangsFormula::worst_case_cubic(kLinearizationIntolerance, w, kMaxAtlasPathHeight^2 / w) + // == maxTessellationSegments + // + float k = GrWangsFormula::cubic_k(kLinearizationIntolerance); + float h = kMaxAtlasPathHeight; + float s = shaderCaps.maxTessellationSegments(); + // Quadratic formula from Numerical Recipes in C: + // + // q = -1/2 [b + sign(b) sqrt(b*b - 4*a*c)] + // x1 = q/a + // x2 = c/q + // + // float a = 1; // 'a' is always 1 in our specific equation. + float b = -s*s*s*s / (4*k*k); // Always negative. + float c = h*h*h*h; // Always positive. + float det = b*b - 4*1*c; + if (det <= 0) { + // maxTessellationSegments is too small for any path whose area == kMaxAtlasPathHeight^2. + // (This is unexpected because the GL spec mandates a minimum of 64 segments.) + SkDebugf("WARNING: maxTessellationSegments seems too low. (%i)\n", + shaderCaps.maxTessellationSegments()); + return; + } + float q = -.5f * (b - std::sqrt(det)); // Always positive. + // The two roots represent the width^2 and height^2 of the tallest rectangle that is limited by + // GrWangsFormula::worst_case_cubic(). + float r0 = q; // Always positive. + float r1 = c/q; // Always positive. + float worstCaseWidth = std::sqrt(std::max(r0, r1)); +#ifdef SK_DEBUG + float worstCaseHeight = std::sqrt(std::min(r0, r1)); + // Verify the above equation worked as expected. It should have found a width and height whose + // area == kMaxAtlasPathHeight^2. + SkASSERT(SkScalarNearlyEqual(worstCaseHeight * worstCaseWidth, h*h, 1)); + // Verify GrWangsFormula::worst_case_cubic() still works as we expect. The worst case number of + // segments for this bounding box should be maxTessellationSegments. + SkASSERT(SkScalarNearlyEqual(GrWangsFormula::worst_case_cubic( + kLinearizationIntolerance, worstCaseWidth, worstCaseHeight), s, 1)); +#endif + fStencilAtlasFlags &= ~OpFlags::kDisableHWTessellation; + fMaxAtlasPathWidth = std::min(fMaxAtlasPathWidth, (int)worstCaseWidth); } GrPathRenderer::CanDrawPath GrTessellationPathRenderer::onCanDrawPath( const CanDrawPathArgs& args) const { - // This class should not have been added to the chain without tessellation support. - SkASSERT(args.fCaps->shaderCaps()->tessellationSupport()); if (!args.fShape->style().isSimpleFill() || args.fShape->inverseFilled() || args.fViewMatrix->hasPerspective()) { return CanDrawPath::kNo; @@ -51,63 +121,142 @@ GrPathRenderer::CanDrawPath GrTessellationPathRenderer::onCanDrawPath( bool GrTessellationPathRenderer::onDrawPath(const DrawPathArgs& args) { GrRenderTargetContext* renderTargetContext = args.fRenderTargetContext; GrOpMemoryPool* pool = args.fContext->priv().opMemoryPool(); + const GrShaderCaps& shaderCaps = *args.fContext->priv().caps()->shaderCaps(); + SkPath path; args.fShape->asPath(&path); + SkRect devBounds; + args.fViewMatrix->mapRect(&devBounds, path.getBounds()); + // See if the path is small and simple enough to atlas instead of drawing directly. // // NOTE: The atlas uses alpha8 coverage even for msaa render targets. We could theoretically // render the sample mask to an integer texture, but such a scheme would probably require // GL_EXT_post_depth_coverage, which appears to have low adoption. SkIRect devIBounds; - SkIVector devToAtlasOffset; - if (this->tryAddPathToAtlas(*args.fContext->priv().caps(), *args.fViewMatrix, path, - args.fAAType, &devIBounds, &devToAtlasOffset)) { + SkIPoint16 locationInAtlas; + bool transposedInAtlas; + if (this->tryAddPathToAtlas(*args.fContext->priv().caps(), *args.fViewMatrix, path, devBounds, + args.fAAType, &devIBounds, &locationInAtlas, &transposedInAtlas)) { +#ifdef SK_DEBUG + // If using hardware tessellation in the atlas, make sure the max number of segments is + // sufficient for this path. fMaxAtlasPathWidth should have been tuned for this to always be + // the case. + if (!(fStencilAtlasFlags & OpFlags::kDisableHWTessellation)) { + int worstCaseNumSegments = GrWangsFormula::worst_case_cubic(kLinearizationIntolerance, + devIBounds.width(), + devIBounds.height()); + SkASSERT(worstCaseNumSegments <= shaderCaps.maxTessellationSegments()); + } +#endif auto op = pool->allocate<GrDrawAtlasPathOp>( renderTargetContext->numSamples(), sk_ref_sp(fAtlas.textureProxy()), - devIBounds, devToAtlasOffset, *args.fViewMatrix, std::move(args.fPaint)); - renderTargetContext->addDrawOp(*args.fClip, std::move(op)); + devIBounds, locationInAtlas, transposedInAtlas, *args.fViewMatrix, + std::move(args.fPaint)); + renderTargetContext->addDrawOp(args.fClip, std::move(op)); return true; } - auto op = pool->allocate<GrTessellatePathOp>( - *args.fViewMatrix, path, std::move(args.fPaint), args.fAAType); - renderTargetContext->addDrawOp(*args.fClip, std::move(op)); + auto drawPathFlags = OpFlags::kNone; + + // Find the worst-case log2 number of line segments that a curve in this path might need to be + // divided into. + int worstCaseResolveLevel = GrWangsFormula::worst_case_cubic_log2(kLinearizationIntolerance, + devBounds.width(), + devBounds.height()); + if (worstCaseResolveLevel > kMaxResolveLevel) { + // The path is too large for our internal indirect draw shaders. Crop it to the viewport. + SkPath viewport; + viewport.addRect(SkRect::MakeIWH(renderTargetContext->width(), + renderTargetContext->height()).makeOutset(1, 1)); + // Perform the crop in device space so it's a simple rect-path intersection. + path.transform(*args.fViewMatrix); + if (!Op(viewport, path, kIntersect_SkPathOp, &path)) { + // The crop can fail if the PathOps encounter NaN or infinities. Return true + // because drawing nothing is acceptable behavior for FP overflow. + return true; + } + // Transform the path back to its own local space. + SkMatrix inverse; + if (!args.fViewMatrix->invert(&inverse)) { + return true; // Singular view matrix. Nothing would have drawn anyway. Return true. + } + path.transform(inverse); + path.setIsVolatile(true); + args.fViewMatrix->mapRect(&devBounds, path.getBounds()); + worstCaseResolveLevel = GrWangsFormula::worst_case_cubic_log2(kLinearizationIntolerance, + devBounds.width(), + devBounds.height()); + // kMaxResolveLevel should be large enough to tessellate paths the size of any screen we + // might encounter. + SkASSERT(worstCaseResolveLevel <= kMaxResolveLevel); + } + + if ((1 << worstCaseResolveLevel) > shaderCaps.maxTessellationSegments()) { + // The path is too large for hardware tessellation; a curve in this bounding box could + // potentially require more segments than are supported by the hardware. Fall back on + // indirect draws. + drawPathFlags |= OpFlags::kDisableHWTessellation; + } + + auto op = pool->allocate<GrTessellatePathOp>(*args.fViewMatrix, path, std::move(args.fPaint), + args.fAAType, drawPathFlags); + renderTargetContext->addDrawOp(args.fClip, std::move(op)); return true; } bool GrTessellationPathRenderer::tryAddPathToAtlas( - const GrCaps& caps, const SkMatrix& viewMatrix, const SkPath& path, GrAAType aaType, - SkIRect* devIBounds, SkIVector* devToAtlasOffset) { + const GrCaps& caps, const SkMatrix& viewMatrix, const SkPath& path, const SkRect& devBounds, + GrAAType aaType, SkIRect* devIBounds, SkIPoint16* locationInAtlas, + bool* transposedInAtlas) { if (!caps.multisampleDisableSupport() && GrAAType::kNone == aaType) { return false; } - // Atlas paths require their points to be transformed on CPU. Check if the path has too many - // points to justify this CPU transformation. - if (path.countPoints() > 150) { + // Atlas paths require their points to be transformed on the CPU and copied into an "uber path". + // Check if this path has too many points to justify this extra work. + if (path.countPoints() > 200) { return false; } - // Check if the path is too large for an atlas. - SkRect devBounds; - viewMatrix.mapRect(&devBounds, path.getBounds()); - if (devBounds.height() * devBounds.width() > 100 * 100 || - std::max(devBounds.height(), devBounds.width()) > kMaxAtlasSize / 2) { + // Transpose tall paths in the atlas. Since we limit ourselves to small-area paths, this + // guarantees that every atlas entry has a small height, which lends very well to efficient pow2 + // atlas packing. + devBounds.roundOut(devIBounds); + int maxDimenstion = devIBounds->width(); + int minDimension = devIBounds->height(); + *transposedInAtlas = minDimension > maxDimenstion; + if (*transposedInAtlas) { + std::swap(minDimension, maxDimenstion); + } + + // Check if the path is too large for an atlas. Since we use "minDimension" for height in the + // atlas, limiting to kMaxAtlasPathHeight^2 pixels guarantees height <= kMaxAtlasPathHeight. + if (maxDimenstion * minDimension > kMaxAtlasPathHeight * kMaxAtlasPathHeight || + maxDimenstion > fMaxAtlasPathWidth) { return false; } - devBounds.roundOut(devIBounds); - if (!fAtlas.addRect(*devIBounds, devToAtlasOffset)) { + if (!fAtlas.addRect(maxDimenstion, minDimension, locationInAtlas)) { return false; } SkMatrix atlasMatrix = viewMatrix; - atlasMatrix.postTranslate(devToAtlasOffset->x(), devToAtlasOffset->y()); + if (*transposedInAtlas) { + std::swap(atlasMatrix[0], atlasMatrix[3]); + std::swap(atlasMatrix[1], atlasMatrix[4]); + float tx=atlasMatrix.getTranslateX(), ty=atlasMatrix.getTranslateY(); + atlasMatrix.setTranslateX(ty - devIBounds->y() + locationInAtlas->x()); + atlasMatrix.setTranslateY(tx - devIBounds->x() + locationInAtlas->y()); + } else { + atlasMatrix.postTranslate(locationInAtlas->x() - devIBounds->x(), + locationInAtlas->y() - devIBounds->y()); + } // Concatenate this path onto our uber path that matches its fill and AA types. SkPath* uberPath = this->getAtlasUberPath(path.getFillType(), GrAAType::kNone != aaType); - uberPath->moveTo(devToAtlasOffset->x(), devToAtlasOffset->y()); // Implicit moveTo(0,0). + uberPath->moveTo(locationInAtlas->x(), locationInAtlas->y()); // Implicit moveTo(0,0). uberPath->addPath(path, atlasMatrix); return true; } @@ -119,8 +268,8 @@ void GrTessellationPathRenderer::onStencilPath(const StencilPathArgs& args) { GrAAType aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone; auto op = args.fContext->priv().opMemoryPool()->allocate<GrTessellatePathOp>( - *args.fViewMatrix, path, GrPaint(), aaType, GrTessellatePathOp::Flags::kStencilOnly); - args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op)); + *args.fViewMatrix, path, GrPaint(), aaType, OpFlags::kStencilOnly); + args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op)); } void GrTessellationPathRenderer::preFlush(GrOnFlushResourceProvider* onFlushRP, @@ -168,9 +317,8 @@ void GrTessellationPathRenderer::renderAtlas(GrOnFlushResourceProvider* onFlushR uberPath->setFillType(fillType); GrAAType aaType = (antialias) ? GrAAType::kMSAA : GrAAType::kNone; auto op = onFlushRP->opMemoryPool()->allocate<GrTessellatePathOp>( - SkMatrix::I(), *uberPath, GrPaint(), aaType, - GrTessellatePathOp::Flags::kStencilOnly); - rtc->addDrawOp(GrNoClip(), std::move(op)); + SkMatrix::I(), *uberPath, GrPaint(), aaType, fStencilAtlasFlags); + rtc->addDrawOp(nullptr, std::move(op)); } } @@ -206,7 +354,7 @@ void GrTessellationPathRenderer::renderAtlas(GrOnFlushResourceProvider* onFlushR auto coverOp = GrFillRectOp::Make(rtc->surfPriv().getContext(), std::move(paint), GrAAType::kMSAA, &drawQuad, stencil, fillRectFlags); - rtc->addDrawOp(GrNoClip(), std::move(coverOp)); + rtc->addDrawOp(nullptr, std::move(coverOp)); if (rtc->asSurfaceProxy()->requiresManualMSAAResolve()) { onFlushRP->addTextureResolveTask(sk_ref_sp(rtc->asTextureProxy()), diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrTessellationPathRenderer.h b/chromium/third_party/skia/src/gpu/tessellate/GrTessellationPathRenderer.h index bf8ea29eb70..4035a0d7a2f 100644 --- a/chromium/third_party/skia/src/gpu/tessellate/GrTessellationPathRenderer.h +++ b/chromium/third_party/skia/src/gpu/tessellate/GrTessellationPathRenderer.h @@ -19,9 +19,32 @@ // target that supports either MSAA or mixed samples if AA is desired. class GrTessellationPathRenderer : public GrPathRenderer, public GrOnFlushCallbackObject { public: - const char* name() const final { return "Tess"; } + // Don't allow linearized segments to be off by more than 1/4th of a pixel from the true curve. + constexpr static float kLinearizationIntolerance = 4; + + // This is the maximum resolve level supported by our internal indirect draw shaders. (Indirect + // draws are an alternative to hardware tessellation, and we can use them when hardware support + // is lacking.) + // + // At a given resolveLevel, a curve gets linearized into 2^resolveLevel line segments. So the + // finest resolveLevel supported by our indirect draw shaders is 2^10 == 1024 line segments. + // + // 1024 line segments is enough resolution (with intolerance == 4) to guarantee we can render a + // 123575px x 123575px path. (See GrWangsFormula::worst_case_cubic.) + constexpr static int kMaxResolveLevel = 10; + + // We send these flags to the internal tessellation Ops to control how a path gets rendered. + enum class OpFlags { + kNone = 0, + // Used when tessellation is not supported, or when a path will require more resolution than + // the max number of segments supported by the hardware. + kDisableHWTessellation = (1 << 0), + kStencilOnly = (1 << 1), + kWireframe = (1 << 2) + }; GrTessellationPathRenderer(const GrCaps&); + const char* name() const final { return "GrTessellationPathRenderer"; } StencilSupport onGetStencilSupport(const GrStyledShape& shape) const override { // TODO: Single-pass (e.g., convex) paths can have full support. return kStencilOnly_StencilSupport; @@ -33,18 +56,24 @@ public: int numOpsTaskIDs) override; private: + void initAtlasFlags(const GrShaderCaps& shaderCaps); SkPath* getAtlasUberPath(SkPathFillType fillType, bool antialias) { int idx = (int)antialias << 1; idx |= (int)fillType & 1; return &fAtlasUberPaths[idx]; } // Allocates space in fAtlas if the path is small and simple enough, and if there is room. - bool tryAddPathToAtlas(const GrCaps&, const SkMatrix&, const SkPath&, GrAAType, - SkIRect* devIBounds, SkIVector* devToAtlasOffset); + bool tryAddPathToAtlas(const GrCaps&, const SkMatrix&, const SkPath&, const SkRect& devBounds, + GrAAType, SkIRect* devIBounds, SkIPoint16* locationInAtlas, + bool* transposedInAtlas); void renderAtlas(GrOnFlushResourceProvider*); GrDynamicAtlas fAtlas; + OpFlags fStencilAtlasFlags; + int fMaxAtlasPathWidth; SkPath fAtlasUberPaths[4]; // 2 fillTypes * 2 antialias modes. }; +GR_MAKE_BITFIELD_CLASS_OPS(GrTessellationPathRenderer::OpFlags); + #endif diff --git a/chromium/third_party/skia/src/gpu/tessellate/GrWangsFormula.h b/chromium/third_party/skia/src/gpu/tessellate/GrWangsFormula.h index 1fa79c6793e..b9c3264e479 100644 --- a/chromium/third_party/skia/src/gpu/tessellate/GrWangsFormula.h +++ b/chromium/third_party/skia/src/gpu/tessellate/GrWangsFormula.h @@ -22,6 +22,11 @@ SK_ALWAYS_INLINE static float length(const Sk2f& n) { return std::sqrt(nn[0] + nn[1]); } +// Constant term for the quatratic formula. +constexpr float quadratic_k(float intolerance) { + return .25f * intolerance; +} + // Returns the minimum number of evenly spaced (in the parametric sense) line segments that the // quadratic must be chopped into in order to guarantee all lines stay within a distance of // "1/intolerance" pixels from the true curve. @@ -29,10 +34,15 @@ SK_ALWAYS_INLINE static float quadratic(float intolerance, const SkPoint pts[]) Sk2f p0 = Sk2f::Load(pts); Sk2f p1 = Sk2f::Load(pts + 1); Sk2f p2 = Sk2f::Load(pts + 2); - float k = intolerance * .25f; + float k = quadratic_k(intolerance); return SkScalarSqrt(k * length(p0 - p1*2 + p2)); } +// Constant term for the cubic formula. +constexpr float cubic_k(float intolerance) { + return .75f * intolerance; +} + // Returns the minimum number of evenly spaced (in the parametric sense) line segments that the // cubic must be chopped into in order to guarantee all lines stay within a distance of // "1/intolerance" pixels from the true curve. @@ -41,11 +51,19 @@ SK_ALWAYS_INLINE static float cubic(float intolerance, const SkPoint pts[]) { Sk2f p1 = Sk2f::Load(pts + 1); Sk2f p2 = Sk2f::Load(pts + 2); Sk2f p3 = Sk2f::Load(pts + 3); - float k = intolerance * .75f; + float k = cubic_k(intolerance); return SkScalarSqrt(k * length(Sk2f::Max((p0 - p1*2 + p2).abs(), (p1 - p2*2 + p3).abs()))); } +// Returns the maximum number of line segments a cubic with the given device-space bounding box size +// would ever need to be divided into. This is simply a special case of the cubic formula where we +// maximize its value by placing control points on specific corners of the bounding box. +SK_ALWAYS_INLINE static float worst_case_cubic(float intolerance, float devWidth, float devHeight) { + float k = cubic_k(intolerance); + return SkScalarSqrt(2*k * SkVector::Length(devWidth, devHeight)); +} + // Returns the log2 of the provided value, were that value to be rounded up to the next power of 2. // Returns 0 if value <= 0: // Never returns a negative number, even if value is NaN. @@ -63,6 +81,10 @@ SK_ALWAYS_INLINE static int nextlog2(float value) { return exp & ~(exp >> 31); // Return 0 for negative or denormalized floats, and exponents < 0. } +SK_ALWAYS_INLINE static int ceil_log2_sqrt_sqrt(float f) { + return (nextlog2(f) + 3) >> 2; // i.e., "ceil(log2(sqrt(sqrt(f)))) +} + // Returns the minimum log2 number of evenly spaced (in the parametric sense) line segments that the // transformed quadratic must be chopped into in order to guarantee all lines stay within a distance // of "1/intolerance" pixels from the true curve. @@ -74,9 +96,9 @@ SK_ALWAYS_INLINE static int quadratic_log2(float intolerance, const SkPoint pts[ Sk2f v = p0 + p1*-2 + p2; v = vectorXform(v); Sk2f vv = v*v; - float k = intolerance * .25f; + float k = quadratic_k(intolerance); float f = k*k * (vv[0] + vv[1]); - return (nextlog2(f) + 3) >> 2; // ceil(log2(sqrt(sqrt(f)))) + return ceil_log2_sqrt_sqrt(f); } // Returns the minimum log2 number of evenly spaced (in the parametric sense) line segments that the @@ -91,9 +113,17 @@ SK_ALWAYS_INLINE static int cubic_log2(float intolerance, const SkPoint pts[], v = vectorXform(v); Sk4f vv = v*v; vv = Sk4f::Max(vv, SkNx_shuffle<2,3,0,1>(vv)); - float k = intolerance * .75f; + float k = cubic_k(intolerance); float f = k*k * (vv[0] + vv[1]); - return (nextlog2(f) + 3) >> 2; // ceil(log2(sqrt(sqrt(f)))) + return ceil_log2_sqrt_sqrt(f); +} + +// Returns the maximum log2 number of line segments a cubic with the given device-space bounding box +// size would ever need to be divided into. +SK_ALWAYS_INLINE static int worst_case_cubic_log2(float intolerance, float devWidth, + float devHeight) { + float k = cubic_k(intolerance); + return ceil_log2_sqrt_sqrt(4*k*k * (devWidth * devWidth + devHeight * devHeight)); } } // namespace diff --git a/chromium/third_party/skia/src/gpu/text/GrAtlasManager.cpp b/chromium/third_party/skia/src/gpu/text/GrAtlasManager.cpp index efe4a472683..3120255a7c8 100644 --- a/chromium/third_party/skia/src/gpu/text/GrAtlasManager.cpp +++ b/chromium/third_party/skia/src/gpu/text/GrAtlasManager.cpp @@ -7,6 +7,8 @@ #include "src/gpu/text/GrAtlasManager.h" +#include "src/codec/SkMasks.h" +#include "src/core/SkAutoMalloc.h" #include "src/gpu/GrGlyph.h" #include "src/gpu/GrImageInfo.h" #include "src/gpu/text/GrStrikeCache.h" @@ -32,6 +34,155 @@ bool GrAtlasManager::hasGlyph(GrMaskFormat format, GrGlyph* glyph) { return this->getAtlas(format)->hasID(glyph->fAtlasLocator.plotLocator()); } +template <typename INT_TYPE> +static void expand_bits(INT_TYPE* dst, + const uint8_t* src, + int width, + int height, + int dstRowBytes, + int srcRowBytes) { + for (int i = 0; i < height; ++i) { + int rowWritesLeft = width; + const uint8_t* s = src; + INT_TYPE* d = dst; + while (rowWritesLeft > 0) { + unsigned mask = *s++; + for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) { + *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0; + } + } + dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes); + src += srcRowBytes; + } +} + +static void get_packed_glyph_image( + const SkGlyph& glyph, int dstRB, GrMaskFormat expectedMaskFormat, void* dst) { + const int width = glyph.width(); + const int height = glyph.height(); + const void* src = glyph.image(); + SkASSERT(src != nullptr); + + GrMaskFormat grMaskFormat = GrGlyph::FormatFromSkGlyph(glyph.maskFormat()); + if (grMaskFormat == expectedMaskFormat) { + int srcRB = glyph.rowBytes(); + // Notice this comparison is with the glyphs raw mask format, and not its GrMaskFormat. + if (glyph.maskFormat() != SkMask::kBW_Format) { + if (srcRB != dstRB) { + const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat); + for (int y = 0; y < height; y++) { + memcpy(dst, src, width * bbp); + src = (const char*) src + srcRB; + dst = (char*) dst + dstRB; + } + } else { + memcpy(dst, src, dstRB * height); + } + } else { + // Handle 8-bit format by expanding the mask to the expected format. + const uint8_t* bits = reinterpret_cast<const uint8_t*>(src); + switch (expectedMaskFormat) { + case kA8_GrMaskFormat: { + uint8_t* bytes = reinterpret_cast<uint8_t*>(dst); + expand_bits(bytes, bits, width, height, dstRB, srcRB); + break; + } + case kA565_GrMaskFormat: { + uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst); + expand_bits(rgb565, bits, width, height, dstRB, srcRB); + break; + } + default: + SK_ABORT("Invalid GrMaskFormat"); + } + } + } else if (grMaskFormat == kA565_GrMaskFormat && expectedMaskFormat == kARGB_GrMaskFormat) { + // Convert if the glyph uses a 565 mask format since it is using LCD text rendering + // but the expected format is 8888 (will happen on macOS with Metal since that + // combination does not support 565). + static constexpr SkMasks masks{ + {0b1111'1000'0000'0000, 11, 5}, // Red + {0b0000'0111'1110'0000, 5, 6}, // Green + {0b0000'0000'0001'1111, 0, 5}, // Blue + {0, 0, 0} // Alpha + }; + constexpr int a565Bpp = GrMaskFormatBytesPerPixel(kA565_GrMaskFormat); + constexpr int argbBpp = GrMaskFormatBytesPerPixel(kARGB_GrMaskFormat); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + uint16_t color565 = 0; + memcpy(&color565, src, a565Bpp); + uint32_t colorRGBA = GrColorPackRGBA(masks.getRed(color565), + masks.getGreen(color565), + masks.getBlue(color565), + 0xFF); + memcpy(dst, &colorRGBA, argbBpp); + src = (char*)src + a565Bpp; + dst = (char*)dst + argbBpp; + } + } + } else { + // crbug:510931 + // Retrieving the image from the cache can actually change the mask format. This case is + // very uncommon so for now we just draw a clear box for these glyphs. + const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat); + for (int y = 0; y < height; y++) { + sk_bzero(dst, width * bpp); + dst = (char*)dst + dstRB; + } + } +} + +// returns true if glyph successfully added to texture atlas, false otherwise. If the glyph's +// mask format has changed, then addGlyphToAtlas will draw a clear box. This will almost never +// happen. +// TODO we can handle some of these cases if we really want to, but the long term solution is to +// get the actual glyph image itself when we get the glyph metrics. +GrDrawOpAtlas::ErrorCode GrAtlasManager::addGlyphToAtlas(const SkGlyph& skGlyph, + int padding, + GrGlyph* grGlyph, + GrResourceProvider* resourceProvider, + GrDeferredUploadTarget* uploadTarget) { + if (skGlyph.image() == nullptr) { + return GrDrawOpAtlas::ErrorCode::kError; + } + SkASSERT(grGlyph != nullptr); + + GrMaskFormat glyphFormat = GrGlyph::FormatFromSkGlyph(skGlyph.maskFormat()); + GrMaskFormat expectedMaskFormat = this->resolveMaskFormat(glyphFormat); + int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat); + + if (padding > 0) { + SkASSERT(skGlyph.maskFormat() != SkMask::kSDF_Format); + } + + SkASSERT(padding == 0 || padding == 1); + // Add 1 pixel padding around grGlyph if needed. + const int width = skGlyph.width() + 2*padding; + const int height = skGlyph.height() + 2*padding; + int rowBytes = width * bytesPerPixel; + size_t size = height * rowBytes; + + // Temporary storage for normalizing grGlyph image. + SkAutoSMalloc<1024> storage(size); + void* dataPtr = storage.get(); + if (padding > 0) { + sk_bzero(dataPtr, size); + // Advance in one row and one column. + dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel; + } + + get_packed_glyph_image(skGlyph, rowBytes, expectedMaskFormat, dataPtr); + + return this->addToAtlas(resourceProvider, + uploadTarget, + expectedMaskFormat, + width, + height, + storage.get(), + &grGlyph->fAtlasLocator); +} + // add to texture atlas that matches this format GrDrawOpAtlas::ErrorCode GrAtlasManager::addToAtlas(GrResourceProvider* resourceProvider, GrDeferredUploadTarget* target, diff --git a/chromium/third_party/skia/src/gpu/text/GrAtlasManager.h b/chromium/third_party/skia/src/gpu/text/GrAtlasManager.h index 036495fa53b..97fcb9a81a8 100644 --- a/chromium/third_party/skia/src/gpu/text/GrAtlasManager.h +++ b/chromium/third_party/skia/src/gpu/text/GrAtlasManager.h @@ -28,18 +28,6 @@ public: GrAtlasManager(GrProxyProvider*, size_t maxTextureBytes, GrDrawOpAtlas::AllowMultitexturing); ~GrAtlasManager() override; - // Change an expected 565 mask format to 8888 if 565 is not supported (will happen when using - // Metal on macOS). The actual conversion of the data is handled in get_packed_glyph_image() in - // GrStrikeCache.cpp - GrMaskFormat resolveMaskFormat(GrMaskFormat format) const { - if (kA565_GrMaskFormat == format && - !fProxyProvider->caps()->getDefaultBackendFormat(GrColorType::kBGR_565, - GrRenderable::kNo).isValid()) { - format = kARGB_GrMaskFormat; - } - return format; - } - // if getViews returns nullptr, the client must not try to use other functions on the // GrStrikeCache which use the atlas. This function *must* be called first, before other // functions which use the atlas. Note that we can have proxies available but none active @@ -58,6 +46,12 @@ public: bool hasGlyph(GrMaskFormat, GrGlyph*); + GrDrawOpAtlas::ErrorCode addGlyphToAtlas(const SkGlyph& skGlyph, + int padding, + GrGlyph* grGlyph, + GrResourceProvider* resourceProvider, + GrDeferredUploadTarget* uploadTarget); + // To ensure the GrDrawOpAtlas does not evict the Glyph Mask from its texture backing store, // the client must pass in the current op token along with the GrGlyph. // A BulkUseTokenUpdater is used to manage bulk last use token updating in the Atlas. @@ -118,6 +112,17 @@ public: private: bool initAtlas(GrMaskFormat); + // Change an expected 565 mask format to 8888 if 565 is not supported (will happen when using + // Metal on macOS). The actual conversion of the data is handled in get_packed_glyph_image() in + // GrStrikeCache.cpp + GrMaskFormat resolveMaskFormat(GrMaskFormat format) const { + if (kA565_GrMaskFormat == format && + !fProxyProvider->caps()->getDefaultBackendFormat(GrColorType::kBGR_565, + GrRenderable::kNo).isValid()) { + format = kARGB_GrMaskFormat; + } + return format; + } // There is a 1:1 mapping between GrMaskFormats and atlas indices static int MaskFormatToAtlasIndex(GrMaskFormat format) { return static_cast<int>(format); } diff --git a/chromium/third_party/skia/src/gpu/text/GrSDFTOptions.cpp b/chromium/third_party/skia/src/gpu/text/GrSDFTOptions.cpp new file mode 100644 index 00000000000..e0ed2189e90 --- /dev/null +++ b/chromium/third_party/skia/src/gpu/text/GrSDFTOptions.cpp @@ -0,0 +1,167 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/gpu/text/GrSDFTOptions.h" + +#include "include/core/SkFont.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkPaint.h" +#include "include/core/SkScalar.h" +#include "include/core/SkSurfaceProps.h" + +#include <tuple> + +// DF sizes and thresholds for usage of the small and medium sizes. For example, above +// kSmallDFFontLimit we will use the medium size. The large size is used up until the size at +// which we switch over to drawing as paths as controlled by Options. +static const int kSmallDFFontSize = 32; +static const int kSmallDFFontLimit = 32; +static const int kMediumDFFontSize = 72; +static const int kMediumDFFontLimit = 72; +static const int kLargeDFFontSize = 162; +#ifdef SK_BUILD_FOR_MAC +static const int kLargeDFFontLimit = 162; +static const int kExtraLargeDFFontSize = 256; +#endif + +GrSDFTOptions::GrSDFTOptions(SkScalar min, SkScalar max) + : fMinDistanceFieldFontSize{min} + , fMaxDistanceFieldFontSize{max} { + SkASSERT_RELEASE(min > 0 && max >= min); +} + +bool GrSDFTOptions::canDrawAsDistanceFields(const SkPaint& paint, const SkFont& font, + const SkMatrix& viewMatrix, + const SkSurfaceProps& props, + bool contextSupportsDistanceFieldText) const { + // mask filters modify alpha, which doesn't translate well to distance + if (paint.getMaskFilter() || !contextSupportsDistanceFieldText) { + return false; + } + + // TODO: add some stroking support + if (paint.getStyle() != SkPaint::kFill_Style) { + return false; + } + + if (viewMatrix.hasPerspective()) { + // Don't use SDF for perspective. Paths look better. + return false; + } else { + SkScalar maxScale = viewMatrix.getMaxScale(); + SkScalar scaledTextSize = maxScale * font.getSize(); + // Hinted text looks far better at small resolutions + // Scaling up beyond 2x yields undesirable artifacts + if (scaledTextSize < fMinDistanceFieldFontSize || + scaledTextSize > fMaxDistanceFieldFontSize) { + return false; + } + + bool useDFT = props.isUseDeviceIndependentFonts(); +#if SK_FORCE_DISTANCE_FIELD_TEXT + useDFT = true; +#endif + + if (!useDFT && scaledTextSize < kLargeDFFontSize) { + return false; + } + } + + return true; +} + +SkScalar scaled_text_size(const SkScalar textSize, const SkMatrix& viewMatrix) { + SkScalar scaledTextSize = textSize; + + if (viewMatrix.hasPerspective()) { + // for perspective, we simply force to the medium size + // TODO: compute a size based on approximate screen area + scaledTextSize = kMediumDFFontLimit; + } else { + SkScalar maxScale = viewMatrix.getMaxScale(); + // if we have non-unity scale, we need to choose our base text size + // based on the SkPaint's text size multiplied by the max scale factor + // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? + if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { + scaledTextSize *= maxScale; + } + } + + return scaledTextSize; +} + +SkFont GrSDFTOptions::getSDFFont(const SkFont& font, + const SkMatrix& viewMatrix, + SkScalar* textRatio) const { + SkScalar textSize = font.getSize(); + SkScalar scaledTextSize = scaled_text_size(textSize, viewMatrix); + + SkFont dfFont{font}; + + if (scaledTextSize <= kSmallDFFontLimit) { + *textRatio = textSize / kSmallDFFontSize; + dfFont.setSize(SkIntToScalar(kSmallDFFontSize)); + } else if (scaledTextSize <= kMediumDFFontLimit) { + *textRatio = textSize / kMediumDFFontSize; + dfFont.setSize(SkIntToScalar(kMediumDFFontSize)); +#ifdef SK_BUILD_FOR_MAC + } else if (scaledTextSize <= kLargeDFFontLimit) { + *textRatio = textSize / kLargeDFFontSize; + dfFont.setSize(SkIntToScalar(kLargeDFFontSize)); + } else { + *textRatio = textSize / kExtraLargeDFFontSize; + dfFont.setSize(SkIntToScalar(kExtraLargeDFFontSize)); + } +#else + } else { + *textRatio = textSize / kLargeDFFontSize; + dfFont.setSize(SkIntToScalar(kLargeDFFontSize)); + } +#endif + + dfFont.setEdging(SkFont::Edging::kAntiAlias); + dfFont.setForceAutoHinting(false); + dfFont.setHinting(SkFontHinting::kNormal); + + // The sub-pixel position will always happen when transforming to the screen. + dfFont.setSubpixel(false); + return dfFont; +} + +std::pair<SkScalar, SkScalar> GrSDFTOptions::computeSDFMinMaxScale( + SkScalar textSize, const SkMatrix& viewMatrix) const { + + SkScalar scaledTextSize = scaled_text_size(textSize, viewMatrix); + + // We have three sizes of distance field text, and within each size 'bucket' there is a floor + // and ceiling. A scale outside of this range would require regenerating the distance fields + SkScalar dfMaskScaleFloor; + SkScalar dfMaskScaleCeil; + if (scaledTextSize <= kSmallDFFontLimit) { + dfMaskScaleFloor = fMinDistanceFieldFontSize; + dfMaskScaleCeil = kSmallDFFontLimit; + } else if (scaledTextSize <= kMediumDFFontLimit) { + dfMaskScaleFloor = kSmallDFFontLimit; + dfMaskScaleCeil = kMediumDFFontLimit; + } else { + dfMaskScaleFloor = kMediumDFFontLimit; + dfMaskScaleCeil = fMaxDistanceFieldFontSize; + } + + // Because there can be multiple runs in the blob, we want the overall maxMinScale, and + // minMaxScale to make regeneration decisions. Specifically, we want the maximum minimum scale + // we can tolerate before we'd drop to a lower mip size, and the minimum maximum scale we can + // tolerate before we'd have to move to a large mip size. When we actually test these values + // we look at the delta in scale between the new viewmatrix and the old viewmatrix, and test + // against these values to decide if we can reuse or not(ie, will a given scale change our mip + // level) + SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScaleCeil); + + return std::make_pair(dfMaskScaleFloor / scaledTextSize, dfMaskScaleCeil / scaledTextSize); +} + + diff --git a/chromium/third_party/skia/src/gpu/text/GrSDFTOptions.h b/chromium/third_party/skia/src/gpu/text/GrSDFTOptions.h new file mode 100644 index 00000000000..33e7b6bd2db --- /dev/null +++ b/chromium/third_party/skia/src/gpu/text/GrSDFTOptions.h @@ -0,0 +1,38 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrSDFTOptions_DEFINED +#define GrSDFTOptions_DEFINED + +#include "include/core/SkFont.h" +#include "include/core/SkScalar.h" + +class SkMatrix; +class SkSurfaceProps; + +class GrSDFTOptions { +public: + GrSDFTOptions(SkScalar min, SkScalar max); + + bool canDrawAsDistanceFields(const SkPaint&, const SkFont&, const SkMatrix& viewMatrix, + const SkSurfaceProps& props, + bool contextSupportsDistanceFieldText) const; + SkFont getSDFFont(const SkFont& font, + const SkMatrix& viewMatrix, + SkScalar* textRatio) const; + std::pair<SkScalar, SkScalar> computeSDFMinMaxScale( + SkScalar textSize, const SkMatrix& viewMatrix) const; +private: + // Below this size (in device space) distance field text will not be used. + const SkScalar fMinDistanceFieldFontSize; + + // Above this size (in device space) distance field text will not be used and glyphs will + // be rendered from outline as individual paths. + const SkScalar fMaxDistanceFieldFontSize; +}; + +#endif // GrSDFTOptions_DEFINED diff --git a/chromium/third_party/skia/src/gpu/text/GrTextBlob.cpp b/chromium/third_party/skia/src/gpu/text/GrTextBlob.cpp index e73868beaa7..565d605f995 100644 --- a/chromium/third_party/skia/src/gpu/text/GrTextBlob.cpp +++ b/chromium/third_party/skia/src/gpu/text/GrTextBlob.cpp @@ -8,11 +8,10 @@ #include "include/core/SkColorFilter.h" #include "include/gpu/GrContext.h" #include "include/private/SkTemplates.h" -#include "src/codec/SkMasks.h" -#include "src/core/SkAutoMalloc.h" #include "src/core/SkMaskFilterBase.h" #include "src/core/SkMatrixProvider.h" #include "src/core/SkPaintPriv.h" +#include "src/core/SkStrikeSpec.h" #include "src/gpu/GrBlurUtils.h" #include "src/gpu/GrClip.h" #include "src/gpu/GrStyle.h" @@ -41,153 +40,229 @@ GrTextBlob::PathGlyph::PathGlyph(const SkPath& path, SkPoint origin) // -- GrTextBlob::SubRun --------------------------------------------------------------------------- GrTextBlob::SubRun::SubRun(SubRunType type, GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec, - GrMaskFormat format, const SkSpan<PackedGlyphIDorGrGlyph>& glyphs, - const SkSpan<char>& vertexData) - : fType{type} - , fBlob{textBlob} + GrMaskFormat format, SkRect vertexBounds, + const SkSpan<VertexData>& vertexData) + : fBlob{textBlob} + , fType{type} , fMaskFormat{format} - , fGlyphs{glyphs} - , fVertexData{vertexData} , fStrikeSpec{strikeSpec} - , fCurrentColor{textBlob->fColor} - , fCurrentOrigin{textBlob->fInitialOrigin} - , fCurrentMatrix{textBlob->fInitialMatrix} { - SkASSERT(type != kTransformedPath); - textBlob->insertSubRun(this); + , fVertexBounds{vertexBounds} + , fVertexData{vertexData} { + SkASSERT(fType != kTransformedPath); } GrTextBlob::SubRun::SubRun(GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec) - : fType{kTransformedPath} - , fBlob{textBlob} + : fBlob{textBlob} + , fType{kTransformedPath} , fMaskFormat{kA8_GrMaskFormat} - , fGlyphs{SkSpan<PackedGlyphIDorGrGlyph>{}} - , fVertexData{SkSpan<char>{}} , fStrikeSpec{strikeSpec} - , fCurrentColor{textBlob->fColor} - , fPaths{} { - textBlob->insertSubRun(this); -} - -static SkRect dest_rect(const SkGlyph& g, SkPoint origin) { - return SkRect::MakeXYWH( - SkIntToScalar(g.left()) + origin.x(), - SkIntToScalar(g.top()) + origin.y(), - SkIntToScalar(g.width()), - SkIntToScalar(g.height())); -} - -static bool is_SDF(const SkGlyph& skGlyph) { - return skGlyph.maskFormat() == SkMask::kSDF_Format; -} - -static SkRect dest_rect(const SkGlyph& g, SkPoint origin, SkScalar textScale) { - if (!is_SDF(g)) { - return SkRect::MakeXYWH( - SkIntToScalar(g.left()) * textScale + origin.x(), - SkIntToScalar(g.top()) * textScale + origin.y(), - SkIntToScalar(g.width()) * textScale, - SkIntToScalar(g.height()) * textScale); - } else { - return SkRect::MakeXYWH( - (SkIntToScalar(g.left()) + SK_DistanceFieldInset) * textScale + origin.x(), - (SkIntToScalar(g.top()) + SK_DistanceFieldInset) * textScale + origin.y(), - (SkIntToScalar(g.width()) - 2 * SK_DistanceFieldInset) * textScale, - (SkIntToScalar(g.height()) - 2 * SK_DistanceFieldInset) * textScale); - } -} - -void GrTextBlob::SubRun::appendGlyphs(const SkZip<SkGlyphVariant, SkPoint>& drawables) { - SkScalar strikeToSource = fStrikeSpec.strikeToSourceRatio(); - SkASSERT(!this->isPrepared()); - PackedGlyphIDorGrGlyph* packedIDCursor = fGlyphs.data(); - char* vertexCursor = fVertexData.data(); - size_t vertexStride = this->vertexStride(); - // We always write the third position component used by SDFs. If it is unused it gets - // overwritten. Similarly, we always write the color and the blob will later overwrite it - // with texture coords if it is unused. - size_t colorOffset = this->colorOffset(); - for (auto [variant, pos] : drawables) { - SkGlyph* skGlyph = variant; - // Only floor the device coordinates. - SkRect dstRect; - if (!this->needsTransform()) { - pos = {SkScalarFloorToScalar(pos.x()), SkScalarFloorToScalar(pos.y())}; - dstRect = dest_rect(*skGlyph, pos); - } else { - dstRect = dest_rect(*skGlyph, pos, strikeToSource); - } - - this->joinGlyphBounds(dstRect); - - // V0 - *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fLeft, dstRect.fTop, 1.f}; - *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor; - vertexCursor += vertexStride; - - // V1 - *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fLeft, dstRect.fBottom, 1.f}; - *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor; - vertexCursor += vertexStride; - - // V2 - *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fRight, dstRect.fTop, 1.f}; - *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor; - vertexCursor += vertexStride; - - // V3 - *reinterpret_cast<SkPoint3*>(vertexCursor) = {dstRect.fRight, dstRect.fBottom, 1.f}; - *reinterpret_cast<GrColor*>(vertexCursor + colorOffset) = fCurrentColor; - vertexCursor += vertexStride; - - packedIDCursor->fPackedGlyphID = skGlyph->getPackedID(); - packedIDCursor++; - } - - // Use the negative initial origin to make the fVertexBounds {0, 0} based. - SkPoint pt = fBlob->fInitialOrigin; - if (!this->needsTransform()) { - // If the box is in device space, then transform the source space origin to device space. - pt = fBlob->fInitialMatrix.mapXY(pt.x(), pt.y()); - } - fVertexBounds.offset(-pt); -} + , fVertexBounds{SkRect::MakeEmpty()} + , fVertexData{SkSpan<VertexData>{}} { } void GrTextBlob::SubRun::resetBulkUseToken() { fBulkUseToken.reset(); } GrDrawOpAtlas::BulkUseTokenUpdater* GrTextBlob::SubRun::bulkUseToken() { return &fBulkUseToken; } -GrTextStrike* GrTextBlob::SubRun::strike() const { return fStrike.get(); } GrMaskFormat GrTextBlob::SubRun::maskFormat() const { return fMaskFormat; } -size_t GrTextBlob::SubRun::vertexStride() const { - return GetVertexStride(this->maskFormat(), this->hasW()); -} -size_t GrTextBlob::SubRun::colorOffset() const { - return this->hasW() ? offsetof(SDFT3DVertex, color) : offsetof(Mask2DVertex, color); -} -size_t GrTextBlob::SubRun::texCoordOffset() const { - switch (fMaskFormat) { +size_t GrTextBlob::SubRun::vertexStride() const { + switch (this->maskFormat()) { case kA8_GrMaskFormat: - return this->hasW() ? offsetof(SDFT3DVertex, atlasPos) - : offsetof(Mask2DVertex, atlasPos); + return this->hasW() ? sizeof(Mask3DVertex) : sizeof(Mask2DVertex); case kARGB_GrMaskFormat: - return this->hasW() ? offsetof(ARGB3DVertex, atlasPos) - : offsetof(ARGB2DVertex, atlasPos); + return this->hasW() ? sizeof(ARGB3DVertex) : sizeof(ARGB2DVertex); default: SkASSERT(!this->hasW()); - return offsetof(Mask2DVertex, atlasPos); + return sizeof(Mask2DVertex); } -} - -char* GrTextBlob::SubRun::quadStart(size_t index) const { - return SkTAddOffset<char>(fVertexData.data(), this->quadOffset(index)); + SkUNREACHABLE; } size_t GrTextBlob::SubRun::quadOffset(size_t index) const { return index * kVerticesPerGlyph * this->vertexStride(); } -void GrTextBlob::SubRun::joinGlyphBounds(const SkRect& glyphBounds) { - fVertexBounds.joinNonEmptyArg(glyphBounds); +template <typename Rect> +static auto ltbr(const Rect& r) { + return std::make_tuple(r.left(), r.top(), r.right(), r.bottom()); +} + +void GrTextBlob::SubRun::fillVertexData( + void *vertexDst, int offset, int count, + GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin, SkIRect clip) const { + + SkMatrix matrix = drawMatrix; + matrix.preTranslate(drawOrigin.x(), drawOrigin.y()); + + auto transformed2D = [&](auto dst, SkScalar dstPadding, SkScalar srcPadding) { + SkScalar strikeToSource = fStrikeSpec.strikeToSourceRatio(); + SkPoint inset = {dstPadding, dstPadding}; + for (auto[quad, vertexData] : SkMakeZip(dst, fVertexData.subspan(offset, count))) { + auto[glyph, pos, rect] = vertexData; + auto [l, t, r, b] = rect; + SkPoint sLT = (SkPoint::Make(l, t) + inset) * strikeToSource + pos, + sRB = (SkPoint::Make(r, b) - inset) * strikeToSource + pos; + SkPoint lt = matrix.mapXY(sLT.x(), sLT.y()), + lb = matrix.mapXY(sLT.x(), sRB.y()), + rt = matrix.mapXY(sRB.x(), sLT.y()), + rb = matrix.mapXY(sRB.x(), sRB.y()); + auto[al, at, ar, ab] = glyph.grGlyph->fAtlasLocator.getUVs(srcPadding); + quad[0] = {lt, color, {al, at}}; // L,T + quad[1] = {lb, color, {al, ab}}; // L,B + quad[2] = {rt, color, {ar, at}}; // R,T + quad[3] = {rb, color, {ar, ab}}; // R,B + } + }; + + auto transformed3D = [&](auto dst, SkScalar dstPadding, SkScalar srcPadding) { + SkScalar strikeToSource = fStrikeSpec.strikeToSourceRatio(); + SkPoint inset = {dstPadding, dstPadding}; + auto mapXYZ = [&](SkScalar x, SkScalar y) { + SkPoint pt{x, y}; + SkPoint3 result; + matrix.mapHomogeneousPoints(&result, &pt, 1); + return result; + }; + for (auto[quad, vertexData] : SkMakeZip(dst, fVertexData.subspan(offset, count))) { + auto[glyph, pos, rect] = vertexData; + auto [l, t, r, b] = rect; + SkPoint sLT = (SkPoint::Make(l, t) + inset) * strikeToSource + pos, + sRB = (SkPoint::Make(r, b) - inset) * strikeToSource + pos; + SkPoint3 lt = mapXYZ(sLT.x(), sLT.y()), + lb = mapXYZ(sLT.x(), sRB.y()), + rt = mapXYZ(sRB.x(), sLT.y()), + rb = mapXYZ(sRB.x(), sRB.y()); + auto[al, at, ar, ab] = glyph.grGlyph->fAtlasLocator.getUVs(srcPadding); + quad[0] = {lt, color, {al, at}}; // L,T + quad[1] = {lb, color, {al, ab}}; // L,B + quad[2] = {rt, color, {ar, at}}; // R,T + quad[3] = {rb, color, {ar, ab}}; // R,B + } + }; + + auto direct2D = [&](auto dst, SkIRect* clip) { + // Rectangles in device space + SkPoint originInDeviceSpace = matrix.mapXY(0, 0); + for (auto[quad, vertexData] : SkMakeZip(dst, fVertexData.subspan(offset, count))) { + auto[glyph, pos, rect] = vertexData; + auto[l, t, r, b] = rect; + auto[fx, fy] = pos + originInDeviceSpace; + auto[al, at, ar, ab] = glyph.grGlyph->fAtlasLocator.getUVs(0); + if (clip == nullptr) { + SkScalar dx = SkScalarRoundToScalar(fx), + dy = SkScalarRoundToScalar(fy); + auto[dl, dt, dr, db] = SkRect::MakeLTRB(l + dx, t + dy, r + dx, b + dy); + quad[0] = {{dl, dt}, color, {al, at}}; // L,T + quad[1] = {{dl, db}, color, {al, ab}}; // L,B + quad[2] = {{dr, dt}, color, {ar, at}}; // R,T + quad[3] = {{dr, db}, color, {ar, ab}}; // R,B + } else { + int dx = SkScalarRoundToInt(fx), + dy = SkScalarRoundToInt(fy); + SkIRect devIRect = SkIRect::MakeLTRB(l + dx, t + dy, r + dx, b + dy); + SkScalar dl, dt, dr, db; + uint16_t tl, tt, tr, tb; + if (!clip->containsNoEmptyCheck(devIRect)) { + if (SkIRect clipped; clipped.intersect(devIRect, *clip)) { + int lD = clipped.left() - devIRect.left(); + int tD = clipped.top() - devIRect.top(); + int rD = clipped.right() - devIRect.right(); + int bD = clipped.bottom() - devIRect.bottom(); + int indexLT, indexRB; + std::tie(dl, dt, dr, db) = ltbr(clipped); + std::tie(tl, tt, indexLT) = + GrDrawOpAtlas::UnpackIndexFromTexCoords(al, at); + std::tie(tr, tb, indexRB) = + GrDrawOpAtlas::UnpackIndexFromTexCoords(ar, ab); + std::tie(tl, tt) = + GrDrawOpAtlas::PackIndexInTexCoords(tl + lD, tt + tD, indexLT); + std::tie(tr, tb) = + GrDrawOpAtlas::PackIndexInTexCoords(tr + rD, tb + bD, indexRB); + } else { + // TODO: omit generating any vertex data for fully clipped glyphs ? + std::tie(dl, dt, dr, db) = std::make_tuple(0, 0, 0, 0); + std::tie(tl, tt, tr, tb) = std::make_tuple(0, 0, 0, 0); + } + + } else { + std::tie(dl, dt, dr, db) = ltbr(devIRect); + std::tie(tl, tt, tr, tb) = std::tie(al, at, ar, ab); + } + quad[0] = {{dl, dt}, color, {tl, tt}}; // L,T + quad[1] = {{dl, db}, color, {tl, tb}}; // L,B + quad[2] = {{dr, dt}, color, {tr, tt}}; // R,T + quad[3] = {{dr, db}, color, {tr, tb}}; // R,B + } + } + }; + + switch (fType) { + case kDirectMask: { + if (clip.isEmpty()) { + if (this->maskFormat() != kARGB_GrMaskFormat) { + using Quad = Mask2DVertex[4]; + SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph); + direct2D((Quad*) vertexDst, nullptr); + } else { + using Quad = ARGB2DVertex[4]; + SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph); + direct2D((Quad*) vertexDst, nullptr); + } + } else { + if (this->maskFormat() != kARGB_GrMaskFormat) { + using Quad = Mask2DVertex[4]; + SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph); + direct2D((Quad*) vertexDst, &clip); + } else { + using Quad = ARGB2DVertex[4]; + SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph); + direct2D((Quad*) vertexDst, &clip); + } + } + break; + } + case kTransformedMask: { + if (!this->hasW()) { + if (this->maskFormat() == GrMaskFormat::kARGB_GrMaskFormat) { + using Quad = ARGB2DVertex[4]; + SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph); + transformed2D((Quad*) vertexDst, 0, 1); + } else { + using Quad = Mask2DVertex[4]; + SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph); + transformed2D((Quad*) vertexDst, 0, 1); + } + } else { + if (this->maskFormat() == GrMaskFormat::kARGB_GrMaskFormat) { + using Quad = ARGB3DVertex[4]; + SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph); + transformed3D((Quad*) vertexDst, 0, 1); + } else { + using Quad = Mask3DVertex[4]; + SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph); + transformed3D((Quad*) vertexDst, 0, 1); + } + } + break; + } + case kTransformedSDFT: { + if (!this->hasW()) { + using Quad = Mask2DVertex[4]; + SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph); + transformed2D((Quad*) vertexDst, SK_DistanceFieldInset, SK_DistanceFieldInset); + } else { + using Quad = Mask3DVertex[4]; + SkASSERT(sizeof(Quad) == this->vertexStride() * kVerticesPerGlyph); + transformed3D((Quad*) vertexDst, SK_DistanceFieldInset, SK_DistanceFieldInset); + } + break; + } + case kTransformedPath: + SK_ABORT("Paths don't generate vertex data."); + } +} + +int GrTextBlob::SubRun::glyphCount() const { + return fVertexData.count(); } bool GrTextBlob::SubRun::drawAsDistanceFields() const { return fType == kTransformedSDFT; } @@ -204,8 +279,22 @@ bool GrTextBlob::SubRun::needsPadding() const { return fType == kTransformedPath || fType == kTransformedMask; } +int GrTextBlob::SubRun::atlasPadding() const { + return SkTo<int>(this->needsPadding()); +} + +auto GrTextBlob::SubRun::vertexData() const -> SkSpan<const VertexData> { + return fVertexData; +} + bool GrTextBlob::SubRun::hasW() const { - return fBlob->hasW(fType); + if (fType == kTransformedSDFT || fType == kTransformedMask || fType == kTransformedPath) { + return fBlob->hasPerspective(); + } + + // The viewMatrix is implicitly SkMatrix::I when drawing kDirectMask, because it is not + // used. + return false; } void GrTextBlob::SubRun::prepareGrGlyphs(GrStrikeCache* strikeCache) { @@ -215,114 +304,248 @@ void GrTextBlob::SubRun::prepareGrGlyphs(GrStrikeCache* strikeCache) { fStrike = fStrikeSpec.findOrCreateGrStrike(strikeCache); - for (auto& tmp : fGlyphs) { - tmp.fGrGlyph = fStrike->getGlyph(tmp.fPackedGlyphID); + for (auto& tmp : fVertexData) { + tmp.glyph.grGlyph = fStrike->getGlyph(tmp.glyph.packedGlyphID); } } -void GrTextBlob::SubRun::translateVerticesIfNeeded( - const SkMatrix& drawMatrix, SkPoint drawOrigin) { - SkVector translation; +SkRect GrTextBlob::SubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const { + SkRect outBounds = fVertexBounds; if (this->needsTransform()) { - // If transform is needed, then the vertices are in source space, calculate the source - // space translation. - translation = drawOrigin - fCurrentOrigin; + // if the glyph needs transformation offset the by the new origin, and map to device space. + outBounds.offset(drawOrigin); + outBounds = drawMatrix.mapRect(outBounds); } else { - // Calculate the translation in source space to a translation in device space. Calculate - // the translation by mapping (0, 0) through both the current matrix, and the draw - // matrix, and taking the difference. - SkMatrix currentMatrix{fCurrentMatrix}; - currentMatrix.preTranslate(fCurrentOrigin.x(), fCurrentOrigin.y()); - SkPoint currentDeviceOrigin{0, 0}; - currentMatrix.mapPoints(¤tDeviceOrigin, 1); - SkMatrix completeDrawMatrix{drawMatrix}; - completeDrawMatrix.preTranslate(drawOrigin.x(), drawOrigin.y()); - SkPoint drawDeviceOrigin{0, 0}; - completeDrawMatrix.mapPoints(&drawDeviceOrigin, 1); - translation = drawDeviceOrigin - currentDeviceOrigin; + SkPoint offset = drawMatrix.mapXY(drawOrigin.x(), drawOrigin.y()); + // The vertex bounds are already {0, 0} based, so just add the new origin offset. + outBounds.offset(offset); + + // Due to floating point numerical inaccuracies, we have to round out here + outBounds.roundOut(); } + return outBounds; +} - if (translation != SkPoint{0, 0}) { - size_t vertexStride = this->vertexStride(); - for (size_t quad = 0; quad < fGlyphs.size(); quad++) { - SkPoint* vertexCursor = reinterpret_cast<SkPoint*>(quadStart(quad)); - for (int i = 0; i < 4; ++i) { - *vertexCursor += translation; - vertexCursor = SkTAddOffset<SkPoint>(vertexCursor, vertexStride); - } - } - fCurrentMatrix = drawMatrix; - fCurrentOrigin = drawOrigin; +GrGlyph* GrTextBlob::SubRun::grGlyph(int i) const { + return fVertexData[i].glyph.grGlyph; +} + +void GrTextBlob::SubRun::setUseLCDText(bool useLCDText) { fUseLCDText = useLCDText; } +bool GrTextBlob::SubRun::hasUseLCDText() const { return fUseLCDText; } +void GrTextBlob::SubRun::setAntiAliased(bool antiAliased) { fAntiAliased = antiAliased; } +bool GrTextBlob::SubRun::isAntiAliased() const { return fAntiAliased; } +const SkStrikeSpec& GrTextBlob::SubRun::strikeSpec() const { return fStrikeSpec; } + +auto GrTextBlob::SubRun::MakePaths( + const SkZip<SkGlyphVariant, SkPoint>& drawables, + const SkFont& runFont, + const SkStrikeSpec& strikeSpec, + GrTextBlob* blob, + SkArenaAlloc* alloc) -> SubRun* { + SubRun* subRun = alloc->make<SubRun>(blob, strikeSpec); + subRun->setAntiAliased(runFont.hasSomeAntiAliasing()); + for (auto [variant, pos] : drawables) { + subRun->fPaths.emplace_back(*variant.path(), pos); } + return subRun; +}; + +auto GrTextBlob::SubRun::MakeSDFT( + const SkZip<SkGlyphVariant, SkPoint>& drawables, + const SkFont& runFont, + const SkStrikeSpec& strikeSpec, + GrTextBlob* blob, + SkArenaAlloc* alloc) -> SubRun* { + SubRun* subRun = SubRun::InitForAtlas( + kTransformedSDFT, drawables, strikeSpec, kA8_GrMaskFormat, blob, alloc); + subRun->setUseLCDText(runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias); + subRun->setAntiAliased(runFont.hasSomeAntiAliasing()); + return subRun; +} + +auto GrTextBlob::SubRun::MakeDirectMask( + const SkZip<SkGlyphVariant, SkPoint>& drawables, + const SkStrikeSpec& strikeSpec, + GrMaskFormat format, + GrTextBlob* blob, + SkArenaAlloc* alloc) -> SubRun* { + return SubRun::InitForAtlas(kDirectMask, drawables, strikeSpec, format, blob, alloc); } -void GrTextBlob::SubRun::updateVerticesColorIfNeeded(GrColor newColor) { - if (this->maskFormat() != kARGB_GrMaskFormat && fCurrentColor != newColor) { - size_t vertexStride = this->vertexStride(); - size_t colorOffset = this->colorOffset(); - for (size_t quad = 0; quad < fGlyphs.size(); quad++) { - GrColor* colorCursor = SkTAddOffset<GrColor>(quadStart(quad), colorOffset); - for (int i = 0; i < 4; ++i) { - *colorCursor = newColor; - colorCursor = SkTAddOffset<GrColor>(colorCursor, vertexStride); +auto GrTextBlob::SubRun::MakeTransformedMask( + const SkZip<SkGlyphVariant, SkPoint>& drawables, + const SkStrikeSpec& strikeSpec, + GrMaskFormat format, + GrTextBlob* blob, + SkArenaAlloc* alloc) -> SubRun* { + return SubRun::InitForAtlas(kTransformedMask, drawables, strikeSpec, format, blob, alloc); +} + +void GrTextBlob::SubRun::insertSubRunOpsIntoTarget(GrTextTarget* target, + const SkSurfaceProps& props, + const SkPaint& paint, + const GrClip* clip, + const SkMatrixProvider& deviceMatrix, + SkPoint drawOrigin) { + if (this->drawAsPaths()) { + SkPaint runPaint{paint}; + runPaint.setAntiAlias(this->isAntiAliased()); + // If there are shaders, blurs or styles, the path must be scaled into source + // space independently of the CTM. This allows the CTM to be correct for the + // different effects. + GrStyle style(runPaint); + + bool needsExactCTM = runPaint.getShader() + || style.applies() + || runPaint.getMaskFilter(); + + // Calculate the matrix that maps the path glyphs from their size in the strike to + // the graphics source space. + SkScalar scale = this->fStrikeSpec.strikeToSourceRatio(); + SkMatrix strikeToSource = SkMatrix::Scale(scale, scale); + strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y()); + if (!needsExactCTM) { + for (const auto& pathPos : this->fPaths) { + const SkPath& path = pathPos.fPath; + const SkPoint pos = pathPos.fOrigin; // Transform the glyph to source space. + SkMatrix pathMatrix = strikeToSource; + pathMatrix.postTranslate(pos.x(), pos.y()); + SkPreConcatMatrixProvider strikeToDevice(deviceMatrix, pathMatrix); + + GrStyledShape shape(path, paint); + target->drawShape(clip, runPaint, strikeToDevice, shape); + } + } else { + // Transform the path to device because the deviceMatrix must be unchanged to + // draw effect, filter or shader paths. + for (const auto& pathPos : this->fPaths) { + const SkPath& path = pathPos.fPath; + const SkPoint pos = pathPos.fOrigin; + // Transform the glyph to source space. + SkMatrix pathMatrix = strikeToSource; + pathMatrix.postTranslate(pos.x(), pos.y()); + + SkPath deviceOutline; + path.transform(pathMatrix, &deviceOutline); + deviceOutline.setIsVolatile(true); + GrStyledShape shape(deviceOutline, paint); + target->drawShape(clip, runPaint, deviceMatrix, shape); } } - this->fCurrentColor = newColor; + } else { + int glyphCount = this->glyphCount(); + if (0 == glyphCount) { + return; + } + + bool skipClip = false; + SkIRect clipRect = SkIRect::MakeEmpty(); + SkRect rtBounds = SkRect::MakeWH(target->width(), target->height()); + SkRRect clipRRect = SkRRect::MakeRect(rtBounds); + GrAA aa; + // We can clip geometrically if we're not using SDFs or transformed glyphs, + // and we have an axis-aligned rectangular non-AA clip + if (!this->drawAsDistanceFields() && + !this->needsTransform() && + (!clip || (clip->isRRect(&clipRRect, &aa) && + clipRRect.isRect() && GrAA::kNo == aa))) { + // We only need to do clipping work if the subrun isn't contained by the clip + SkRect subRunBounds = this->deviceRect(deviceMatrix.localToDevice(), drawOrigin); + if (!clipRRect.getBounds().contains(subRunBounds)) { + // If the subrun is completely outside, don't add an op for it + if (!clipRRect.getBounds().intersects(subRunBounds)) { + return; + } else { + clipRRect.getBounds().round(&clipRect); + } + } + skipClip = true; + } + + auto op = this->makeOp(deviceMatrix, drawOrigin, clipRect, paint, props, target); + if (op != nullptr) { + target->addDrawOp(skipClip ? nullptr : clip, std::move(op)); + } } } -void GrTextBlob::SubRun::updateTexCoords(int begin, int end) { - SkASSERT(this->isPrepared()); - - const size_t vertexStride = this->vertexStride(); - const size_t texCoordOffset = this->texCoordOffset(); - char* vertex = this->quadStart(begin); - uint16_t* textureCoords = reinterpret_cast<uint16_t*>(vertex + texCoordOffset); - for (int i = begin; i < end; i++) { - GrGlyph* glyph = this->fGlyphs[i].fGrGlyph; - SkASSERT(glyph != nullptr); - - int pad = this->drawAsDistanceFields() ? SK_DistanceFieldInset - : (this->needsPadding() ? 1 : 0); - std::array<uint16_t, 4> uvs = glyph->fAtlasLocator.getUVs(pad); - - textureCoords[0] = uvs[0]; - textureCoords[1] = uvs[1]; - textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride); - textureCoords[0] = uvs[0]; - textureCoords[1] = uvs[3]; - textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride); - textureCoords[0] = uvs[2]; - textureCoords[1] = uvs[1]; - textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride); - textureCoords[0] = uvs[2]; - textureCoords[1] = uvs[3]; - textureCoords = SkTAddOffset<uint16_t>(textureCoords, vertexStride); +SkPMColor4f generate_filtered_color(const SkPaint& paint, const GrColorInfo& colorInfo) { + SkColor4f c = paint.getColor4f(); + if (auto* xform = colorInfo.colorSpaceXformFromSRGB()) { + c = xform->apply(c); + } + if (auto* cf = paint.getColorFilter()) { + c = cf->filterColor4f(c, colorInfo.colorSpace(), colorInfo.colorSpace()); } + return c.premul(); } -SkRect GrTextBlob::SubRun::deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const { - SkRect outBounds = fVertexBounds; - if (this->needsTransform()) { - // if the glyph needs transformation offset the by the new origin, and map to device space. - outBounds.offset(drawOrigin); - outBounds = drawMatrix.mapRect(outBounds); - } else { - SkPoint offset = drawMatrix.mapXY(drawOrigin.x(), drawOrigin.y()); - // The vertex bounds are already {0, 0} based, so just add the new origin offset. - outBounds.offset(offset); +std::unique_ptr<GrAtlasTextOp> GrTextBlob::SubRun::makeOp(const SkMatrixProvider& matrixProvider, + SkPoint drawOrigin, + const SkIRect& clipRect, + const SkPaint& paint, + const SkSurfaceProps& props, + GrTextTarget* target) { + GrPaint grPaint; + target->makeGrPaint(this->maskFormat(), paint, matrixProvider, &grPaint); + const GrColorInfo& colorInfo = target->colorInfo(); + // This is the color the op will use to draw. + SkPMColor4f drawingColor = generate_filtered_color(paint, colorInfo); - // Due to floating point numerical inaccuracies, we have to round out here - outBounds.roundOut(); + if (this->drawAsDistanceFields()) { + // TODO: Can we be even smarter based on the dest transfer function? + return GrAtlasTextOp::MakeDistanceField(target->getContext(), + std::move(grPaint), + this, + matrixProvider.localToDevice(), + drawOrigin, + clipRect, + drawingColor, + target->colorInfo().isLinearlyBlended(), + SkPaintPriv::ComputeLuminanceColor(paint), + props); + } else { + return GrAtlasTextOp::MakeBitmap(target->getContext(), + std::move(grPaint), + this, + matrixProvider.localToDevice(), + drawOrigin, + clipRect, + drawingColor); } - return outBounds; } -void GrTextBlob::SubRun::setUseLCDText(bool useLCDText) { fFlags.useLCDText = useLCDText; } -bool GrTextBlob::SubRun::hasUseLCDText() const { return fFlags.useLCDText; } -void GrTextBlob::SubRun::setAntiAliased(bool antiAliased) { fFlags.antiAliased = antiAliased; } -bool GrTextBlob::SubRun::isAntiAliased() const { return fFlags.antiAliased; } -const SkStrikeSpec& GrTextBlob::SubRun::strikeSpec() const { return fStrikeSpec; } +auto GrTextBlob::SubRun::InitForAtlas(SubRunType type, + const SkZip<SkGlyphVariant, SkPoint>& drawables, + const SkStrikeSpec& strikeSpec, + GrMaskFormat format, + GrTextBlob* blob, + SkArenaAlloc* alloc) -> SubRun* { + size_t vertexCount = drawables.size(); + using Data = VertexData; + SkRect bounds = SkRectPriv::MakeLargestInverted(); + auto initializer = [&, strikeToSource=strikeSpec.strikeToSourceRatio()](size_t i) { + auto [variant, pos] = drawables[i]; + SkGlyph* skGlyph = variant; + int16_t l = skGlyph->left(); + int16_t t = skGlyph->top(); + int16_t r = l + skGlyph->width(); + int16_t b = t + skGlyph->height(); + SkPoint lt = SkPoint::Make(l, t) * strikeToSource + pos, + rb = SkPoint::Make(r, b) * strikeToSource + pos; + + bounds.joinPossiblyEmptyRect(SkRect::MakeLTRB(lt.x(), lt.y(), rb.x(), rb.y())); + return Data{{skGlyph->getPackedID()}, pos, {l, t, r, b}}; + }; + + SkSpan<Data> vertexData{ + alloc->makeInitializedArray<Data>(vertexCount, initializer), vertexCount}; + + SubRun* subRun = alloc->make<SubRun>(type, blob, strikeSpec, format, bounds, vertexData); + + return subRun; +} + // -- GrTextBlob ----------------------------------------------------------------------------------- void GrTextBlob::operator delete(void* p) { ::operator delete(p); } @@ -331,33 +554,12 @@ void* GrTextBlob::operator new(size_t, void* p) { return p; } GrTextBlob::~GrTextBlob() = default; -sk_sp<GrTextBlob> GrTextBlob::Make(const SkGlyphRunList& glyphRunList, - const SkMatrix& drawMatrix, - GrColor color, - bool forceWForDistanceFields) { - - static_assert(sizeof(ARGB2DVertex) <= sizeof(Mask2DVertex)); - static_assert(alignof(ARGB2DVertex) <= alignof(Mask2DVertex)); - size_t quadSize = sizeof(Mask2DVertex) * kVerticesPerGlyph; - if (drawMatrix.hasPerspective() || forceWForDistanceFields) { - static_assert(sizeof(ARGB3DVertex) <= sizeof(SDFT3DVertex)); - static_assert(alignof(ARGB3DVertex) <= alignof(SDFT3DVertex)); - quadSize = sizeof(SDFT3DVertex) * kVerticesPerGlyph; - } - - // We can use the alignment of SDFT3DVertex as a proxy for all Vertex alignments. - static_assert(alignof(SDFT3DVertex) >= alignof(Mask2DVertex)); - // Assume there is no padding needed between glyph pointers and vertices. - static_assert(alignof(GrGlyph*) >= alignof(SDFT3DVertex)); - - // In the arena, the layout is GrGlyph*... | SDFT3DVertex... | SubRun, so there is no padding - // between GrGlyph* and SDFT3DVertex, but padding is needed between the Mask2DVertex array - // and the SubRun. - size_t vertexToSubRunPadding = alignof(SDFT3DVertex) - alignof(SubRun); - size_t arenaSize = - sizeof(GrGlyph*) * glyphRunList.totalGlyphCount() - + quadSize * glyphRunList.totalGlyphCount() - + glyphRunList.runCount() * (sizeof(SubRun) + vertexToSubRunPadding); +sk_sp<GrTextBlob> GrTextBlob::Make(const SkGlyphRunList& glyphRunList, const SkMatrix& drawMatrix) { + // The difference in alignment from the storage of VertexData to SubRun; + constexpr size_t alignDiff = alignof(SubRun) - alignof(SubRun::VertexData); + constexpr size_t vertexDataToSubRunPadding = alignDiff > 0 ? alignDiff : 0; + size_t arenaSize = sizeof(SubRun::VertexData) * glyphRunList.totalGlyphCount() + + glyphRunList.runCount() * (sizeof(SubRun) + vertexDataToSubRunPadding); size_t allocationSize = sizeof(GrTextBlob) + arenaSize; @@ -365,8 +567,7 @@ sk_sp<GrTextBlob> GrTextBlob::Make(const SkGlyphRunList& glyphRunList, SkColor initialLuminance = SkPaintPriv::ComputeLuminanceColor(glyphRunList.paint()); sk_sp<GrTextBlob> blob{new (allocation) GrTextBlob{ - arenaSize, drawMatrix, glyphRunList.origin(), - color, initialLuminance, forceWForDistanceFields}}; + arenaSize, drawMatrix, glyphRunList.origin(), initialLuminance}}; return blob; } @@ -400,42 +601,31 @@ void GrTextBlob::setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax) { fMinMaxScale = std::min(scaledMax, fMinMaxScale); } -size_t GrTextBlob::GetVertexStride(GrMaskFormat maskFormat, bool hasWCoord) { - switch (maskFormat) { - case kA8_GrMaskFormat: - return hasWCoord ? sizeof(SDFT3DVertex) : sizeof(Mask2DVertex); - case kARGB_GrMaskFormat: - return hasWCoord ? sizeof(ARGB3DVertex) : sizeof(ARGB2DVertex); - default: - SkASSERT(!hasWCoord); - return sizeof(Mask2DVertex); - } -} - -bool GrTextBlob::mustRegenerate(const SkPaint& paint, bool anyRunHasSubpixelPosition, - const SkMaskFilterBase::BlurRec& blurRec, - const SkMatrix& drawMatrix, SkPoint drawOrigin) { +bool GrTextBlob::canReuse(const SkPaint& paint, + const SkMaskFilterBase::BlurRec& blurRec, + const SkMatrix& drawMatrix, + SkPoint drawOrigin) { // If we have LCD text then our canonical color will be set to transparent, in this case we have // to regenerate the blob on any color change // We use the grPaint to get any color filter effects if (fKey.fCanonicalColor == SK_ColorTRANSPARENT && fInitialLuminance != SkPaintPriv::ComputeLuminanceColor(paint)) { - return true; + return false; } if (fInitialMatrix.hasPerspective() != drawMatrix.hasPerspective()) { - return true; + return false; } /** This could be relaxed for blobs with only distance field glyphs. */ if (fInitialMatrix.hasPerspective() && !SkMatrixPriv::CheapEqual(fInitialMatrix, drawMatrix)) { - return true; + return false; } // We only cache one masked version if (fKey.fHasBlur && (fBlurRec.fSigma != blurRec.fSigma || fBlurRec.fStyle != blurRec.fStyle)) { - return true; + return false; } // Similarly, we only cache one version for each style @@ -443,15 +633,14 @@ bool GrTextBlob::mustRegenerate(const SkPaint& paint, bool anyRunHasSubpixelPosi (fStrokeInfo.fFrameWidth != paint.getStrokeWidth() || fStrokeInfo.fMiterLimit != paint.getStrokeMiter() || fStrokeInfo.fJoin != paint.getStrokeJoin())) { - return true; + return false; } // Mixed blobs must be regenerated. We could probably figure out a way to do integer scrolls // for mixed blobs if this becomes an issue. if (this->hasBitmap() && this->hasDistanceField()) { // Identical view matrices and we can reuse in all cases - return !(SkMatrixPriv::CheapEqual(fInitialMatrix, drawMatrix) && - drawOrigin == fInitialOrigin); + return SkMatrixPriv::CheapEqual(fInitialMatrix, drawMatrix) && drawOrigin == fInitialOrigin; } if (this->hasBitmap()) { @@ -459,7 +648,7 @@ bool GrTextBlob::mustRegenerate(const SkPaint& paint, bool anyRunHasSubpixelPosi fInitialMatrix.getScaleY() != drawMatrix.getScaleY() || fInitialMatrix.getSkewX() != drawMatrix.getSkewX() || fInitialMatrix.getSkewY() != drawMatrix.getSkewY()) { - return true; + return false; } // TODO(herb): this is not needed for full pixel glyph choice, but is needed to adjust @@ -481,7 +670,7 @@ bool GrTextBlob::mustRegenerate(const SkPaint& paint, bool anyRunHasSubpixelPosi SkPoint translation = drawDeviceOrigin - initialDeviceOrigin; if (!SkScalarIsInt(translation.x()) || !SkScalarIsInt(translation.y())) { - return true; + return false; } } else if (this->hasDistanceField()) { // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would result in a different @@ -490,170 +679,31 @@ bool GrTextBlob::mustRegenerate(const SkPaint& paint, bool anyRunHasSubpixelPosi SkScalar oldMaxScale = fInitialMatrix.getMaxScale(); SkScalar scaleAdjust = newMaxScale / oldMaxScale; if (scaleAdjust < fMaxMinScale || scaleAdjust > fMinMaxScale) { - return true; + return false; } } - // It is possible that a blob has neither distanceField nor bitmaptext. This is in the case - // when all of the runs inside the blob are drawn as paths. In this case, we always regenerate - // the blob anyways at flush time, so no need to regenerate explicitly - return false; + // If the blob is all paths, there is no reason to regenerate. + return true; } -void GrTextBlob::addOp(GrTextTarget* target, - const SkSurfaceProps& props, - const SkPaint& paint, - const SkPMColor4f& filteredColor, - const GrClip& clip, - const SkMatrixProvider& deviceMatrix, - SkPoint drawOrigin) { +void GrTextBlob::insertOpsIntoTarget(GrTextTarget* target, + const SkSurfaceProps& props, + const SkPaint& paint, + const GrClip* clip, + const SkMatrixProvider& deviceMatrix, + SkPoint drawOrigin) { for (SubRun* subRun = fFirstSubRun; subRun != nullptr; subRun = subRun->fNextSubRun) { - if (subRun->drawAsPaths()) { - SkPaint runPaint{paint}; - runPaint.setAntiAlias(subRun->isAntiAliased()); - // If there are shaders, blurs or styles, the path must be scaled into source - // space independently of the CTM. This allows the CTM to be correct for the - // different effects. - GrStyle style(runPaint); - - bool needsExactCTM = runPaint.getShader() - || style.applies() - || runPaint.getMaskFilter(); - - // Calculate the matrix that maps the path glyphs from their size in the strike to - // the graphics source space. - SkMatrix strikeToSource = SkMatrix::MakeScale( - subRun->fStrikeSpec.strikeToSourceRatio()); - strikeToSource.postTranslate(drawOrigin.x(), drawOrigin.y()); - if (!needsExactCTM) { - for (const auto& pathPos : subRun->fPaths) { - const SkPath& path = pathPos.fPath; - const SkPoint pos = pathPos.fOrigin; // Transform the glyph to source space. - SkMatrix pathMatrix = strikeToSource; - pathMatrix.postTranslate(pos.x(), pos.y()); - SkPreConcatMatrixProvider strikeToDevice(deviceMatrix, pathMatrix); - - GrStyledShape shape(path, paint); - target->drawShape(clip, runPaint, strikeToDevice, shape); - } - } else { - // Transform the path to device because the deviceMatrix must be unchanged to - // draw effect, filter or shader paths. - for (const auto& pathPos : subRun->fPaths) { - const SkPath& path = pathPos.fPath; - const SkPoint pos = pathPos.fOrigin; - // Transform the glyph to source space. - SkMatrix pathMatrix = strikeToSource; - pathMatrix.postTranslate(pos.x(), pos.y()); - - SkPath deviceOutline; - path.transform(pathMatrix, &deviceOutline); - deviceOutline.setIsVolatile(true); - GrStyledShape shape(deviceOutline, paint); - target->drawShape(clip, runPaint, deviceMatrix, shape); - } - } - } else { - int glyphCount = subRun->fGlyphs.count(); - if (0 == glyphCount) { - continue; - } - - bool skipClip = false; - SkIRect clipRect = SkIRect::MakeEmpty(); - SkRect rtBounds = SkRect::MakeWH(target->width(), target->height()); - SkRRect clipRRect; - GrAA aa; - // We can clip geometrically if we're not using SDFs or transformed glyphs, - // and we have an axis-aligned rectangular non-AA clip - if (!subRun->drawAsDistanceFields() && - !subRun->needsTransform() && - clip.isRRect(rtBounds, &clipRRect, &aa) && - clipRRect.isRect() && GrAA::kNo == aa) { - skipClip = true; - // We only need to do clipping work if the subrun isn't contained by the clip - SkRect subRunBounds = subRun->deviceRect(deviceMatrix.localToDevice(), drawOrigin); - if (!clipRRect.getBounds().contains(subRunBounds)) { - // If the subrun is completely outside, don't add an op for it - if (!clipRRect.getBounds().intersects(subRunBounds)) { - continue; - } else { - clipRRect.getBounds().round(&clipRect); - } - } - } - - auto op = this->makeOp(*subRun, deviceMatrix, drawOrigin, clipRect, - paint, filteredColor, props, target); - if (op) { - if (skipClip) { - target->addDrawOp(GrNoClip(), std::move(op)); - } - else { - target->addDrawOp(clip, std::move(op)); - } - } - } + subRun->insertSubRunOpsIntoTarget(target, props, paint, clip, deviceMatrix, drawOrigin); } } const GrTextBlob::Key& GrTextBlob::key() const { return fKey; } size_t GrTextBlob::size() const { return fSize; } -std::unique_ptr<GrDrawOp> GrTextBlob::test_makeOp(const SkMatrixProvider& matrixProvider, - SkPoint drawOrigin, - const SkPaint& paint, - const SkPMColor4f& filteredColor, - const SkSurfaceProps& props, - GrTextTarget* target) { - SubRun* info = fFirstSubRun; - SkIRect emptyRect = SkIRect::MakeEmpty(); - return this->makeOp(*info, matrixProvider, drawOrigin, emptyRect, paint, - filteredColor, props, target); -} - -bool GrTextBlob::hasW(GrTextBlob::SubRunType type) const { - if (type == kTransformedSDFT) { - return this->hasPerspective() || fForceWForDistanceFields; - } else if (type == kTransformedMask || type == kTransformedPath) { - return this->hasPerspective(); - } - - // The viewMatrix is implicitly SkMatrix::I when drawing kDirectMask, because it is not - // used. - return false; -} - -GrTextBlob::SubRun* GrTextBlob::makeSubRun(SubRunType type, - const SkZip<SkGlyphVariant, SkPoint>& drawables, - const SkStrikeSpec& strikeSpec, - GrMaskFormat format) { - SkSpan<SubRun::PackedGlyphIDorGrGlyph> glyphs{ - fAlloc.makeArrayDefault<SubRun::PackedGlyphIDorGrGlyph>(drawables.size()), drawables.size()}; - bool hasW = this->hasW(type); - - SkASSERT(!fInitialMatrix.hasPerspective() || hasW); - - size_t vertexDataSize = drawables.size() * GetVertexStride(format, hasW) * kVerticesPerGlyph; - SkSpan<char> vertexData{fAlloc.makeArrayDefault<char>(vertexDataSize), vertexDataSize}; - - SubRun* subRun = fAlloc.make<SubRun>(type, this, strikeSpec, format, glyphs, vertexData); - - subRun->appendGlyphs(drawables); - - return subRun; -} - -void GrTextBlob::addSingleMaskFormat( - SubRunType type, - const SkZip<SkGlyphVariant, SkPoint>& drawables, - const SkStrikeSpec& strikeSpec, - GrMaskFormat format) { - this->makeSubRun(type, drawables, strikeSpec, format); -} - +template<typename AddSingleMaskFormat> void GrTextBlob::addMultiMaskFormat( - SubRunType type, + AddSingleMaskFormat addSingle, const SkZip<SkGlyphVariant, SkPoint>& drawables, const SkStrikeSpec& strikeSpec) { this->setHasBitmap(); @@ -668,39 +718,24 @@ void GrTextBlob::addMultiMaskFormat( GrMaskFormat nextFormat = GrGlyph::FormatFromSkGlyph(glyph->maskFormat()); if (format != nextFormat) { auto sameFormat = drawables.subspan(startIndex, i - startIndex); - this->addSingleMaskFormat(type, sameFormat, strikeSpec, format); + SubRun* subRun = addSingle(sameFormat, strikeSpec, format, this, &fAlloc); + this->insertSubRun(subRun); format = nextFormat; startIndex = i; } } auto sameFormat = drawables.last(drawables.size() - startIndex); - this->addSingleMaskFormat(type, sameFormat, strikeSpec, format); -} - -void GrTextBlob::addSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables, - const SkStrikeSpec& strikeSpec, - const SkFont& runFont, - SkScalar minScale, - SkScalar maxScale) { - this->setHasDistanceField(); - this->setMinAndMaxScale(minScale, maxScale); - - SubRun* subRun = this->makeSubRun(kTransformedSDFT, drawables, strikeSpec, kA8_GrMaskFormat); - subRun->setUseLCDText(runFont.getEdging() == SkFont::Edging::kSubpixelAntiAlias); - subRun->setAntiAliased(runFont.hasSomeAntiAliasing()); + SubRun* subRun = addSingle(sameFormat, strikeSpec, format, this, &fAlloc); + this->insertSubRun(subRun); } GrTextBlob::GrTextBlob(size_t allocSize, const SkMatrix& drawMatrix, SkPoint origin, - GrColor color, - SkColor initialLuminance, - bool forceWForDistanceFields) + SkColor initialLuminance) : fSize{allocSize} , fInitialMatrix{drawMatrix} , fInitialOrigin{origin} - , fForceWForDistanceFields{forceWForDistanceFields} - , fColor{color} , fInitialLuminance{initialLuminance} , fAlloc{SkTAddOffset<char>(this, sizeof(GrTextBlob)), allocSize, allocSize/2} { } @@ -714,53 +749,18 @@ void GrTextBlob::insertSubRun(SubRun* subRun) { } } -std::unique_ptr<GrAtlasTextOp> GrTextBlob::makeOp(SubRun& info, - const SkMatrixProvider& matrixProvider, - SkPoint drawOrigin, - const SkIRect& clipRect, - const SkPaint& paint, - const SkPMColor4f& filteredColor, - const SkSurfaceProps& props, - GrTextTarget* target) { - GrPaint grPaint; - target->makeGrPaint(info.maskFormat(), paint, matrixProvider, &grPaint); - if (info.drawAsDistanceFields()) { - // TODO: Can we be even smarter based on the dest transfer function? - return GrAtlasTextOp::MakeDistanceField(target->getContext(), - std::move(grPaint), - &info, - matrixProvider.localToDevice(), - drawOrigin, - clipRect, - filteredColor, - target->colorInfo().isLinearlyBlended(), - SkPaintPriv::ComputeLuminanceColor(paint), - props); - } else { - return GrAtlasTextOp::MakeBitmap(target->getContext(), - std::move(grPaint), - &info, - matrixProvider.localToDevice(), - drawOrigin, - clipRect, - filteredColor); - } -} - void GrTextBlob::processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables, const SkStrikeSpec& strikeSpec) { - this->addMultiMaskFormat(kDirectMask, drawables, strikeSpec); + + this->addMultiMaskFormat(SubRun::MakeDirectMask, drawables, strikeSpec); } void GrTextBlob::processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& drawables, const SkFont& runFont, const SkStrikeSpec& strikeSpec) { this->setHasBitmap(); - SubRun* subRun = fAlloc.make<SubRun>(this, strikeSpec); - subRun->setAntiAliased(runFont.hasSomeAntiAliasing()); - for (auto [variant, pos] : drawables) { - subRun->fPaths.emplace_back(*variant.path(), pos); - } + SubRun* subRun = SubRun::MakePaths(drawables, runFont, strikeSpec, this, &fAlloc); + this->insertSubRun(subRun); } void GrTextBlob::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables, @@ -768,158 +768,18 @@ void GrTextBlob::processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawabl const SkFont& runFont, SkScalar minScale, SkScalar maxScale) { - this->addSDFT(drawables, strikeSpec, runFont, minScale, maxScale); + this->setHasDistanceField(); + this->setMinAndMaxScale(minScale, maxScale); + SubRun* subRun = SubRun::MakeSDFT(drawables, runFont, strikeSpec, this, &fAlloc); + this->insertSubRun(subRun); } void GrTextBlob::processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables, const SkStrikeSpec& strikeSpec) { - this->addMultiMaskFormat(kTransformedMask, drawables, strikeSpec); -} - -// -- Adding a mask to an atlas ---------------------------------------------------------------- - -// expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to -// A8, RGB565, or RGBA8888. -template <typename INT_TYPE> -static void expand_bits(INT_TYPE* dst, - const uint8_t* src, - int width, - int height, - int dstRowBytes, - int srcRowBytes) { - for (int i = 0; i < height; ++i) { - int rowWritesLeft = width; - const uint8_t* s = src; - INT_TYPE* d = dst; - while (rowWritesLeft > 0) { - unsigned mask = *s++; - for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) { - *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0; - } - } - dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes); - src += srcRowBytes; - } -} - -static void get_packed_glyph_image( - const SkGlyph& glyph, int dstRB, GrMaskFormat expectedMaskFormat, void* dst) { - const int width = glyph.width(); - const int height = glyph.height(); - const void* src = glyph.image(); - SkASSERT(src != nullptr); - - GrMaskFormat grMaskFormat = GrGlyph::FormatFromSkGlyph(glyph.maskFormat()); - if (grMaskFormat == expectedMaskFormat) { - int srcRB = glyph.rowBytes(); - // Notice this comparison is with the glyphs raw mask format, and not its GrMaskFormat. - if (glyph.maskFormat() != SkMask::kBW_Format) { - if (srcRB != dstRB) { - const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat); - for (int y = 0; y < height; y++) { - memcpy(dst, src, width * bbp); - src = (const char*) src + srcRB; - dst = (char*) dst + dstRB; - } - } else { - memcpy(dst, src, dstRB * height); - } - } else { - // Handle 8-bit format by expanding the mask to the expected format. - const uint8_t* bits = reinterpret_cast<const uint8_t*>(src); - switch (expectedMaskFormat) { - case kA8_GrMaskFormat: { - uint8_t* bytes = reinterpret_cast<uint8_t*>(dst); - expand_bits(bytes, bits, width, height, dstRB, srcRB); - break; - } - case kA565_GrMaskFormat: { - uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst); - expand_bits(rgb565, bits, width, height, dstRB, srcRB); - break; - } - default: - SK_ABORT("Invalid GrMaskFormat"); - } - } - } else if (grMaskFormat == kA565_GrMaskFormat && expectedMaskFormat == kARGB_GrMaskFormat) { - // Convert if the glyph uses a 565 mask format since it is using LCD text rendering - // but the expected format is 8888 (will happen on macOS with Metal since that - // combination does not support 565). - static constexpr SkMasks masks{ - {0b1111'1000'0000'0000, 11, 5}, // Red - {0b0000'0111'1110'0000, 5, 6}, // Green - {0b0000'0000'0001'1111, 0, 5}, // Blue - {0, 0, 0} // Alpha - }; - const int a565Bpp = GrMaskFormatBytesPerPixel(kA565_GrMaskFormat); - const int argbBpp = GrMaskFormatBytesPerPixel(kARGB_GrMaskFormat); - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - uint16_t color565 = 0; - memcpy(&color565, src, a565Bpp); - uint32_t colorRGBA = GrColorPackRGBA(masks.getRed(color565), - masks.getGreen(color565), - masks.getBlue(color565), - 0xFF); - memcpy(dst, &colorRGBA, argbBpp); - src = (char*)src + a565Bpp; - dst = (char*)dst + argbBpp; - } - } - } else { - // crbug:510931 - // Retrieving the image from the cache can actually change the mask format. This case is - // very uncommon so for now we just draw a clear box for these glyphs. - const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat); - for (int y = 0; y < height; y++) { - sk_bzero(dst, width * bpp); - dst = (char*)dst + dstRB; - } - } + this->addMultiMaskFormat(SubRun::MakeTransformedMask, drawables, strikeSpec); } -// returns true if glyph successfully added to texture atlas, false otherwise. If the glyph's -// mask format has changed, then add_glyph_to_atlas will draw a clear box. This will almost never -// happen. -// TODO we can handle some of these cases if we really want to, but the long term solution is to -// get the actual glyph image itself when we get the glyph metrics. -static GrDrawOpAtlas::ErrorCode add_glyph_to_atlas(const SkGlyph& skGlyph, - GrMaskFormat expectedMaskFormat, - bool needsPadding, - GrResourceProvider* resourceProvider, - GrDeferredUploadTarget* target, - GrAtlasManager* fullAtlasManager, - GrGlyph* grGlyph) { - SkASSERT(grGlyph != nullptr); - SkASSERT(skGlyph.image() != nullptr); - - expectedMaskFormat = fullAtlasManager->resolveMaskFormat(expectedMaskFormat); - int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat); - - SkDEBUGCODE(bool isSDFGlyph = skGlyph.maskFormat() == SkMask::kSDF_Format;) - SkASSERT(!needsPadding || !isSDFGlyph); - - // Add 1 pixel padding around grGlyph if needed. - const int width = needsPadding ? skGlyph.width() + 2 : skGlyph.width(); - const int height = needsPadding ? skGlyph.height() + 2 : skGlyph.height(); - int rowBytes = width * bytesPerPixel; - size_t size = height * rowBytes; - - // Temporary storage for normalizing grGlyph image. - SkAutoSMalloc<1024> storage(size); - void* dataPtr = storage.get(); - if (needsPadding) { - sk_bzero(dataPtr, size); - // Advance in one row and one column. - dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel; - } - - get_packed_glyph_image(skGlyph, rowBytes, expectedMaskFormat, dataPtr); - - return fullAtlasManager->addToAtlas(resourceProvider, target, expectedMaskFormat, width, height, - storage.get(), &grGlyph->fAtlasLocator); -} +auto GrTextBlob::firstSubRun() const -> SubRun* { return fFirstSubRun; } // -- GrTextBlob::VertexRegenerator ---------------------------------------------------------------- GrTextBlob::VertexRegenerator::VertexRegenerator(GrResourceProvider* resourceProvider, @@ -935,43 +795,32 @@ std::tuple<bool, int> GrTextBlob::VertexRegenerator::updateTextureCoordinates( const int begin, const int end) { SkASSERT(fSubRun->isPrepared()); - const SkStrikeSpec& strikeSpec = fSubRun->strikeSpec(); - if (!fMetricsAndImages.isValid() || - fMetricsAndImages->descriptor() != strikeSpec.descriptor()) { - fMetricsAndImages.init(strikeSpec); - } + SkBulkGlyphMetricsAndImages metricsAndImages{fSubRun->strikeSpec()}; // Update the atlas information in the GrStrike. - auto code = GrDrawOpAtlas::ErrorCode::kSucceeded; auto tokenTracker = fUploadTarget->tokenTracker(); - int i = begin; - for (; i < end; i++) { - GrGlyph* grGlyph = fSubRun->fGlyphs[i].fGrGlyph; - SkASSERT(grGlyph); + auto vertexData = fSubRun->vertexData().subspan(begin, end - begin); + int glyphsPlacedInAtlas = 0; + for (auto [glyph, pos, rect] : vertexData) { + GrGlyph* grGlyph = glyph.grGlyph; + SkASSERT(grGlyph != nullptr); if (!fFullAtlasManager->hasGlyph(fSubRun->maskFormat(), grGlyph)) { - const SkGlyph& skGlyph = *fMetricsAndImages->glyph(grGlyph->fPackedID); - if (skGlyph.image() == nullptr) { - return {false, 0}; - } - code = add_glyph_to_atlas(skGlyph, fSubRun->maskFormat(), - fSubRun->needsPadding(), fResourceProvider, - fUploadTarget, fFullAtlasManager, grGlyph); + const SkGlyph& skGlyph = *metricsAndImages.glyph(grGlyph->fPackedID); + auto code = fFullAtlasManager->addGlyphToAtlas( + skGlyph, fSubRun->atlasPadding(), grGlyph, fResourceProvider, fUploadTarget); if (code != GrDrawOpAtlas::ErrorCode::kSucceeded) { - break; + return {code != GrDrawOpAtlas::ErrorCode::kError, glyphsPlacedInAtlas}; } } fFullAtlasManager->addGlyphToBulkAndSetUseToken( fSubRun->bulkUseToken(), fSubRun->maskFormat(), grGlyph, tokenTracker->nextDrawToken()); + glyphsPlacedInAtlas++; } - int glyphsPlacedInAtlas = i - begin; - // Update the quads with the new atlas coordinates. - fSubRun->updateTexCoords(begin, begin + glyphsPlacedInAtlas); - - return {code != GrDrawOpAtlas::ErrorCode::kError, glyphsPlacedInAtlas}; + return {true, glyphsPlacedInAtlas}; } std::tuple<bool, int> GrTextBlob::VertexRegenerator::regenerate(int begin, int end) { @@ -984,15 +833,16 @@ std::tuple<bool, int> GrTextBlob::VertexRegenerator::regenerate(int begin, int e auto [success, glyphsPlacedInAtlas] = this->updateTextureCoordinates(begin, end); // Update atlas generation if there are no more glyphs to put in the atlas. - if (success && begin + glyphsPlacedInAtlas == fSubRun->fGlyphs.count()) { + if (success && begin + glyphsPlacedInAtlas == fSubRun->glyphCount()) { // Need to get the freshest value of the atlas' generation because // updateTextureCoordinates may have changed it. fSubRun->fAtlasGeneration = fFullAtlasManager->atlasGeneration(fSubRun->maskFormat()); } + return {success, glyphsPlacedInAtlas}; } else { // The atlas hasn't changed, so our texture coordinates are still valid. - if (end == fSubRun->fGlyphs.count()) { + if (end == fSubRun->glyphCount()) { // The atlas hasn't changed and the texture coordinates are all still valid. Update // all the plots used to the new use token. fFullAtlasManager->setUseTokenBulk(*fSubRun->bulkUseToken(), diff --git a/chromium/third_party/skia/src/gpu/text/GrTextBlob.h b/chromium/third_party/skia/src/gpu/text/GrTextBlob.h index 98f813a258c..ab04255c2da 100644 --- a/chromium/third_party/skia/src/gpu/text/GrTextBlob.h +++ b/chromium/third_party/skia/src/gpu/text/GrTextBlob.h @@ -27,7 +27,7 @@ class GrAtlasTextOp; class GrDeferredUploadTarget; class GrGlyph; class GrStrikeCache; -class GrTextContext; +class GrTextTarget; class SkMatrixProvider; class SkSurfaceProps; @@ -61,13 +61,6 @@ public: class SubRun; class VertexRegenerator; - enum SubRunType { - kDirectMask, - kTransformedMask, - kTransformedPath, - kTransformedSDFT - }; - struct Key { Key(); uint32_t fUniqueID; @@ -105,9 +98,7 @@ public: // Make an empty GrTextBlob, with all the invariants set to make the right decisions when // adding SubRuns. static sk_sp<GrTextBlob> Make(const SkGlyphRunList& glyphRunList, - const SkMatrix& drawMatrix, - GrColor color, - bool forceWForDistanceFields); + const SkMatrix& drawMatrix); // Key manipulation functions void setupKey(const GrTextBlob::Key& key, @@ -124,78 +115,30 @@ public: void setHasBitmap(); void setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax); - static size_t GetVertexStride(GrMaskFormat maskFormat, bool hasWCoord); + bool canReuse(const SkPaint& paint, const SkMaskFilterBase::BlurRec& blurRec, + const SkMatrix& drawMatrix, SkPoint drawOrigin); - bool mustRegenerate(const SkPaint&, bool, const SkMaskFilterBase::BlurRec& blurRec, - const SkMatrix& drawMatrix, SkPoint drawOrigin); - - void addOp(GrTextTarget* target, - const SkSurfaceProps& props, - const SkPaint& paint, - const SkPMColor4f& filteredColor, - const GrClip& clip, - const SkMatrixProvider& deviceMatrix, - SkPoint drawOrigin); - - - // Normal text mask, SDFT, or color. - struct Mask2DVertex { - SkPoint devicePos; - GrColor color; - SkIPoint16 atlasPos; - }; - struct ARGB2DVertex { - SkPoint devicePos; - SkIPoint16 atlasPos; - }; - - // Perspective SDFT or SDFT forced to 3D or perspective color. - struct SDFT3DVertex { - SkPoint3 devicePos; - GrColor color; - SkIPoint16 atlasPos; - }; - struct ARGB3DVertex { - SkPoint3 devicePos; - SkIPoint16 atlasPos; - }; + void insertOpsIntoTarget(GrTextTarget* target, + const SkSurfaceProps& props, + const SkPaint& paint, + const GrClip* clip, + const SkMatrixProvider& deviceMatrix, + SkPoint drawOrigin); static const int kVerticesPerGlyph = 4; const Key& key() const; size_t size() const; - // Internal test methods - std::unique_ptr<GrDrawOp> test_makeOp(const SkMatrixProvider& matrixProvider, - SkPoint drawOrigin, - const SkPaint& paint, - const SkPMColor4f& filteredColor, - const SkSurfaceProps&, - GrTextTarget*); - - bool hasW(SubRunType type) const; - - SubRun* makeSubRun(SubRunType type, - const SkZip<SkGlyphVariant, SkPoint>& drawables, - const SkStrikeSpec& strikeSpec, - GrMaskFormat format); - - void addSingleMaskFormat( - SubRunType type, - const SkZip<SkGlyphVariant, SkPoint>& drawables, - const SkStrikeSpec& strikeSpec, - GrMaskFormat format); - + template<typename AddSingleMaskFormat> void addMultiMaskFormat( - SubRunType type, + AddSingleMaskFormat addSingle, const SkZip<SkGlyphVariant, SkPoint>& drawables, const SkStrikeSpec& strikeSpec); - void addSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables, - const SkStrikeSpec& strikeSpec, - const SkFont& runFont, - SkScalar minScale, - SkScalar maxScale); + SubRun* firstSubRun() const; + + bool forceWForDistanceFields() const; private: enum TextType { @@ -212,21 +155,10 @@ private: GrTextBlob(size_t allocSize, const SkMatrix& drawMatrix, SkPoint origin, - GrColor color, - SkColor initialLuminance, - bool forceWForDistanceFields); + SkColor initialLuminance); void insertSubRun(SubRun* subRun); - std::unique_ptr<GrAtlasTextOp> makeOp(SubRun& info, - const SkMatrixProvider& matrixProvider, - SkPoint drawOrigin, - const SkIRect& clipRect, - const SkPaint& paint, - const SkPMColor4f& filteredColor, - const SkSurfaceProps&, - GrTextTarget*); - // Methods to satisfy SkGlyphRunPainterInterface void processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables, const SkStrikeSpec& strikeSpec) override; @@ -254,11 +186,6 @@ private: // blob. const SkPoint fInitialOrigin; - // From the distance field options to force distance fields to have a W coordinate. - const bool fForceWForDistanceFields; - - // The color of the text to draw for solid colors. - const GrColor fColor; const SkColor fInitialLuminance; SkMaskFilterBase::BlurRec fBlurRec; @@ -306,7 +233,6 @@ private: GrResourceProvider* fResourceProvider; GrDeferredUploadTarget* fUploadTarget; GrAtlasManager* fFullAtlasManager; - SkTLazy<SkBulkGlyphMetricsAndImages> fMetricsAndImages; SubRun* fSubRun; }; @@ -314,15 +240,24 @@ private: // Hold data to draw the different types of sub run. SubRuns are produced knowing all the // glyphs that are included in them. class GrTextBlob::SubRun { + enum SubRunType { + kDirectMask, + kTransformedMask, + kTransformedPath, + kTransformedSDFT + }; + public: - // Within a glyph-based subRun, the glyphs are initially recorded as SkPackedGlyphs. At - // flush time they are then converted to GrGlyph's (via the GrTextStrike). Once converted - // they are never converted back. - union PackedGlyphIDorGrGlyph { - PackedGlyphIDorGrGlyph() {} - - SkPackedGlyphID fPackedGlyphID; - GrGlyph* fGrGlyph; + struct VertexData { + union { + // Initially, filled with packed id, but changed to GrGlyph* in the onPrepare stage. + SkPackedGlyphID packedGlyphID; + GrGlyph* grGlyph; + } glyph; + const SkPoint pos; + // The rectangle of the glyphs in strike space. But, for kDirectMask this also implies a + // device space rect. + GrIRect16 rect; }; // SubRun for masks @@ -330,79 +265,144 @@ public: GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec, GrMaskFormat format, - const SkSpan<PackedGlyphIDorGrGlyph>& glyphs, - const SkSpan<char>& vertexData); + SkRect vertexBounds, + const SkSpan<VertexData>& vertexData); // SubRun for paths SubRun(GrTextBlob* textBlob, const SkStrikeSpec& strikeSpec); - void appendGlyphs(const SkZip<SkGlyphVariant, SkPoint>& drawables); - // TODO when this object is more internal, drop the privacy void resetBulkUseToken(); GrDrawOpAtlas::BulkUseTokenUpdater* bulkUseToken(); - GrTextStrike* strike() const; GrMaskFormat maskFormat() const; size_t vertexStride() const; - size_t colorOffset() const; - size_t texCoordOffset() const; - char* quadStart(size_t index) const; size_t quadOffset(size_t index) const; + void fillVertexData( + void* vertexDst, int offset, int count, + GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin, + SkIRect clip) const; - void joinGlyphBounds(const SkRect& glyphBounds); + int glyphCount() const; bool drawAsDistanceFields() const; - bool drawAsPaths() const; bool needsTransform() const; bool needsPadding() const; + int atlasPadding() const; + SkSpan<const VertexData> vertexData() const; + // Acquire a GrTextStrike and convert the SkPackedGlyphIDs to GrGlyphs for this run void prepareGrGlyphs(GrStrikeCache*); // has 'prepareGrGlyphs' been called (i.e., can the GrGlyphs be accessed) ? SkDEBUGCODE(bool isPrepared() const { return SkToBool(fStrike); }) - void translateVerticesIfNeeded(const SkMatrix& drawMatrix, SkPoint drawOrigin); - void updateVerticesColorIfNeeded(GrColor newColor); - void updateTexCoords(int begin, int end); - // The rectangle that surrounds all the glyph bounding boxes in device space. SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const; + GrGlyph* grGlyph(int i) const; + // df properties - void setUseLCDText(bool useLCDText); bool hasUseLCDText() const; - void setAntiAliased(bool antiAliased); bool isAntiAliased() const; const SkStrikeSpec& strikeSpec() const; + static SubRun* MakePaths(const SkZip<SkGlyphVariant, SkPoint>& drawables, + const SkFont& runFont, + const SkStrikeSpec& strikeSpec, + GrTextBlob* blob, + SkArenaAlloc* alloc); + static SubRun* MakeSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables, + const SkFont& runFont, + const SkStrikeSpec& strikeSpec, + GrTextBlob* blob, + SkArenaAlloc* alloc); + static SubRun* MakeDirectMask(const SkZip<SkGlyphVariant, SkPoint>& drawables, + const SkStrikeSpec& strikeSpec, + GrMaskFormat format, + GrTextBlob* blob, + SkArenaAlloc* alloc); + static SubRun* MakeTransformedMask(const SkZip<SkGlyphVariant, SkPoint>& drawables, + const SkStrikeSpec& strikeSpec, + GrMaskFormat format, + GrTextBlob* blob, + SkArenaAlloc* alloc); + + void insertSubRunOpsIntoTarget(GrTextTarget* target, + const SkSurfaceProps& props, + const SkPaint& paint, + const GrClip* clip, + const SkMatrixProvider& deviceMatrix, + SkPoint drawOrigin); + + std::unique_ptr<GrAtlasTextOp> makeOp(const SkMatrixProvider& matrixProvider, + SkPoint drawOrigin, + const SkIRect& clipRect, + const SkPaint& paint, + const SkSurfaceProps&, + GrTextTarget*); + SubRun* fNextSubRun{nullptr}; + GrTextBlob* fBlob; + uint64_t fAtlasGeneration{GrDrawOpAtlas::kInvalidAtlasGeneration}; + +private: + struct AtlasPt { + uint16_t u; + uint16_t v; + }; + + // Normal text mask, SDFT, or color. + struct Mask2DVertex { + SkPoint devicePos; + GrColor color; + AtlasPt atlasPos; + }; + struct ARGB2DVertex { + ARGB2DVertex(SkPoint d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {} + SkPoint devicePos; + AtlasPt atlasPos; + }; + + // Perspective SDFT or SDFT forced to 3D or perspective color. + struct Mask3DVertex { + SkPoint3 devicePos; + GrColor color; + AtlasPt atlasPos; + }; + struct ARGB3DVertex { + ARGB3DVertex(SkPoint3 d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {} + SkPoint3 devicePos; + AtlasPt atlasPos; + }; + + static SubRun* InitForAtlas(SubRunType type, + const SkZip<SkGlyphVariant, SkPoint>& drawables, + const SkStrikeSpec& strikeSpec, + GrMaskFormat format, + GrTextBlob* blob, + SkArenaAlloc* alloc); + bool hasW() const; + void setUseLCDText(bool useLCDText); + void setAntiAliased(bool antiAliased); + bool drawAsPaths() const; + const SubRunType fType; - GrTextBlob* const fBlob; const GrMaskFormat fMaskFormat; - const SkSpan<PackedGlyphIDorGrGlyph> fGlyphs; - const SkSpan<char> fVertexData; + bool fUseLCDText{false}; + bool fAntiAliased{false}; + const SkStrikeSpec fStrikeSpec; sk_sp<GrTextStrike> fStrike; - struct { - bool useLCDText:1; - bool antiAliased:1; - } fFlags{false, false}; - GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken; - uint64_t fAtlasGeneration{GrDrawOpAtlas::kInvalidAtlasGeneration}; - GrColor fCurrentColor; - SkPoint fCurrentOrigin; - SkMatrix fCurrentMatrix; - std::vector<PathGlyph> fPaths; -private: + GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken; // The vertex bounds in device space if needsTransform() is false, otherwise the bounds in // source space. The bounds are the joined rectangles of all the glyphs. - SkRect fVertexBounds = SkRectPriv::MakeLargestInverted(); - bool hasW() const; - + const SkRect fVertexBounds; + const SkSpan<VertexData> fVertexData; + std::vector<PathGlyph> fPaths; }; // SubRun #endif // GrTextBlob_DEFINED diff --git a/chromium/third_party/skia/src/gpu/text/GrTextBlobCache.cpp b/chromium/third_party/skia/src/gpu/text/GrTextBlobCache.cpp index c3a6860231e..29c855e7056 100644 --- a/chromium/third_party/skia/src/gpu/text/GrTextBlobCache.cpp +++ b/chromium/third_party/skia/src/gpu/text/GrTextBlobCache.cpp @@ -9,15 +9,64 @@ DECLARE_SKMESSAGEBUS_MESSAGE(GrTextBlobCache::PurgeBlobMessage) +// This function is captured by the above macro using implementations from SkMessageBus.h static inline bool SkShouldPostMessageToBus( const GrTextBlobCache::PurgeBlobMessage& msg, uint32_t msgBusUniqueID) { return msg.fContextID == msgBusUniqueID; } +GrTextBlobCache::GrTextBlobCache(PurgeMore purgeMore, uint32_t messageBusID) + : fPurgeMore(purgeMore) + , fSizeBudget(kDefaultBudget) + , fMessageBusID(messageBusID) + , fPurgeBlobInbox(messageBusID) { } + GrTextBlobCache::~GrTextBlobCache() { this->freeAll(); } +sk_sp<GrTextBlob> +GrTextBlobCache::makeCachedBlob(const SkGlyphRunList& glyphRunList, const GrTextBlob::Key& key, + const SkMaskFilterBase::BlurRec& blurRec, + const SkMatrix& viewMatrix) { + sk_sp<GrTextBlob> cacheBlob(GrTextBlob::Make(glyphRunList, viewMatrix)); + cacheBlob->setupKey(key, blurRec, glyphRunList.paint()); + this->internalAdd(cacheBlob); + glyphRunList.temporaryShuntBlobNotifyAddedToCache(fMessageBusID); + return cacheBlob; +} + +sk_sp<GrTextBlob> GrTextBlobCache::find(const GrTextBlob::Key& key) const { + const auto* idEntry = fBlobIDCache.find(key.fUniqueID); + return idEntry ? idEntry->find(key) : nullptr; +} + +void GrTextBlobCache::remove(GrTextBlob* blob) { + this->internalRemove(blob); +} + +void GrTextBlobCache::internalRemove(GrTextBlob* blob) { + auto id = GrTextBlob::GetKey(*blob).fUniqueID; + auto* idEntry = fBlobIDCache.find(id); + SkASSERT(idEntry); + + fCurrentSize -= blob->size(); + fBlobList.remove(blob); + idEntry->removeBlob(blob); + if (idEntry->fBlobs.empty()) { + fBlobIDCache.remove(id); + } +} + +void GrTextBlobCache::makeMRU(GrTextBlob* blob) { + if (fBlobList.head() == blob) { + return; + } + + fBlobList.remove(blob); + fBlobList.addToHead(blob); +} + void GrTextBlobCache::freeAll() { fBlobIDCache.foreach([this](uint32_t, BlobIDCacheEntry* entry) { for (const auto& blob : entry->fBlobs) { @@ -33,12 +82,21 @@ void GrTextBlobCache::freeAll() { SkASSERT(fBlobList.isEmpty()); } +void GrTextBlobCache::setBudget(size_t budget) { + fSizeBudget = budget; + this->internalCheckPurge(); +} + void GrTextBlobCache::PostPurgeBlobMessage(uint32_t blobID, uint32_t cacheID) { SkASSERT(blobID != SK_InvalidGenID); SkMessageBus<PurgeBlobMessage>::Post(PurgeBlobMessage(blobID, cacheID)); } void GrTextBlobCache::purgeStaleBlobs() { + this->internalPurgeStaleBlobs(); +} + +void GrTextBlobCache::internalPurgeStaleBlobs() { SkTArray<PurgeBlobMessage> msgs; fPurgeBlobInbox.poll(&msgs); @@ -60,36 +118,93 @@ void GrTextBlobCache::purgeStaleBlobs() { } } -void GrTextBlobCache::checkPurge(GrTextBlob* blob) { +size_t GrTextBlobCache::usedBytes() const { + return fCurrentSize; +} + +void GrTextBlobCache::internalCheckPurge(GrTextBlob* blob) { // First, purge all stale blob IDs. - this->purgeStaleBlobs(); + this->internalPurgeStaleBlobs(); // If we are still over budget, then unref until we are below budget again if (fCurrentSize > fSizeBudget) { - BitmapBlobList::Iter iter; - iter.init(fBlobList, BitmapBlobList::Iter::kTail_IterStart); + TextBlobList::Iter iter; + iter.init(fBlobList, TextBlobList::Iter::kTail_IterStart); GrTextBlob* lruBlob = nullptr; while (fCurrentSize > fSizeBudget && (lruBlob = iter.get()) && lruBlob != blob) { // Backup the iterator before removing and unrefing the blob iter.prev(); - this->remove(lruBlob); + this->internalRemove(lruBlob); } // If we break out of the loop with lruBlob == blob, then we haven't purged enough // use the call back and try to free some more. If we are still overbudget after this, // then this single textblob is over our budget if (blob && lruBlob == blob) { - (*fCallback)(fData); + fPurgeMore(); } -#ifdef SPEW_BUDGET_MESSAGE + #ifdef SPEW_BUDGET_MESSAGE if (fCurrentSize > fSizeBudget) { SkDebugf("Single textblob is larger than our whole budget"); } -#endif + #endif } } +void GrTextBlobCache::internalAdd(sk_sp<GrTextBlob> blob) { + auto id = GrTextBlob::GetKey(*blob).fUniqueID; + auto* idEntry = fBlobIDCache.find(id); + if (!idEntry) { + idEntry = fBlobIDCache.set(id, BlobIDCacheEntry(id)); + } + + // Safe to retain a raw ptr temporarily here, because the cache will hold a ref. + GrTextBlob* rawBlobPtr = blob.get(); + fBlobList.addToHead(rawBlobPtr); + fCurrentSize += blob->size(); + idEntry->addBlob(std::move(blob)); + + this->internalCheckPurge(rawBlobPtr); +} + +GrTextBlobCache::BlobIDCacheEntry::BlobIDCacheEntry() : fID(SK_InvalidGenID) {} + +GrTextBlobCache::BlobIDCacheEntry::BlobIDCacheEntry(uint32_t id) : fID(id) {} + +uint32_t GrTextBlobCache::BlobIDCacheEntry::GetKey(const GrTextBlobCache::BlobIDCacheEntry& entry) { + return entry.fID; +} + +void GrTextBlobCache::BlobIDCacheEntry::addBlob(sk_sp<GrTextBlob> blob) { + SkASSERT(blob); + SkASSERT(GrTextBlob::GetKey(*blob).fUniqueID == fID); + SkASSERT(!this->find(GrTextBlob::GetKey(*blob))); + fBlobs.emplace_back(std::move(blob)); +} + +void GrTextBlobCache::BlobIDCacheEntry::removeBlob(GrTextBlob* blob) { + SkASSERT(blob); + SkASSERT(GrTextBlob::GetKey(*blob).fUniqueID == fID); + + auto index = this->findBlobIndex(GrTextBlob::GetKey(*blob)); + SkASSERT(index >= 0); + + fBlobs.removeShuffle(index); +} +sk_sp<GrTextBlob> GrTextBlobCache::BlobIDCacheEntry::find(const GrTextBlob::Key& key) const { + auto index = this->findBlobIndex(key); + return index < 0 ? nullptr : fBlobs[index]; +} + +int GrTextBlobCache::BlobIDCacheEntry::findBlobIndex(const GrTextBlob::Key& key) const { + for (int i = 0; i < fBlobs.count(); ++i) { + if (GrTextBlob::GetKey(*fBlobs[i]) == key) { + return i; + } + } + return -1; +} diff --git a/chromium/third_party/skia/src/gpu/text/GrTextBlobCache.h b/chromium/third_party/skia/src/gpu/text/GrTextBlobCache.h index 9af2f2c5a1e..6dc46908229 100644 --- a/chromium/third_party/skia/src/gpu/text/GrTextBlobCache.h +++ b/chromium/third_party/skia/src/gpu/text/GrTextBlobCache.h @@ -15,85 +15,30 @@ #include "src/core/SkTextBlobPriv.h" #include "src/gpu/text/GrTextBlob.h" +#include <functional> + class GrTextBlobCache { public: - /** - * The callback function used by the cache when it is still over budget after a purge. The - * passed in 'data' is the same 'data' handed to setOverbudgetCallback. - */ - typedef void (*PFOverBudgetCB)(void* data); - - GrTextBlobCache(PFOverBudgetCB cb, void* data, uint32_t uniqueID) - : fCallback(cb) - , fData(data) - , fSizeBudget(kDefaultBudget) - , fUniqueID(uniqueID) - , fPurgeBlobInbox(uniqueID) { - SkASSERT(cb && data); - } - ~GrTextBlobCache(); + // The callback function used by the cache when it is still over budget after a purge. + using PurgeMore = std::function<void()>; - sk_sp<GrTextBlob> makeBlob(const SkGlyphRunList& glyphRunList, - const SkMatrix& viewMatrix, - GrColor color, - bool forceW) { - return GrTextBlob::Make(glyphRunList, viewMatrix, color, forceW); - } + GrTextBlobCache(PurgeMore purgeMore, uint32_t messageBusID); + ~GrTextBlobCache(); sk_sp<GrTextBlob> makeCachedBlob(const SkGlyphRunList& glyphRunList, const GrTextBlob::Key& key, const SkMaskFilterBase::BlurRec& blurRec, - const SkMatrix& viewMatrix, - GrColor color, - bool forceW) { - sk_sp<GrTextBlob> cacheBlob(this->makeBlob(glyphRunList, viewMatrix, color, forceW)); - cacheBlob->setupKey(key, blurRec, glyphRunList.paint()); - this->add(cacheBlob); - glyphRunList.temporaryShuntBlobNotifyAddedToCache(fUniqueID); - return cacheBlob; - } - - sk_sp<GrTextBlob> find(const GrTextBlob::Key& key) const { - const auto* idEntry = fBlobIDCache.find(key.fUniqueID); - return idEntry ? idEntry->find(key) : nullptr; - } - - void remove(GrTextBlob* blob) { - auto id = GrTextBlob::GetKey(*blob).fUniqueID; - auto* idEntry = fBlobIDCache.find(id); - SkASSERT(idEntry); - - fCurrentSize -= blob->size(); - fBlobList.remove(blob); - idEntry->removeBlob(blob); - if (idEntry->fBlobs.empty()) { - fBlobIDCache.remove(id); - } - } - - void makeMRU(GrTextBlob* blob) { - if (fBlobList.head() == blob) { - return; - } - - fBlobList.remove(blob); - fBlobList.addToHead(blob); - } + const SkMatrix& viewMatrix); - void freeAll(); + sk_sp<GrTextBlob> find(const GrTextBlob::Key& key) const; - // TODO move to SkTextBlob - static void BlobGlyphCount(int* glyphCount, int* runCount, const SkTextBlob* blob) { - SkTextBlobRunIterator itCounter(blob); - for (; !itCounter.done(); itCounter.next(), (*runCount)++) { - *glyphCount += itCounter.glyphCount(); - } - } + void remove(GrTextBlob* blob); - void setBudget(size_t budget) { - fSizeBudget = budget; - this->checkPurge(); - } + void makeMRU(GrTextBlob* blob); + + void freeAll(); + + void setBudget(size_t budget); struct PurgeBlobMessage { PurgeBlobMessage(uint32_t blobID, uint32_t contextUniqueID) @@ -107,84 +52,48 @@ public: void purgeStaleBlobs(); - size_t usedBytes() const { return fCurrentSize; } + size_t usedBytes() const; private: - using BitmapBlobList = SkTInternalLList<GrTextBlob>; + using TextBlobList = SkTInternalLList<GrTextBlob>; struct BlobIDCacheEntry { - BlobIDCacheEntry() : fID(SK_InvalidGenID) {} - explicit BlobIDCacheEntry(uint32_t id) : fID(id) {} - - static uint32_t GetKey(const BlobIDCacheEntry& entry) { - return entry.fID; - } - - void addBlob(sk_sp<GrTextBlob> blob) { - SkASSERT(blob); - SkASSERT(GrTextBlob::GetKey(*blob).fUniqueID == fID); - SkASSERT(!this->find(GrTextBlob::GetKey(*blob))); - - fBlobs.emplace_back(std::move(blob)); - } - - void removeBlob(GrTextBlob* blob) { - SkASSERT(blob); - SkASSERT(GrTextBlob::GetKey(*blob).fUniqueID == fID); - - auto index = this->findBlobIndex(GrTextBlob::GetKey(*blob)); - SkASSERT(index >= 0); - - fBlobs.removeShuffle(index); - } - - sk_sp<GrTextBlob> find(const GrTextBlob::Key& key) const { - auto index = this->findBlobIndex(key); - return index < 0 ? nullptr : fBlobs[index]; - } - - int findBlobIndex(const GrTextBlob::Key& key) const{ - for (int i = 0; i < fBlobs.count(); ++i) { - if (GrTextBlob::GetKey(*fBlobs[i]) == key) { - return i; - } - } - return -1; - } - - uint32_t fID; + BlobIDCacheEntry(); + explicit BlobIDCacheEntry(uint32_t id); + + static uint32_t GetKey(const BlobIDCacheEntry& entry); + + void addBlob(sk_sp<GrTextBlob> blob); + + void removeBlob(GrTextBlob* blob); + + sk_sp<GrTextBlob> find(const GrTextBlob::Key& key) const; + + int findBlobIndex(const GrTextBlob::Key& key) const; + + uint32_t fID; // Current clients don't generate multiple GrAtlasTextBlobs per SkTextBlob, so an array w/ // linear search is acceptable. If usage changes, we should re-evaluate this structure. SkSTArray<1, sk_sp<GrTextBlob>> fBlobs; }; - void add(sk_sp<GrTextBlob> blob) { - auto id = GrTextBlob::GetKey(*blob).fUniqueID; - auto* idEntry = fBlobIDCache.find(id); - if (!idEntry) { - idEntry = fBlobIDCache.set(id, BlobIDCacheEntry(id)); - } - - // Safe to retain a raw ptr temporarily here, because the cache will hold a ref. - GrTextBlob* rawBlobPtr = blob.get(); - fBlobList.addToHead(rawBlobPtr); - fCurrentSize += blob->size(); - idEntry->addBlob(std::move(blob)); + void internalPurgeStaleBlobs(); - this->checkPurge(rawBlobPtr); - } + void internalAdd(sk_sp<GrTextBlob> blob); + void internalRemove(GrTextBlob* blob); - void checkPurge(GrTextBlob* blob = nullptr); + void internalCheckPurge(GrTextBlob* blob = nullptr); - static const int kMinGrowthSize = 1 << 16; static const int kDefaultBudget = 1 << 22; - BitmapBlobList fBlobList; + + TextBlobList fBlobList; SkTHashMap<uint32_t, BlobIDCacheEntry> fBlobIDCache; - PFOverBudgetCB fCallback; - void* fData; + PurgeMore fPurgeMore; size_t fSizeBudget; size_t fCurrentSize{0}; - uint32_t fUniqueID; // unique id to use for messaging + + // In practice 'messageBusID' is always the unique ID of the owning GrContext + uint32_t fMessageBusID; SkMessageBus<PurgeBlobMessage>::Inbox fPurgeBlobInbox; }; diff --git a/chromium/third_party/skia/src/gpu/text/GrTextContext.cpp b/chromium/third_party/skia/src/gpu/text/GrTextContext.cpp deleted file mode 100644 index 59a3d46179f..00000000000 --- a/chromium/third_party/skia/src/gpu/text/GrTextContext.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "src/gpu/text/GrTextContext.h" - -#include "include/core/SkGraphics.h" -#include "include/gpu/GrContext.h" -#include "include/private/SkTo.h" -#include "src/core/SkDistanceFieldGen.h" -#include "src/core/SkDraw.h" -#include "src/core/SkDrawProcs.h" -#include "src/core/SkGlyphRun.h" -#include "src/core/SkMaskFilterBase.h" -#include "src/core/SkPaintPriv.h" -#include "src/gpu/GrCaps.h" -#include "src/gpu/GrRecordingContextPriv.h" -#include "src/gpu/SkGr.h" -#include "src/gpu/ops/GrMeshDrawOp.h" -#include "src/gpu/text/GrSDFMaskFilter.h" -#include "src/gpu/text/GrTextBlobCache.h" - -// DF sizes and thresholds for usage of the small and medium sizes. For example, above -// kSmallDFFontLimit we will use the medium size. The large size is used up until the size at -// which we switch over to drawing as paths as controlled by Options. -static const int kSmallDFFontSize = 32; -static const int kSmallDFFontLimit = 32; -static const int kMediumDFFontSize = 72; -static const int kMediumDFFontLimit = 72; -static const int kLargeDFFontSize = 162; -#ifdef SK_BUILD_FOR_MAC -static const int kLargeDFFontLimit = 162; -static const int kExtraLargeDFFontSize = 256; -#endif - -static const int kDefaultMinDistanceFieldFontSize = 18; -#if defined(SK_BUILD_FOR_ANDROID) -static const int kDefaultMaxDistanceFieldFontSize = 384; -#elif defined(SK_BUILD_FOR_MAC) -static const int kDefaultMaxDistanceFieldFontSize = kExtraLargeDFFontSize; -#else -static const int kDefaultMaxDistanceFieldFontSize = 2 * kLargeDFFontSize; -#endif - -GrTextContext::GrTextContext(const Options& options) : fOptions(options) { - SanitizeOptions(&fOptions); -} - -std::unique_ptr<GrTextContext> GrTextContext::Make(const Options& options) { - return std::unique_ptr<GrTextContext>(new GrTextContext(options)); -} - -SkColor GrTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd) { - SkColor canonicalColor = SkPaintPriv::ComputeLuminanceColor(paint); - if (lcd) { - // This is the correct computation, but there are tons of cases where LCD can be overridden. - // For now we just regenerate if any run in a textblob has LCD. - // TODO figure out where all of these overrides are and see if we can incorporate that logic - // at a higher level *OR* use sRGB - SkASSERT(false); - //canonicalColor = SkMaskGamma::CanonicalColor(canonicalColor); - } else { - // A8, though can have mixed BMP text but it shouldn't matter because BMP text won't have - // gamma corrected masks anyways, nor color - U8CPU lum = SkComputeLuminance(SkColorGetR(canonicalColor), - SkColorGetG(canonicalColor), - SkColorGetB(canonicalColor)); - // reduce to our finite number of bits - canonicalColor = SkMaskGamma::CanonicalColor(SkColorSetRGB(lum, lum, lum)); - } - return canonicalColor; -} - -SkScalerContextFlags GrTextContext::ComputeScalerContextFlags(const GrColorInfo& colorInfo) { - // If we're doing linear blending, then we can disable the gamma hacks. - // Otherwise, leave them on. In either case, we still want the contrast boost: - // TODO: Can we be even smarter about mask gamma based on the dest transfer function? - if (colorInfo.isLinearlyBlended()) { - return SkScalerContextFlags::kBoostContrast; - } else { - return SkScalerContextFlags::kFakeGammaAndBoostContrast; - } -} - -void GrTextContext::SanitizeOptions(Options* options) { - if (options->fMaxDistanceFieldFontSize < 0.f) { - options->fMaxDistanceFieldFontSize = kDefaultMaxDistanceFieldFontSize; - } - if (options->fMinDistanceFieldFontSize < 0.f) { - options->fMinDistanceFieldFontSize = kDefaultMinDistanceFieldFontSize; - } -} - -bool GrTextContext::CanDrawAsDistanceFields(const SkPaint& paint, const SkFont& font, - const SkMatrix& viewMatrix, - const SkSurfaceProps& props, - bool contextSupportsDistanceFieldText, - const Options& options) { - // mask filters modify alpha, which doesn't translate well to distance - if (paint.getMaskFilter() || !contextSupportsDistanceFieldText) { - return false; - } - - // TODO: add some stroking support - if (paint.getStyle() != SkPaint::kFill_Style) { - return false; - } - - if (viewMatrix.hasPerspective()) { - if (!options.fDistanceFieldVerticesAlwaysHaveW) { - return false; - } - } else { - SkScalar maxScale = viewMatrix.getMaxScale(); - SkScalar scaledTextSize = maxScale * font.getSize(); - // Hinted text looks far better at small resolutions - // Scaling up beyond 2x yields undesireable artifacts - if (scaledTextSize < options.fMinDistanceFieldFontSize || - scaledTextSize > options.fMaxDistanceFieldFontSize) { - return false; - } - - bool useDFT = props.isUseDeviceIndependentFonts(); -#if SK_FORCE_DISTANCE_FIELD_TEXT - useDFT = true; -#endif - - if (!useDFT && scaledTextSize < kLargeDFFontSize) { - return false; - } - } - - return true; -} - -SkScalar scaled_text_size(const SkScalar textSize, const SkMatrix& viewMatrix) { - SkScalar scaledTextSize = textSize; - - if (viewMatrix.hasPerspective()) { - // for perspective, we simply force to the medium size - // TODO: compute a size based on approximate screen area - scaledTextSize = kMediumDFFontLimit; - } else { - SkScalar maxScale = viewMatrix.getMaxScale(); - // if we have non-unity scale, we need to choose our base text size - // based on the SkPaint's text size multiplied by the max scale factor - // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? - if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { - scaledTextSize *= maxScale; - } - } - - return scaledTextSize; -} - -SkFont GrTextContext::InitDistanceFieldFont(const SkFont& font, - const SkMatrix& viewMatrix, - const Options& options, - SkScalar* textRatio) { - SkScalar textSize = font.getSize(); - SkScalar scaledTextSize = scaled_text_size(textSize, viewMatrix); - - SkFont dfFont{font}; - - if (scaledTextSize <= kSmallDFFontLimit) { - *textRatio = textSize / kSmallDFFontSize; - dfFont.setSize(SkIntToScalar(kSmallDFFontSize)); - } else if (scaledTextSize <= kMediumDFFontLimit) { - *textRatio = textSize / kMediumDFFontSize; - dfFont.setSize(SkIntToScalar(kMediumDFFontSize)); -#ifdef SK_BUILD_FOR_MAC - } else if (scaledTextSize <= kLargeDFFontLimit) { - *textRatio = textSize / kLargeDFFontSize; - dfFont.setSize(SkIntToScalar(kLargeDFFontSize)); - } else { - *textRatio = textSize / kExtraLargeDFFontSize; - dfFont.setSize(SkIntToScalar(kExtraLargeDFFontSize)); - } -#else - } else { - *textRatio = textSize / kLargeDFFontSize; - dfFont.setSize(SkIntToScalar(kLargeDFFontSize)); - } -#endif - - dfFont.setEdging(SkFont::Edging::kAntiAlias); - dfFont.setForceAutoHinting(false); - dfFont.setHinting(SkFontHinting::kNormal); - - // The sub-pixel position will always happen when transforming to the screen. - dfFont.setSubpixel(false); - return dfFont; -} - -std::pair<SkScalar, SkScalar> GrTextContext::InitDistanceFieldMinMaxScale( - SkScalar textSize, - const SkMatrix& viewMatrix, - const GrTextContext::Options& options) { - - SkScalar scaledTextSize = scaled_text_size(textSize, viewMatrix); - - // We have three sizes of distance field text, and within each size 'bucket' there is a floor - // and ceiling. A scale outside of this range would require regenerating the distance fields - SkScalar dfMaskScaleFloor; - SkScalar dfMaskScaleCeil; - if (scaledTextSize <= kSmallDFFontLimit) { - dfMaskScaleFloor = options.fMinDistanceFieldFontSize; - dfMaskScaleCeil = kSmallDFFontLimit; - } else if (scaledTextSize <= kMediumDFFontLimit) { - dfMaskScaleFloor = kSmallDFFontLimit; - dfMaskScaleCeil = kMediumDFFontLimit; - } else { - dfMaskScaleFloor = kMediumDFFontLimit; - dfMaskScaleCeil = options.fMaxDistanceFieldFontSize; - } - - // Because there can be multiple runs in the blob, we want the overall maxMinScale, and - // minMaxScale to make regeneration decisions. Specifically, we want the maximum minimum scale - // we can tolerate before we'd drop to a lower mip size, and the minimum maximum scale we can - // tolerate before we'd have to move to a large mip size. When we actually test these values - // we look at the delta in scale between the new viewmatrix and the old viewmatrix, and test - // against these values to decide if we can reuse or not(ie, will a given scale change our mip - // level) - SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScaleCeil); - - return std::make_pair(dfMaskScaleFloor / scaledTextSize, dfMaskScaleCeil / scaledTextSize); -} - -SkPaint GrTextContext::InitDistanceFieldPaint(const SkPaint& paint) { - SkPaint dfPaint{paint}; - dfPaint.setMaskFilter(GrSDFMaskFilter::Make()); - return dfPaint; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -#if GR_TEST_UTILS - -#include "src/gpu/GrRenderTargetContext.h" - -GR_DRAW_OP_TEST_DEFINE(GrAtlasTextOp) { - static uint32_t gContextID = SK_InvalidGenID; - static std::unique_ptr<GrTextContext> gTextContext; - static SkSurfaceProps gSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType); - - if (context->priv().contextID() != gContextID) { - gContextID = context->priv().contextID(); - gTextContext = GrTextContext::Make(GrTextContext::Options()); - } - - // Setup dummy SkPaint / GrPaint / GrRenderTargetContext - auto rtc = GrRenderTargetContext::Make( - context, GrColorType::kRGBA_8888, nullptr, SkBackingFit::kApprox, {1024, 1024}); - - SkSimpleMatrixProvider matrixProvider(GrTest::TestMatrixInvertible(random)); - - SkPaint skPaint; - skPaint.setColor(random->nextU()); - - SkFont font; - if (random->nextBool()) { - font.setEdging(SkFont::Edging::kSubpixelAntiAlias); - } else { - font.setEdging(random->nextBool() ? SkFont::Edging::kAntiAlias : SkFont::Edging::kAlias); - } - font.setSubpixel(random->nextBool()); - - const char* text = "The quick brown fox jumps over the lazy dog."; - - // create some random x/y offsets, including negative offsets - static const int kMaxTrans = 1024; - int xPos = (random->nextU() % 2) * 2 - 1; - int yPos = (random->nextU() % 2) * 2 - 1; - int xInt = (random->nextU() % kMaxTrans) * xPos; - int yInt = (random->nextU() % kMaxTrans) * yPos; - - return gTextContext->createOp_TestingOnly(context, gTextContext.get(), rtc.get(), skPaint, font, - matrixProvider, text, xInt, yInt); -} - -#endif diff --git a/chromium/third_party/skia/src/gpu/text/GrTextContext.h b/chromium/third_party/skia/src/gpu/text/GrTextContext.h deleted file mode 100644 index 4b902393e29..00000000000 --- a/chromium/third_party/skia/src/gpu/text/GrTextContext.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2015 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#ifndef GrTextContext_DEFINED -#define GrTextContext_DEFINED - -#include "src/core/SkGlyphRun.h" -#include "src/gpu/GrGeometryProcessor.h" -#include "src/gpu/text/GrTextTarget.h" - -#if GR_TEST_UTILS -#include "src/gpu/GrDrawOpTest.h" -#endif - -class GrDrawOp; -class GrRecordingContext; -class GrRenderTargetContext; -class GrTextBlobCache; -class SkGlyph; -class GrTextBlob; - -/* - * Renders text using some kind of an atlas, ie BitmapText or DistanceField text - */ -class GrTextContext { -public: - struct Options { - /** - * Below this size (in device space) distance field text will not be used. Negative means - * use a default value. - */ - SkScalar fMinDistanceFieldFontSize = -1.f; - /** - * Above this size (in device space) distance field text will not be used and glyphs will - * be rendered from outline as individual paths. Negative means use a default value. - */ - SkScalar fMaxDistanceFieldFontSize = -1.f; - /** Forces all distance field vertices to use 3 components, not just when in perspective. */ - bool fDistanceFieldVerticesAlwaysHaveW = false; - }; - - static std::unique_ptr<GrTextContext> Make(const Options& options); - - void drawGlyphRunList(GrRecordingContext*, - GrTextTarget*, - const GrClip&, - const SkMatrixProvider&, - const SkSurfaceProps&, - const SkGlyphRunList&) const; - -#if GR_TEST_UTILS - std::unique_ptr<GrDrawOp> createOp_TestingOnly(GrRecordingContext*, - GrTextContext*, - GrRenderTargetContext*, - const SkPaint&, - const SkFont&, - const SkMatrixProvider&, - const char* text, - int x, - int y); -#endif - - static void SanitizeOptions(Options* options); - static bool CanDrawAsDistanceFields(const SkPaint&, const SkFont&, const SkMatrix& viewMatrix, - const SkSurfaceProps& props, - bool contextSupportsDistanceFieldText, - const Options& options); - - static SkFont InitDistanceFieldFont(const SkFont& font, - const SkMatrix& viewMatrix, - const Options& options, - SkScalar* textRatio); - - static SkPaint InitDistanceFieldPaint(const SkPaint& paint); - - static std::pair<SkScalar, SkScalar> InitDistanceFieldMinMaxScale(SkScalar textSize, - const SkMatrix& viewMatrix, - const Options& options); - -private: - GrTextContext(const Options& options); - - // sets up the descriptor on the blob and returns a detached cache. Client must attach - static SkColor ComputeCanonicalColor(const SkPaint&, bool lcd); - // Determines if we need to use fake gamma (and contrast boost): - static SkScalerContextFlags ComputeScalerContextFlags(const GrColorInfo&); - - Options fOptions; - -#if GR_TEST_UTILS - static const SkScalerContextFlags kTextBlobOpScalerContextFlags = - SkScalerContextFlags::kFakeGammaAndBoostContrast; - GR_DRAW_OP_TEST_FRIEND(GrAtlasTextOp); -#endif -}; - -#endif // GrTextContext_DEFINED diff --git a/chromium/third_party/skia/src/gpu/text/GrTextTarget.h b/chromium/third_party/skia/src/gpu/text/GrTextTarget.h index 9f88eb72044..7a834ccc5f6 100644 --- a/chromium/third_party/skia/src/gpu/text/GrTextTarget.h +++ b/chromium/third_party/skia/src/gpu/text/GrTextTarget.h @@ -31,9 +31,9 @@ public: const GrColorInfo& colorInfo() const { return fColorInfo; } - virtual void addDrawOp(const GrClip&, std::unique_ptr<GrAtlasTextOp> op) = 0; + virtual void addDrawOp(const GrClip*, std::unique_ptr<GrAtlasTextOp> op) = 0; - virtual void drawShape(const GrClip&, + virtual void drawShape(const GrClip*, const SkPaint&, const SkMatrixProvider&, const GrStyledShape&) = 0; diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkAMDMemoryAllocator.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkAMDMemoryAllocator.cpp index a1339537d6c..03467a24af2 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkAMDMemoryAllocator.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkAMDMemoryAllocator.cpp @@ -98,8 +98,8 @@ GrVkAMDMemoryAllocator::~GrVkAMDMemoryAllocator() { fAllocator = VK_NULL_HANDLE; } -bool GrVkAMDMemoryAllocator::allocateMemoryForImage(VkImage image, AllocationPropertyFlags flags, - GrVkBackendMemory* backendMemory) { +VkResult GrVkAMDMemoryAllocator::allocateImageMemory(VkImage image, AllocationPropertyFlags flags, + GrVkBackendMemory* backendMemory) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); VmaAllocationCreateInfo info; info.flags = 0; @@ -124,16 +124,15 @@ bool GrVkAMDMemoryAllocator::allocateMemoryForImage(VkImage image, AllocationPro VmaAllocation allocation; VkResult result = vmaAllocateMemoryForImage(fAllocator, image, &info, &allocation, nullptr); - if (VK_SUCCESS != result) { - return false; + if (VK_SUCCESS == result) { + *backendMemory = (GrVkBackendMemory)allocation; } - *backendMemory = (GrVkBackendMemory)allocation; - return true; + return result; } -bool GrVkAMDMemoryAllocator::allocateMemoryForBuffer(VkBuffer buffer, BufferUsage usage, - AllocationPropertyFlags flags, - GrVkBackendMemory* backendMemory) { +VkResult GrVkAMDMemoryAllocator::allocateBufferMemory(VkBuffer buffer, BufferUsage usage, + AllocationPropertyFlags flags, + GrVkBackendMemory* backendMemory) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); VmaAllocationCreateInfo info; info.flags = 0; @@ -187,12 +186,11 @@ bool GrVkAMDMemoryAllocator::allocateMemoryForBuffer(VkBuffer buffer, BufferUsag result = vmaAllocateMemoryForBuffer(fAllocator, buffer, &info, &allocation, nullptr); } } - if (VK_SUCCESS != result) { - return false; + if (VK_SUCCESS == result) { + *backendMemory = (GrVkBackendMemory)allocation; } - *backendMemory = (GrVkBackendMemory)allocation; - return true; + return result; } void GrVkAMDMemoryAllocator::freeMemory(const GrVkBackendMemory& memoryHandle) { @@ -225,12 +223,10 @@ void GrVkAMDMemoryAllocator::getAllocInfo(const GrVkBackendMemory& memoryHandle, alloc->fBackendMemory = memoryHandle; } -void* GrVkAMDMemoryAllocator::mapMemory(const GrVkBackendMemory& memoryHandle) { +VkResult GrVkAMDMemoryAllocator::mapMemory(const GrVkBackendMemory& memoryHandle, void** data) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); const VmaAllocation allocation = (const VmaAllocation)memoryHandle; - void* mapPtr; - vmaMapMemory(fAllocator, allocation, &mapPtr); - return mapPtr; + return vmaMapMemory(fAllocator, allocation, data); } void GrVkAMDMemoryAllocator::unmapMemory(const GrVkBackendMemory& memoryHandle) { @@ -239,18 +235,18 @@ void GrVkAMDMemoryAllocator::unmapMemory(const GrVkBackendMemory& memoryHandle) vmaUnmapMemory(fAllocator, allocation); } -void GrVkAMDMemoryAllocator::flushMappedMemory(const GrVkBackendMemory& memoryHandle, - VkDeviceSize offset, VkDeviceSize size) { +VkResult GrVkAMDMemoryAllocator::flushMemory(const GrVkBackendMemory& memoryHandle, + VkDeviceSize offset, VkDeviceSize size) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); const VmaAllocation allocation = (const VmaAllocation)memoryHandle; - vmaFlushAllocation(fAllocator, allocation, offset, size); + return vmaFlushAllocation(fAllocator, allocation, offset, size); } -void GrVkAMDMemoryAllocator::invalidateMappedMemory(const GrVkBackendMemory& memoryHandle, - VkDeviceSize offset, VkDeviceSize size) { +VkResult GrVkAMDMemoryAllocator::invalidateMemory(const GrVkBackendMemory& memoryHandle, + VkDeviceSize offset, VkDeviceSize size) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); const VmaAllocation allocation = (const VmaAllocation)memoryHandle; - vmaFlushAllocation(fAllocator, allocation, offset, size); + return vmaFlushAllocation(fAllocator, allocation, offset, size); } uint64_t GrVkAMDMemoryAllocator::totalUsedMemory() const { diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkAMDMemoryAllocator.h b/chromium/third_party/skia/src/gpu/vk/GrVkAMDMemoryAllocator.h index 5957cd5944f..82a3e31c29c 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkAMDMemoryAllocator.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkAMDMemoryAllocator.h @@ -39,23 +39,22 @@ public: ~GrVkAMDMemoryAllocator() override; - bool allocateMemoryForImage(VkImage image, AllocationPropertyFlags flags, - GrVkBackendMemory*) override; + VkResult allocateImageMemory(VkImage image, AllocationPropertyFlags flags, + GrVkBackendMemory*) override; - bool allocateMemoryForBuffer(VkBuffer buffer, BufferUsage usage, - AllocationPropertyFlags flags, GrVkBackendMemory*) override; + VkResult allocateBufferMemory(VkBuffer buffer, BufferUsage usage, + AllocationPropertyFlags flags, GrVkBackendMemory*) override; void freeMemory(const GrVkBackendMemory&) override; void getAllocInfo(const GrVkBackendMemory&, GrVkAlloc*) const override; - void* mapMemory(const GrVkBackendMemory&) override; + VkResult mapMemory(const GrVkBackendMemory&, void** data) override; void unmapMemory(const GrVkBackendMemory&) override; - void flushMappedMemory(const GrVkBackendMemory&, VkDeviceSize offset, - VkDeviceSize size) override; - void invalidateMappedMemory(const GrVkBackendMemory&, VkDeviceSize offset, - VkDeviceSize size) override; + VkResult flushMemory(const GrVkBackendMemory&, VkDeviceSize offset, VkDeviceSize size) override; + VkResult invalidateMemory(const GrVkBackendMemory&, VkDeviceSize offset, + VkDeviceSize size) override; uint64_t totalUsedMemory() const override; uint64_t totalAllocatedMemory() const override; diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkCaps.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkCaps.cpp index eacce98fc74..5dc79fbd250 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkCaps.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkCaps.cpp @@ -9,6 +9,7 @@ #include "include/gpu/vk/GrVkBackendContext.h" #include "include/gpu/vk/GrVkExtensions.h" #include "src/core/SkCompressedDataUtils.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrProgramDesc.h" #include "src/gpu/GrRenderTarget.h" #include "src/gpu/GrRenderTargetProxy.h" @@ -516,14 +517,20 @@ void GrVkCaps::initGrCaps(const GrVkInterface* vkInterface, static const uint32_t kMaxVertexAttributes = 64; fMaxVertexAttributes = std::min(properties.limits.maxVertexInputAttributes, kMaxVertexAttributes); + // GrCaps::fSampleLocationsSupport refers to the ability to *query* the sample locations (not + // program them). For now we just set this to true if the device uses standard locations, and + // return the standard locations back when queried. if (properties.limits.standardSampleLocations) { fSampleLocationsSupport = true; } + // See skbug.com/10346 +#if 0 if (extensions.hasExtension(VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME, 1)) { // We "disable" multisample by colocating all samples at pixel center. fMultisampleDisableSupport = true; } +#endif if (extensions.hasExtension(VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME, 1)) { fMixedSamplesSupport = true; @@ -1318,22 +1325,6 @@ bool GrVkCaps::isFormatSRGB(const GrBackendFormat& format) const { return format_is_srgb(vkFormat); } -SkImage::CompressionType GrVkCaps::compressionType(const GrBackendFormat& format) const { - VkFormat vkFormat; - if (!format.asVkFormat(&vkFormat)) { - return SkImage::CompressionType::kNone; - } - - switch (vkFormat) { - case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: return SkImage::CompressionType::kETC2_RGB8_UNORM; - case VK_FORMAT_BC1_RGB_UNORM_BLOCK: return SkImage::CompressionType::kBC1_RGB8_UNORM; - case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: return SkImage::CompressionType::kBC1_RGBA8_UNORM; - default: return SkImage::CompressionType::kNone; - } - - SkUNREACHABLE; -} - bool GrVkCaps::isFormatTexturable(const GrBackendFormat& format) const { VkFormat vkFormat; if (!format.asVkFormat(&vkFormat)) { @@ -1531,12 +1522,6 @@ bool GrVkCaps::onAreColorTypeAndFormatCompatible(GrColorType ct, return false; } - SkImage::CompressionType compression = GrVkFormatToCompressionType(vkFormat); - if (compression != SkImage::CompressionType::kNone) { - return ct == (SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x - : GrColorType::kRGBA_8888); - } - const auto& info = this->getFormatInfo(vkFormat); for (int i = 0; i < info.fColorTypeInfoCount; ++i) { if (info.fColorTypeInfos[i].fColorType == ct) { @@ -1579,7 +1564,7 @@ GrBackendFormat GrVkCaps::getBackendFormatFromCompressionType( SkUNREACHABLE; } -GrSwizzle GrVkCaps::getReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const { +GrSwizzle GrVkCaps::onGetReadSwizzle(const GrBackendFormat& format, GrColorType colorType) const { VkFormat vkFormat; SkAssertResult(format.asVkFormat(&vkFormat)); const auto* ycbcrInfo = format.getVkYcbcrConversionInfo(); @@ -1589,6 +1574,7 @@ GrSwizzle GrVkCaps::getReadSwizzle(const GrBackendFormat& format, GrColorType co // onAreColorTypeAndFormatCompatible. return GrSwizzle{"rgba"}; } + const auto& info = this->getFormatInfo(vkFormat); for (int i = 0; i < info.fColorTypeInfoCount; ++i) { const auto& ctInfo = info.fColorTypeInfos[i]; @@ -1641,7 +1627,7 @@ GrCaps::SupportedRead GrVkCaps::onSupportedReadPixelsColorType( return {GrColorType::kUnknown, 0}; } - SkImage::CompressionType compression = GrVkFormatToCompressionType(vkFormat); + SkImage::CompressionType compression = GrBackendFormatToCompressionType(srcBackendFormat); if (compression != SkImage::CompressionType::kNone) { return { SkCompressionTypeIsOpaque(compression) ? GrColorType::kRGB_888x : GrColorType::kRGBA_8888, 0 }; @@ -1716,9 +1702,12 @@ GrProgramDesc GrVkCaps::makeDesc(const GrRenderTarget* rt, const GrProgramInfo& b.add32(GrVkGpu::kShader_PersistentCacheKeyType); GrVkRenderTarget* vkRT = (GrVkRenderTarget*) rt; + + bool needsStencil = programInfo.numStencilSamples() || programInfo.isStencilEnabled(); // TODO: support failure in getSimpleRenderPass - SkASSERT(vkRT->getSimpleRenderPass()); - vkRT->getSimpleRenderPass()->genKey(&b); + const GrVkRenderPass* rp = vkRT->getSimpleRenderPass(needsStencil); + SkASSERT(rp); + rp->genKey(&b); GrStencilSettings stencil = programInfo.nonGLStencilSettings(); stencil.genKey(&b, true); diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkCaps.h b/chromium/third_party/skia/src/gpu/vk/GrVkCaps.h index f136817b2ff..57787c2db42 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkCaps.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkCaps.h @@ -33,7 +33,6 @@ public: const GrVkExtensions& extensions, GrProtected isProtected = GrProtected::kNo); bool isFormatSRGB(const GrBackendFormat&) const override; - SkImage::CompressionType compressionType(const GrBackendFormat&) const override; bool isFormatTexturable(const GrBackendFormat&) const override; bool isVkFormatTexturable(VkFormat) const; @@ -189,7 +188,6 @@ public: return fColorTypeToFormatTable[idx]; } - GrSwizzle getReadSwizzle(const GrBackendFormat&, GrColorType) const override; GrSwizzle getWriteSwizzle(const GrBackendFormat&, GrColorType) const override; uint64_t computeFormatKey(const GrBackendFormat&) const override; @@ -243,6 +241,9 @@ private: SupportedRead onSupportedReadPixelsColorType(GrColorType, const GrBackendFormat&, GrColorType) const override; + GrSwizzle onGetReadSwizzle(const GrBackendFormat&, GrColorType) const override; + + // ColorTypeInfo for a specific format struct ColorTypeInfo { GrColorType fColorType = GrColorType::kUnknown; diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkCommandBuffer.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkCommandBuffer.cpp index e23459b496a..c1dfe13fc52 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkCommandBuffer.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkCommandBuffer.cpp @@ -308,6 +308,7 @@ void GrVkCommandBuffer::drawIndirect(const GrVkGpu* gpu, SkASSERT(fActiveRenderPass); SkASSERT(!indirectBuffer->isCpuBuffer()); this->addingWork(gpu); + this->addResource(indirectBuffer->resource()); GR_VK_CALL(gpu->vkInterface(), CmdDrawIndirect(fCmdBuffer, indirectBuffer->buffer(), offset, @@ -324,6 +325,7 @@ void GrVkCommandBuffer::drawIndexedIndirect(const GrVkGpu* gpu, SkASSERT(fActiveRenderPass); SkASSERT(!indirectBuffer->isCpuBuffer()); this->addingWork(gpu); + this->addResource(indirectBuffer->resource()); GR_VK_CALL(gpu->vkInterface(), CmdDrawIndexedIndirect(fCmdBuffer, indirectBuffer->buffer(), offset, @@ -472,7 +474,7 @@ bool GrVkPrimaryCommandBuffer::beginRenderPass(GrVkGpu* gpu, SkASSERT(!fActiveRenderPass); SkASSERT(renderPass->isCompatible(*target)); - const GrVkFramebuffer* framebuffer = target->getFramebuffer(); + const GrVkFramebuffer* framebuffer = target->getFramebuffer(renderPass->hasStencilAttachment()); if (!framebuffer) { return false; } @@ -499,7 +501,7 @@ bool GrVkPrimaryCommandBuffer::beginRenderPass(GrVkGpu* gpu, GR_VK_CALL(gpu->vkInterface(), CmdBeginRenderPass(fCmdBuffer, &beginInfo, contents)); fActiveRenderPass = renderPass; this->addResource(renderPass); - target->addResources(*this); + target->addResources(*this, renderPass->hasStencilAttachment()); return true; } diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkGpu.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkGpu.cpp index f2ab8104ac8..6bec1c977e9 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkGpu.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkGpu.cpp @@ -14,6 +14,7 @@ #include "src/core/SkCompressedDataUtils.h" #include "src/core/SkConvertPixels.h" #include "src/core/SkMipMap.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrDataUtils.h" #include "src/gpu/GrGeometryProcessor.h" @@ -241,7 +242,6 @@ void GrVkGpu::destroyResources() { fMainCmdPool->getPrimaryCommandBuffer()->end(this); fMainCmdPool->close(); } - SkASSERT(!fTempCmdPool); // wait for all commands to finish VkResult res = VK_CALL(QueueWaitIdle(fQueue)); @@ -286,9 +286,11 @@ void GrVkGpu::destroyResources() { GrVkGpu::~GrVkGpu() { if (!fDisconnected) { this->destroyResources(); - fMemoryAllocator.reset(); } delete fCompiler; + // We don't delete the memory allocator until the very end of the GrVkGpu lifetime so that + // clients can continue to delete backend textures even after a context has been abandoned. + fMemoryAllocator.reset(); } @@ -296,12 +298,10 @@ void GrVkGpu::disconnect(DisconnectType type) { INHERITED::disconnect(type); if (!fDisconnected) { this->destroyResources(); - fMemoryAllocator.reset(); fSemaphoresToWaitOn.reset(); fSemaphoresToSignal.reset(); fMainCmdBuffer = nullptr; - SkASSERT(!fTempCmdBuffer); fDisconnected = true; } } @@ -309,7 +309,8 @@ void GrVkGpu::disconnect(DisconnectType type) { /////////////////////////////////////////////////////////////////////////////// GrOpsRenderPass* GrVkGpu::getOpsRenderPass( - GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds, + GrRenderTarget* rt, GrStencilAttachment* stencil, + GrSurfaceOrigin origin, const SkIRect& bounds, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { @@ -317,49 +318,18 @@ GrOpsRenderPass* GrVkGpu::getOpsRenderPass( fCachedOpsRenderPass.reset(new GrVkOpsRenderPass(this)); } - if (!fCachedOpsRenderPass->set(rt, origin, bounds, colorInfo, stencilInfo, sampledProxies)) { + if (!fCachedOpsRenderPass->set(rt, stencil, origin, bounds, + colorInfo, stencilInfo, sampledProxies)) { return nullptr; } return fCachedOpsRenderPass.get(); } -GrVkPrimaryCommandBuffer* GrVkGpu::getTempCommandBuffer() { - SkASSERT(!fTempCmdPool && !fTempCmdBuffer); - fTempCmdPool = fResourceProvider.findOrCreateCommandPool(); - if (!fTempCmdPool) { - return nullptr; - } - fTempCmdBuffer = fTempCmdPool->getPrimaryCommandBuffer(); - SkASSERT(fTempCmdBuffer); - fTempCmdBuffer->begin(this); - return fTempCmdBuffer; -} - -bool GrVkGpu::submitTempCommandBuffer(SyncQueue sync, sk_sp<GrRefCntedCallback> finishedCallback) { - SkASSERT(fTempCmdBuffer); - - fTempCmdBuffer->end(this); - fTempCmdPool->close(); - - SkASSERT(fMainCmdBuffer->validateNoSharedImageResources(fTempCmdBuffer)); - - fTempCmdBuffer->addFinishedProc(std::move(finishedCallback)); - - SkTArray<GrVkSemaphore::Resource*, false> fEmptySemaphores; - bool didSubmit = fTempCmdBuffer->submitToQueue(this, fQueue, fEmptySemaphores, - fEmptySemaphores); - if (didSubmit && sync == kForce_SyncQueue) { - fTempCmdBuffer->forceSync(this); - } - fTempCmdPool->unref(); - fTempCmdPool = nullptr; - fTempCmdBuffer = nullptr; - return didSubmit; -} - bool GrVkGpu::submitCommandBuffer(SyncQueue sync) { TRACE_EVENT0("skia.gpu", TRACE_FUNC); - SkASSERT(this->currentCommandBuffer()); + if (!this->currentCommandBuffer()) { + return false; + } SkASSERT(!fCachedOpsRenderPass || !fCachedOpsRenderPass->isActive()); if (!this->currentCommandBuffer()->hasWork() && kForce_SyncQueue != sync && @@ -510,6 +480,9 @@ bool GrVkGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int widt GrColorType surfaceColorType, GrColorType bufferColorType, GrGpuBuffer* transferBuffer, size_t bufferOffset, size_t rowBytes) { + if (!this->currentCommandBuffer()) { + return false; + } if (surfaceColorType != bufferColorType) { return false; } @@ -574,6 +547,9 @@ bool GrVkGpu::onTransferPixelsTo(GrTexture* texture, int left, int top, int widt bool GrVkGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int width, int height, GrColorType surfaceColorType, GrColorType bufferColorType, GrGpuBuffer* transferBuffer, size_t offset) { + if (!this->currentCommandBuffer()) { + return false; + } SkASSERT(surface); SkASSERT(transferBuffer); if (fProtectedContext == GrProtected::kYes) { @@ -635,6 +611,10 @@ bool GrVkGpu::onTransferPixelsFrom(GrSurface* surface, int left, int top, int wi void GrVkGpu::resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect& srcRect, const SkIPoint& dstPoint) { + if (!this->currentCommandBuffer()) { + return; + } + SkASSERT(dst); SkASSERT(src && src->numSamples() > 1 && src->msaaImage()); @@ -741,10 +721,9 @@ bool GrVkGpu::uploadTexDataLinear(GrVkTexture* tex, int left, int top, int width // 'individualMipOffsets' is filled in as a side-effect. static size_t fill_in_regions(GrVkCaps* vkCaps, SkTArray<VkBufferImageCopy>* regions, SkTArray<size_t>* individualMipOffsets, + SkImage::CompressionType compression, VkFormat vkFormat, SkISize dimensions, GrMipMapped mipMapped, VkDeviceSize bufferOffset) { - SkImage::CompressionType compression = GrVkFormatToCompressionType(vkFormat); - int numMipLevels = 1; if (mipMapped == GrMipMapped::kYes) { numMipLevels = SkMipMap::ComputeLevelCount(dimensions.width(), dimensions.height()) + 1; @@ -788,6 +767,10 @@ static size_t fill_in_regions(GrVkCaps* vkCaps, SkTArray<VkBufferImageCopy>* reg bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, int left, int top, int width, int height, GrColorType dataColorType, const GrMipLevel texels[], int mipLevelCount) { + if (!this->currentCommandBuffer()) { + return false; + } + SkASSERT(!tex->isLinearTiled()); // The assumption is either that we have no mipmaps, or that our rect is the entire texture SkASSERT(1 == mipLevelCount || @@ -972,9 +955,13 @@ bool GrVkGpu::uploadTexDataOptimal(GrVkTexture* tex, int left, int top, int widt // It's probably possible to roll this into uploadTexDataOptimal, // but for now it's easier to maintain as a separate entity. -bool GrVkGpu::uploadTexDataCompressed(GrVkTexture* uploadTexture, VkFormat vkFormat, +bool GrVkGpu::uploadTexDataCompressed(GrVkTexture* uploadTexture, + SkImage::CompressionType compression, VkFormat vkFormat, SkISize dimensions, GrMipMapped mipMapped, const void* data, size_t dataSize) { + if (!this->currentCommandBuffer()) { + return false; + } SkASSERT(data); SkASSERT(!uploadTexture->isLinearTiled()); // For now the assumption is that our rect is the entire texture. @@ -1009,9 +996,9 @@ bool GrVkGpu::uploadTexDataCompressed(GrVkTexture* uploadTexture, VkFormat vkFor SkTArray<VkBufferImageCopy> regions; SkTArray<size_t> individualMipOffsets; SkDEBUGCODE(size_t combinedBufferSize =) fill_in_regions(fVkCaps.get(), ®ions, - &individualMipOffsets, - vkFormat, dimensions, - mipMapped, bufferOffset); + &individualMipOffsets, compression, + vkFormat, dimensions, mipMapped, + bufferOffset); SkASSERT(dataSize == combinedBufferSize); // Change layout of our target so it can be copied to @@ -1090,6 +1077,9 @@ sk_sp<GrTexture> GrVkGpu::onCreateTexture(SkISize dimensions, } if (levelClearMask) { + if (!this->currentCommandBuffer()) { + return nullptr; + } SkSTArray<1, VkImageSubresourceRange> ranges; bool inRange = false; for (uint32_t i = 0; i < tex->mipLevels(); ++i) { @@ -1165,7 +1155,8 @@ sk_sp<GrTexture> GrVkGpu::onCreateCompressedTexture(SkISize dimensions, return nullptr; } - if (!this->uploadTexDataCompressed(tex.get(), pixelFormat, dimensions, mipMapped, + SkImage::CompressionType compression = GrBackendFormatToCompressionType(format); + if (!this->uploadTexDataCompressed(tex.get(), compression, pixelFormat, dimensions, mipMapped, data, dataSize)) { return nullptr; } @@ -1177,6 +1168,9 @@ sk_sp<GrTexture> GrVkGpu::onCreateCompressedTexture(SkISize dimensions, void GrVkGpu::copyBuffer(GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, VkDeviceSize srcOffset, VkDeviceSize dstOffset, VkDeviceSize size) { + if (!this->currentCommandBuffer()) { + return; + } VkBufferCopy copyRegion; copyRegion.srcOffset = srcOffset; copyRegion.dstOffset = dstOffset; @@ -1186,6 +1180,9 @@ void GrVkGpu::copyBuffer(GrVkBuffer* srcBuffer, GrVkBuffer* dstBuffer, VkDeviceS bool GrVkGpu::updateBuffer(GrVkBuffer* buffer, const void* src, VkDeviceSize offset, VkDeviceSize size) { + if (!this->currentCommandBuffer()) { + return false; + } // Update the buffer this->currentCommandBuffer()->updateBuffer(this, buffer, offset, size, src); @@ -1196,7 +1193,8 @@ bool GrVkGpu::updateBuffer(GrVkBuffer* buffer, const void* src, static bool check_image_info(const GrVkCaps& caps, const GrVkImageInfo& info, - bool needsAllocation) { + bool needsAllocation, + uint32_t graphicsQueueIndex) { if (VK_NULL_HANDLE == info.fImage) { return false; } @@ -1209,6 +1207,18 @@ static bool check_image_info(const GrVkCaps& caps, return false; } + if (info.fCurrentQueueFamily != VK_QUEUE_FAMILY_IGNORED && + info.fCurrentQueueFamily != VK_QUEUE_FAMILY_EXTERNAL && + info.fCurrentQueueFamily != VK_QUEUE_FAMILY_FOREIGN_EXT) { + if (info.fSharingMode == VK_SHARING_MODE_EXCLUSIVE) { + if (info.fCurrentQueueFamily != graphicsQueueIndex) { + return false; + } + } else { + return false; + } + } + if (info.fYcbcrConversionInfo.isValid()) { if (!caps.supportsYcbcrConversion()) { return false; @@ -1254,7 +1264,8 @@ sk_sp<GrTexture> GrVkGpu::onWrapBackendTexture(const GrBackendTexture& backendTe return nullptr; } - if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership)) { + if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership, + this->queueIndex())) { return nullptr; } @@ -1266,10 +1277,10 @@ sk_sp<GrTexture> GrVkGpu::onWrapBackendTexture(const GrBackendTexture& backendTe return nullptr; } - sk_sp<GrVkImageLayout> layout = backendTex.getGrVkImageLayout(); - SkASSERT(layout); + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = backendTex.getMutableState(); + SkASSERT(mutableState); return GrVkTexture::MakeWrappedTexture(this, backendTex.dimensions(), ownership, cacheable, - ioType, imageInfo, std::move(layout)); + ioType, imageInfo, std::move(mutableState)); } sk_sp<GrTexture> GrVkGpu::onWrapCompressedBackendTexture(const GrBackendTexture& beTex, @@ -1280,7 +1291,8 @@ sk_sp<GrTexture> GrVkGpu::onWrapCompressedBackendTexture(const GrBackendTexture& return nullptr; } - if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership)) { + if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership, + this->queueIndex())) { return nullptr; } @@ -1292,10 +1304,10 @@ sk_sp<GrTexture> GrVkGpu::onWrapCompressedBackendTexture(const GrBackendTexture& return nullptr; } - sk_sp<GrVkImageLayout> layout = beTex.getGrVkImageLayout(); - SkASSERT(layout); + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = beTex.getMutableState(); + SkASSERT(mutableState); return GrVkTexture::MakeWrappedTexture(this, beTex.dimensions(), ownership, cacheable, - kRead_GrIOType, imageInfo, std::move(layout)); + kRead_GrIOType, imageInfo, std::move(mutableState)); } sk_sp<GrTexture> GrVkGpu::onWrapRenderableBackendTexture(const GrBackendTexture& backendTex, @@ -1307,7 +1319,8 @@ sk_sp<GrTexture> GrVkGpu::onWrapRenderableBackendTexture(const GrBackendTexture& return nullptr; } - if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership)) { + if (!check_image_info(this->vkCaps(), imageInfo, kAdopt_GrWrapOwnership == ownership, + this->queueIndex())) { return nullptr; } @@ -1324,12 +1337,13 @@ sk_sp<GrTexture> GrVkGpu::onWrapRenderableBackendTexture(const GrBackendTexture& sampleCnt = this->vkCaps().getRenderTargetSampleCount(sampleCnt, imageInfo.fFormat); - sk_sp<GrVkImageLayout> layout = backendTex.getGrVkImageLayout(); - SkASSERT(layout); + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = backendTex.getMutableState(); + SkASSERT(mutableState); return GrVkTextureRenderTarget::MakeWrappedTextureRenderTarget(this, backendTex.dimensions(), sampleCnt, ownership, cacheable, - imageInfo, std::move(layout)); + imageInfo, + std::move(mutableState)); } sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTarget& backendRT) { @@ -1346,7 +1360,7 @@ sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTa return nullptr; } - if (!check_image_info(this->vkCaps(), info, false)) { + if (!check_image_info(this->vkCaps(), info, false, this->queueIndex())) { return nullptr; } @@ -1358,10 +1372,11 @@ sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendRenderTarget(const GrBackendRenderTa return nullptr; } - sk_sp<GrVkImageLayout> layout = backendRT.getGrVkImageLayout(); + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = backendRT.getMutableState(); + SkASSERT(mutableState); sk_sp<GrVkRenderTarget> tgt = GrVkRenderTarget::MakeWrappedRenderTarget( - this, backendRT.dimensions(), 1, info, std::move(layout)); + this, backendRT.dimensions(), 1, info, std::move(mutableState)); // We don't allow the client to supply a premade stencil buffer. We always create one if needed. SkASSERT(!backendRT.stencilBits()); @@ -1378,7 +1393,7 @@ sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendTextureAsRenderTarget(const GrBacken if (!tex.getVkImageInfo(&imageInfo)) { return nullptr; } - if (!check_image_info(this->vkCaps(), imageInfo, false)) { + if (!check_image_info(this->vkCaps(), imageInfo, false, this->queueIndex())) { return nullptr; } @@ -1395,11 +1410,11 @@ sk_sp<GrRenderTarget> GrVkGpu::onWrapBackendTextureAsRenderTarget(const GrBacken return nullptr; } - sk_sp<GrVkImageLayout> layout = tex.getGrVkImageLayout(); - SkASSERT(layout); + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = tex.getMutableState(); + SkASSERT(mutableState); return GrVkRenderTarget::MakeWrappedRenderTarget(this, tex.dimensions(), sampleCnt, imageInfo, - std::move(layout)); + std::move(mutableState)); } sk_sp<GrRenderTarget> GrVkGpu::onWrapVulkanSecondaryCBAsRenderTarget( @@ -1422,6 +1437,9 @@ sk_sp<GrRenderTarget> GrVkGpu::onWrapVulkanSecondaryCBAsRenderTarget( } bool GrVkGpu::onRegenerateMipMapLevels(GrTexture* tex) { + if (!this->currentCommandBuffer()) { + return false; + } auto* vkTex = static_cast<GrVkTexture*>(tex); // don't do anything for linearly tiled textures (can't have mipmaps) if (vkTex->isLinearTiled()) { @@ -1628,17 +1646,17 @@ bool GrVkGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture, GrVkImageInfo info; SkAssertResult(backendTexture.getVkImageInfo(&info)); - sk_sp<GrVkImageLayout> layout = backendTexture.getGrVkImageLayout(); - SkASSERT(layout); + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState = backendTexture.getMutableState(); + SkASSERT(mutableState); sk_sp<GrVkTexture> texture = GrVkTexture::MakeWrappedTexture(this, backendTexture.dimensions(), kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, - kRW_GrIOType, info, layout); + kRW_GrIOType, info, std::move(mutableState)); if (!texture) { return false; } - GrVkPrimaryCommandBuffer* cmdBuffer = this->getTempCommandBuffer(); + GrVkPrimaryCommandBuffer* cmdBuffer = this->currentCommandBuffer(); if (!cmdBuffer) { return false; } @@ -1668,10 +1686,14 @@ bool GrVkGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture, range.levelCount = info.fLevelCount; cmdBuffer->clearColorImage(this, texture.get(), &vkColor, 1, &range); } else { + SkImage::CompressionType compression = GrBackendFormatToCompressionType( + backendTexture.getBackendFormat()); + SkTArray<VkBufferImageCopy> regions; SkTArray<size_t> individualMipOffsets; size_t combinedBufferSize = fill_in_regions(fVkCaps.get(), ®ions, &individualMipOffsets, - info.fFormat, backendTexture.dimensions(), + compression, info.fFormat, + backendTexture.dimensions(), backendTexture.fMipMapped, 0); sk_sp<GrVkTransferBuffer> transferBuffer = @@ -1689,8 +1711,6 @@ bool GrVkGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture, data->compressedData(), data->compressedSize()); } else { SkASSERT(data->type() == BackendTextureData::Type::kColor); - SkImage::CompressionType compression = GrVkFormatToCompressionType(info.fFormat); - result = generate_compressed_data(this, (char*)transferBuffer->map(), compression, backendTexture.dimensions(), backendTexture.fMipMapped, data->color()); @@ -1707,7 +1727,10 @@ bool GrVkGpu::onUpdateBackendTexture(const GrBackendTexture& backendTexture, VK_ACCESS_SHADER_READ_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, false); - return this->submitTempCommandBuffer(kSkip_SyncQueue, std::move(finishedCallback)); + if (finishedCallback) { + this->addFinishedCallback(std::move(finishedCallback)); + } + return true; } GrBackendTexture GrVkGpu::onCreateBackendTexture(SkISize dimensions, @@ -1791,6 +1814,56 @@ GrBackendTexture GrVkGpu::onCreateCompressedBackendTexture( return beTex; } +void set_layout_and_queue_from_mutable_state(GrVkGpu* gpu, GrVkImage* image, + const GrVkSharedImageInfo& newInfo) { + // Even though internally we use this helper for getting src access flags and stages they + // can also be used for general dst flags since we don't know exactly what the client + // plans on using the image for. + VkImageLayout newLayout = newInfo.getImageLayout(); + VkPipelineStageFlags dstStage = GrVkImage::LayoutToPipelineSrcStageFlags(newLayout); + VkAccessFlags dstAccess = GrVkImage::LayoutToSrcAccessMask(newLayout); + image->setImageLayoutAndQueueIndex(gpu, newLayout, dstAccess, dstStage, false, + newInfo.getQueueFamilyIndex()); +} + +bool GrVkGpu::setBackendSurfaceState(GrVkImageInfo info, + sk_sp<GrBackendSurfaceMutableStateImpl> currentState, + SkISize dimensions, + const GrVkSharedImageInfo& newInfo) { + sk_sp<GrVkTexture> texture = GrVkTexture::MakeWrappedTexture( + this, dimensions, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType, info, + std::move(currentState)); + SkASSERT(texture); + if (!texture) { + return false; + } + set_layout_and_queue_from_mutable_state(this, texture.get(), newInfo); + return true; +} + +bool GrVkGpu::setBackendTextureState(const GrBackendTexture& backendTeture, + const GrBackendSurfaceMutableState& newState, + sk_sp<GrRefCntedCallback> finishedCallback) { + GrVkImageInfo info; + SkAssertResult(backendTeture.getVkImageInfo(&info)); + sk_sp<GrBackendSurfaceMutableStateImpl> currentState = backendTeture.getMutableState(); + SkASSERT(currentState); + SkASSERT(newState.fBackend == GrBackend::kVulkan); + return this->setBackendSurfaceState(info, std::move(currentState), backendTeture.dimensions(), + newState.fVkState); +} + +bool GrVkGpu::setBackendRenderTargetState(const GrBackendRenderTarget& backendRenderTarget, + const GrBackendSurfaceMutableState& newState, + sk_sp<GrRefCntedCallback> finishedCallback) { + GrVkImageInfo info; + SkAssertResult(backendRenderTarget.getVkImageInfo(&info)); + sk_sp<GrBackendSurfaceMutableStateImpl> currentState = backendRenderTarget.getMutableState(); + SkASSERT(currentState); + SkASSERT(newState.fBackend == GrBackend::kVulkan); + return this->setBackendSurfaceState(info, std::move(currentState), + backendRenderTarget.dimensions(), newState.fVkState); +} void GrVkGpu::querySampleLocations(GrRenderTarget* renderTarget, SkTArray<SkPoint>* sampleLocations) { @@ -1923,7 +1996,9 @@ void GrVkGpu::addBufferMemoryBarrier(const GrManagedResource* resource, VkPipelineStageFlags dstStageMask, bool byRegion, VkBufferMemoryBarrier* barrier) const { - SkASSERT(this->currentCommandBuffer()); + if (!this->currentCommandBuffer()) { + return; + } SkASSERT(resource); this->currentCommandBuffer()->pipelineBarrier(this, resource, @@ -1956,14 +2031,16 @@ void GrVkGpu::addImageMemoryBarrier(const GrManagedResource* resource, barrier); } -void GrVkGpu::prepareSurfacesForBackendAccessAndExternalIO( - GrSurfaceProxy* proxies[], int numProxies, SkSurface::BackendSurfaceAccess access, - const GrPrepareForExternalIORequests& externalRequests) { +void GrVkGpu::prepareSurfacesForBackendAccessAndStateUpdates( + GrSurfaceProxy* proxies[], + int numProxies, + SkSurface::BackendSurfaceAccess access, + const GrBackendSurfaceMutableState* newState) { SkASSERT(numProxies >= 0); SkASSERT(!numProxies || proxies); // Submit the current command buffer to the Queue. Whether we inserted semaphores or not does // not effect what we do here. - if (numProxies && access == SkSurface::BackendSurfaceAccess::kPresent) { + if (numProxies && (access == SkSurface::BackendSurfaceAccess::kPresent || newState)) { GrVkImage* image; for (int i = 0; i < numProxies; ++i) { SkASSERT(proxies[i]->isInstantiated()); @@ -1974,57 +2051,11 @@ void GrVkGpu::prepareSurfacesForBackendAccessAndExternalIO( SkASSERT(rt); image = static_cast<GrVkRenderTarget*>(rt); } - image->prepareForPresent(this); - } - } - - // Handle requests for preparing for external IO - for (int i = 0; i < externalRequests.fNumImages; ++i) { - SkImage* image = externalRequests.fImages[i]; - if (!image->isTextureBacked()) { - continue; - } - SkImage_GpuBase* gpuImage = static_cast<SkImage_GpuBase*>(as_IB(image)); - const GrSurfaceProxyView* view = gpuImage->view(this->getContext()); - SkASSERT(view && *view); - - if (!view->proxy()->isInstantiated()) { - auto resourceProvider = this->getContext()->priv().resourceProvider(); - if (!view->proxy()->instantiate(resourceProvider)) { - continue; - } - } - - GrTexture* tex = view->proxy()->peekTexture(); - if (!tex) { - continue; - } - GrVkTexture* vkTex = static_cast<GrVkTexture*>(tex); - vkTex->prepareForExternal(this); - } - for (int i = 0; i < externalRequests.fNumSurfaces; ++i) { - SkSurface* surface = externalRequests.fSurfaces[i]; - if (!surface->getCanvas()->getGrContext()) { - continue; - } - SkSurface_Gpu* gpuSurface = static_cast<SkSurface_Gpu*>(surface); - auto* rtc = gpuSurface->getDevice()->accessRenderTargetContext(); - sk_sp<GrRenderTargetProxy> proxy = rtc->asRenderTargetProxyRef(); - if (!proxy->isInstantiated()) { - auto resourceProvider = this->getContext()->priv().resourceProvider(); - if (!proxy->instantiate(resourceProvider)) { - continue; + if (newState) { + const GrVkSharedImageInfo& newInfo = newState->fVkState; + set_layout_and_queue_from_mutable_state(this, image, newInfo); } - } - - GrRenderTarget* rt = proxy->peekRenderTarget(); - SkASSERT(rt); - GrVkRenderTarget* vkRT = static_cast<GrVkRenderTarget*>(rt); - if (externalRequests.fPrepareSurfaceForPresent && - externalRequests.fPrepareSurfaceForPresent[i]) { - vkRT->prepareForPresent(this); - } else { - vkRT->prepareForExternal(this); + image->prepareForPresent(this); } } } @@ -2032,7 +2063,14 @@ void GrVkGpu::prepareSurfacesForBackendAccessAndExternalIO( void GrVkGpu::addFinishedProc(GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { SkASSERT(finishedProc); - fResourceProvider.addFinishedProcToActiveCommandBuffers(finishedProc, finishedContext); + sk_sp<GrRefCntedCallback> finishedCallback( + new GrRefCntedCallback(finishedProc, finishedContext)); + this->addFinishedCallback(std::move(finishedCallback)); +} + +void GrVkGpu::addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback) { + SkASSERT(finishedCallback); + fResourceProvider.addFinishedProcToActiveCommandBuffers(std::move(finishedCallback)); } bool GrVkGpu::onSubmitToGpu(bool syncCpu) { @@ -2053,6 +2091,10 @@ static int get_surface_sample_cnt(GrSurface* surf) { void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, GrSurface* src, GrVkImage* dstImage, GrVkImage* srcImage, const SkIRect& srcRect, const SkIPoint& dstPoint) { + if (!this->currentCommandBuffer()) { + return; + } + #ifdef SK_DEBUG int dstSampleCnt = get_surface_sample_cnt(dst); int srcSampleCnt = get_surface_sample_cnt(src); @@ -2108,6 +2150,10 @@ void GrVkGpu::copySurfaceAsCopyImage(GrSurface* dst, GrSurface* src, GrVkImage* void GrVkGpu::copySurfaceAsBlit(GrSurface* dst, GrSurface* src, GrVkImage* dstImage, GrVkImage* srcImage, const SkIRect& srcRect, const SkIPoint& dstPoint) { + if (!this->currentCommandBuffer()) { + return; + } + #ifdef SK_DEBUG int dstSampleCnt = get_surface_sample_cnt(dst); int srcSampleCnt = get_surface_sample_cnt(src); @@ -2255,6 +2301,10 @@ bool GrVkGpu::onReadPixels(GrSurface* surface, int left, int top, int width, int return false; } + if (!this->currentCommandBuffer()) { + return false; + } + GrVkImage* image = nullptr; GrVkRenderTarget* rt = static_cast<GrVkRenderTarget*>(surface->asRenderTarget()); if (rt) { @@ -2443,6 +2493,9 @@ bool GrVkGpu::beginRenderPass(const GrVkRenderPass* renderPass, const VkClearValue* colorClear, GrVkRenderTarget* target, GrSurfaceOrigin origin, const SkIRect& bounds, bool forSecondaryCB) { + if (!this->currentCommandBuffer()) { + return false; + } SkASSERT (!target->wrapsSecondaryCommandBuffer()); auto nativeBounds = GrNativeRect::MakeRelativeTo(origin, target->height(), bounds); @@ -2478,11 +2531,16 @@ bool GrVkGpu::beginRenderPass(const GrVkRenderPass* renderPass, void GrVkGpu::endRenderPass(GrRenderTarget* target, GrSurfaceOrigin origin, const SkIRect& bounds) { + // We had a command buffer when we started the render pass, we should have one now as well. + SkASSERT(this->currentCommandBuffer()); this->currentCommandBuffer()->endRenderPass(this); this->didWriteToSurface(target, origin, &bounds); } void GrVkGpu::submitSecondaryCommandBuffer(std::unique_ptr<GrVkSecondaryCommandBuffer> buffer) { + if (!this->currentCommandBuffer()) { + return; + } this->currentCommandBuffer()->executeCommands(this, std::move(buffer)); } @@ -2540,6 +2598,8 @@ std::unique_ptr<GrSemaphore> GrVkGpu::wrapBackendSemaphore( } void GrVkGpu::insertSemaphore(GrSemaphore* semaphore) { + SkASSERT(semaphore); + GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(semaphore); GrVkSemaphore::Resource* resource = vkSem->getResource(); @@ -2550,6 +2610,8 @@ void GrVkGpu::insertSemaphore(GrSemaphore* semaphore) { } void GrVkGpu::waitSemaphore(GrSemaphore* semaphore) { + SkASSERT(semaphore); + GrVkSemaphore* vkSem = static_cast<GrVkSemaphore*>(semaphore); GrVkSemaphore::Resource* resource = vkSem->getResource(); diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkGpu.h b/chromium/third_party/skia/src/gpu/vk/GrVkGpu.h index be7a03c12d0..312792ba9d4 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkGpu.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkGpu.h @@ -56,9 +56,7 @@ public: VkDevice device() const { return fDevice; } VkQueue queue() const { return fQueue; } uint32_t queueIndex() const { return fQueueIndex; } - GrVkCommandPool* cmdPool() const { - return fTempCmdPool ? fTempCmdPool : fMainCmdPool; - } + GrVkCommandPool* cmdPool() const { return fMainCmdPool; } const VkPhysicalDeviceProperties& physicalDeviceProperties() const { return fPhysDevProps; } @@ -69,14 +67,20 @@ public: GrVkResourceProvider& resourceProvider() { return fResourceProvider; } - GrVkPrimaryCommandBuffer* currentCommandBuffer() const { - return fTempCmdBuffer ? fTempCmdBuffer : fMainCmdBuffer; - } + GrVkPrimaryCommandBuffer* currentCommandBuffer() const { return fMainCmdBuffer; } void querySampleLocations(GrRenderTarget*, SkTArray<SkPoint>*) override; void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {} + bool setBackendTextureState(const GrBackendTexture&, + const GrBackendSurfaceMutableState&, + sk_sp<GrRefCntedCallback> finishedCallback) override; + + bool setBackendRenderTargetState(const GrBackendRenderTarget&, + const GrBackendSurfaceMutableState&, + sk_sp<GrRefCntedCallback> finishedCallback) override; + void deleteBackendTexture(const GrBackendTexture&) override; bool compile(const GrProgramDesc&, const GrProgramInfo&) override; @@ -98,7 +102,8 @@ public: const GrRenderTarget*, int width, int height, int numStencilSamples) override; GrOpsRenderPass* getOpsRenderPass( - GrRenderTarget*, GrSurfaceOrigin, const SkIRect&, + GrRenderTarget*, GrStencilAttachment*, + GrSurfaceOrigin, const SkIRect&, const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) override; @@ -166,6 +171,8 @@ public: const SkIRect& bounds, bool forSecondaryCB); void endRenderPass(GrRenderTarget* target, GrSurfaceOrigin origin, const SkIRect& bounds); + using GrGpu::setOOMed; + private: enum SyncQueue { kForce_SyncQueue, @@ -196,6 +203,11 @@ private: sk_sp<GrRefCntedCallback> finishedCallback, const BackendTextureData*) override; + bool setBackendSurfaceState(GrVkImageInfo info, + sk_sp<GrBackendSurfaceMutableStateImpl> currentState, + SkISize dimensions, + const GrVkSharedImageInfo& newInfo); + sk_sp<GrTexture> onCreateTexture(SkISize, const GrBackendFormat&, GrRenderable, @@ -255,9 +267,13 @@ private: void addFinishedProc(GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) override; - void prepareSurfacesForBackendAccessAndExternalIO( - GrSurfaceProxy* proxies[], int numProxies, SkSurface::BackendSurfaceAccess access, - const GrPrepareForExternalIORequests& externalRequests) override; + void addFinishedCallback(sk_sp<GrRefCntedCallback> finishedCallback); + + void prepareSurfacesForBackendAccessAndStateUpdates( + GrSurfaceProxy* proxies[], + int numProxies, + SkSurface::BackendSurfaceAccess access, + const GrBackendSurfaceMutableState* newState) override; bool onSubmitToGpu(bool syncCpu) override; @@ -284,8 +300,9 @@ private: GrColorType colorType, const void* data, size_t rowBytes); bool uploadTexDataOptimal(GrVkTexture* tex, int left, int top, int width, int height, GrColorType colorType, const GrMipLevel texels[], int mipLevelCount); - bool uploadTexDataCompressed(GrVkTexture* tex, VkFormat vkFormat, SkISize dimensions, - GrMipMapped mipMapped, const void* data, size_t dataSize); + bool uploadTexDataCompressed(GrVkTexture* tex, SkImage::CompressionType compression, + VkFormat vkFormat, SkISize dimensions, GrMipMapped mipMapped, + const void* data, size_t dataSize); void resolveImage(GrSurface* dst, GrVkRenderTarget* src, const SkIRect& srcRect, const SkIPoint& dstPoint); @@ -297,18 +314,6 @@ private: GrVkImageInfo*, GrProtected); - // Creates a new temporary primary command buffer that will be target of all subsequent commands - // until it is submitted via submitTempCommandBuffer. When the temp command buffer gets - // submitted the main command buffer will begin being the target of commands again. When using a - // a temp command buffer, the caller should not use any resources that may have been used by the - // unsubmitted main command buffer. The reason for this is we've already updated state, like - // image layout, for the resources on the main command buffer even though we haven't submitted - // it yet. Thus if the same resource gets used on the temp our tracking will get thosse state - // updates out of order. It is legal to use a resource on either the temp or main command buffer - // that was used on a previously submitted command buffer; - GrVkPrimaryCommandBuffer* getTempCommandBuffer(); - bool submitTempCommandBuffer(SyncQueue sync, sk_sp<GrRefCntedCallback> finishedCallback); - sk_sp<const GrVkInterface> fInterface; sk_sp<GrVkMemoryAllocator> fMemoryAllocator; sk_sp<GrVkCaps> fVkCaps; @@ -326,10 +331,6 @@ private: // just a raw pointer; object's lifespan is managed by fCmdPool GrVkPrimaryCommandBuffer* fMainCmdBuffer; - GrVkCommandPool* fTempCmdPool = nullptr; - // just a raw pointer; object's lifespan is managed by fCmdPool - GrVkPrimaryCommandBuffer* fTempCmdBuffer = nullptr; - SkSTArray<1, GrVkSemaphore::Resource*> fSemaphoresToWaitOn; SkSTArray<1, GrVkSemaphore::Resource*> fSemaphoresToSignal; diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkImage.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkImage.cpp index 5022f1c54d0..98b24db5b0d 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkImage.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkImage.cpp @@ -13,6 +13,43 @@ #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X) +GrVkImage::GrVkImage(const GrVkGpu* gpu, + const GrVkImageInfo& info, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, + GrBackendObjectOwnership ownership, + bool forSecondaryCB) + : fInfo(info) + , fInitialQueueFamily(info.fCurrentQueueFamily) + , fMutableState(std::move(mutableState)) + , fIsBorrowed(GrBackendObjectOwnership::kBorrowed == ownership) { + SkASSERT(fMutableState->getImageLayout() == fInfo.fImageLayout); + SkASSERT(fMutableState->getQueueFamilyIndex() == fInfo.fCurrentQueueFamily); +#ifdef SK_DEBUG + // We can't transfer from the non graphics queue to the graphics queue since we can't + // release the image from the original queue without having that queue. This limits us in terms + // of the types of queue indices we can handle. + if (info.fCurrentQueueFamily != VK_QUEUE_FAMILY_IGNORED && + info.fCurrentQueueFamily != VK_QUEUE_FAMILY_EXTERNAL && + info.fCurrentQueueFamily != VK_QUEUE_FAMILY_FOREIGN_EXT) { + if (info.fSharingMode == VK_SHARING_MODE_EXCLUSIVE) { + if (info.fCurrentQueueFamily != gpu->queueIndex()) { + SkASSERT(false); + } + } else { + SkASSERT(false); + } + } +#endif + if (forSecondaryCB) { + fResource = nullptr; + } else if (fIsBorrowed) { + fResource = new BorrowedResource(gpu, info.fImage, info.fAlloc, info.fImageTiling); + } else { + SkASSERT(VK_NULL_HANDLE != info.fAlloc.fMemory); + fResource = new Resource(gpu, info.fImage, info.fAlloc, info.fImageTiling); + } +} + VkPipelineStageFlags GrVkImage::LayoutToPipelineSrcStageFlags(const VkImageLayout layout) { if (VK_IMAGE_LAYOUT_GENERAL == layout) { return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT; @@ -82,26 +119,58 @@ VkImageAspectFlags vk_format_to_aspect_flags(VkFormat format) { } } -void GrVkImage::setImageLayout(const GrVkGpu* gpu, VkImageLayout newLayout, - VkAccessFlags dstAccessMask, - VkPipelineStageFlags dstStageMask, - bool byRegion, bool releaseFamilyQueue) { +void GrVkImage::setImageLayoutAndQueueIndex(const GrVkGpu* gpu, + VkImageLayout newLayout, + VkAccessFlags dstAccessMask, + VkPipelineStageFlags dstStageMask, + bool byRegion, + uint32_t newQueueFamilyIndex) { SkASSERT(!gpu->isDeviceLost()); - SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED != newLayout && - VK_IMAGE_LAYOUT_PREINITIALIZED != newLayout); + SkASSERT(newLayout == this->currentLayout() || + (VK_IMAGE_LAYOUT_UNDEFINED != newLayout && + VK_IMAGE_LAYOUT_PREINITIALIZED != newLayout)); VkImageLayout currentLayout = this->currentLayout(); + uint32_t currentQueueIndex = this->currentQueueFamilyIndex(); + +#ifdef SK_DEBUG + if (fInfo.fSharingMode == VK_SHARING_MODE_CONCURRENT) { + if (newQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED) { + SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED || + currentQueueIndex == VK_QUEUE_FAMILY_EXTERNAL || + currentQueueIndex == VK_QUEUE_FAMILY_FOREIGN_EXT); + } else { + SkASSERT(newQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL || + newQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT); + SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED); + } + } else { + SkASSERT(fInfo.fSharingMode == VK_SHARING_MODE_EXCLUSIVE); + if (newQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED || + currentQueueIndex == gpu->queueIndex()) { + SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED || + currentQueueIndex == VK_QUEUE_FAMILY_EXTERNAL || + currentQueueIndex == VK_QUEUE_FAMILY_FOREIGN_EXT || + currentQueueIndex == gpu->queueIndex()); + } else if (newQueueFamilyIndex == VK_QUEUE_FAMILY_EXTERNAL || + newQueueFamilyIndex == VK_QUEUE_FAMILY_FOREIGN_EXT) { + SkASSERT(currentQueueIndex == VK_QUEUE_FAMILY_IGNORED || + currentQueueIndex == gpu->queueIndex()); + } + } +#endif - if (releaseFamilyQueue && fInfo.fCurrentQueueFamily == fInitialQueueFamily && - newLayout == currentLayout) { - // We never transfered the image to this queue and we are releasing it so don't do anything. - return; + if (fInfo.fSharingMode == VK_SHARING_MODE_EXCLUSIVE) { + if (newQueueFamilyIndex == VK_QUEUE_FAMILY_IGNORED) { + newQueueFamilyIndex = gpu->queueIndex(); + } + if (currentQueueIndex == VK_QUEUE_FAMILY_IGNORED) { + currentQueueIndex = gpu->queueIndex(); + } } // If the old and new layout are the same and the layout is a read only layout, there is no need // to put in a barrier unless we also need to switch queues. - if (newLayout == currentLayout && !releaseFamilyQueue && - (fInfo.fCurrentQueueFamily == VK_QUEUE_FAMILY_IGNORED || - fInfo.fCurrentQueueFamily == gpu->queueIndex()) && + if (newLayout == currentLayout && currentQueueIndex == newQueueFamilyIndex && (VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == currentLayout || VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == currentLayout || VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == currentLayout)) { @@ -113,26 +182,6 @@ void GrVkImage::setImageLayout(const GrVkGpu* gpu, VkImageLayout newLayout, VkImageAspectFlags aspectFlags = vk_format_to_aspect_flags(fInfo.fFormat); - uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - if (fInfo.fCurrentQueueFamily != VK_QUEUE_FAMILY_IGNORED && - gpu->queueIndex() != fInfo.fCurrentQueueFamily) { - // The image still is owned by its original queue family and we need to transfer it into - // ours. - SkASSERT(!releaseFamilyQueue); - SkASSERT(fInfo.fCurrentQueueFamily == fInitialQueueFamily); - - srcQueueFamilyIndex = fInfo.fCurrentQueueFamily; - dstQueueFamilyIndex = gpu->queueIndex(); - fInfo.fCurrentQueueFamily = gpu->queueIndex(); - } else if (releaseFamilyQueue) { - // We are releasing the image so we must transfer the image back to its original queue - // family. - srcQueueFamilyIndex = fInfo.fCurrentQueueFamily; - dstQueueFamilyIndex = fInitialQueueFamily; - fInfo.fCurrentQueueFamily = fInitialQueueFamily; - } - VkImageMemoryBarrier imageMemoryBarrier = { VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType nullptr, // pNext @@ -140,8 +189,8 @@ void GrVkImage::setImageLayout(const GrVkGpu* gpu, VkImageLayout newLayout, dstAccessMask, // dstAccessMask currentLayout, // oldLayout newLayout, // newLayout - srcQueueFamilyIndex, // srcQueueFamilyIndex - dstQueueFamilyIndex, // dstQueueFamilyIndex + currentQueueIndex, // srcQueueFamilyIndex + newQueueFamilyIndex, // dstQueueFamilyIndex fInfo.fImage, // image { aspectFlags, 0, fInfo.fLevelCount, 0, 1 } // subresourceRange }; @@ -150,6 +199,7 @@ void GrVkImage::setImageLayout(const GrVkGpu* gpu, VkImageLayout newLayout, &imageMemoryBarrier); this->updateImageLayout(newLayout); + this->setQueueFamilyIndex(newQueueFamilyIndex); } bool GrVkImage::InitImageInfo(GrVkGpu* gpu, const ImageDesc& imageDesc, GrVkImageInfo* info) { @@ -217,6 +267,7 @@ bool GrVkImage::InitImageInfo(GrVkGpu* gpu, const ImageDesc& imageDesc, GrVkImag info->fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED; info->fProtected = (createflags & VK_IMAGE_CREATE_PROTECTED_BIT) ? GrProtected::kYes : GrProtected::kNo; + info->fSharingMode = VK_SHARING_MODE_EXCLUSIVE; return true; } @@ -239,24 +290,17 @@ void GrVkImage::prepareForPresent(GrVkGpu* gpu) { layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; } } - this->setImageLayout(gpu, layout, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, false, true); + this->setImageLayoutAndQueueIndex(gpu, layout, 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, false, + fInitialQueueFamily); } void GrVkImage::prepareForExternal(GrVkGpu* gpu) { - this->setImageLayout(gpu, this->currentLayout(), 0, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, false, - true); + this->setImageLayoutAndQueueIndex(gpu, this->currentLayout(), 0, + VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, false, + fInitialQueueFamily); } -void GrVkImage::releaseImage(GrVkGpu* gpu) { - if (!gpu->isDeviceLost() && fInfo.fCurrentQueueFamily != fInitialQueueFamily) { - // The Vulkan spec is vague on what to put for the dstStageMask here. The spec for image - // memory barrier says the dstStageMask must not be zero. However, in the spec when it talks - // about family queue transfers it says the dstStageMask is ignored and should be set to - // zero. Assuming it really is ignored we set it to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT here - // since it makes the Vulkan validation layers happy. - this->setImageLayout(gpu, this->currentLayout(), 0, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, - false, true); - } +void GrVkImage::releaseImage() { if (fResource) { fResource->removeOwningTexture(); fResource->unref(); @@ -283,7 +327,7 @@ void GrVkImage::BorrowedResource::freeGPUData() const { #if GR_TEST_UTILS void GrVkImage::setCurrentQueueFamilyToGraphicsQueue(GrVkGpu* gpu) { - fInfo.fCurrentQueueFamily = gpu->queueIndex(); + fMutableState->setQueueFamilyIndex(gpu->queueIndex()); } #endif diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkImage.h b/chromium/third_party/skia/src/gpu/vk/GrVkImage.h index fbd15767569..dc4d0531563 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkImage.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkImage.h @@ -12,9 +12,10 @@ #include "include/gpu/GrBackendSurface.h" #include "include/gpu/vk/GrVkTypes.h" #include "include/private/GrTypesPriv.h" +#include "include/private/GrVkTypesPriv.h" +#include "src/gpu/GrBackendSurfaceMutableStateImpl.h" #include "src/gpu/GrManagedResource.h" #include "src/gpu/GrTexture.h" -#include "src/gpu/vk/GrVkImageLayout.h" class GrVkGpu; class GrVkTexture; @@ -24,22 +25,12 @@ private: class Resource; public: - GrVkImage(const GrVkGpu* gpu, const GrVkImageInfo& info, sk_sp<GrVkImageLayout> layout, - GrBackendObjectOwnership ownership, bool forSecondaryCB = false) - : fInfo(info) - , fInitialQueueFamily(info.fCurrentQueueFamily) - , fLayout(std::move(layout)) - , fIsBorrowed(GrBackendObjectOwnership::kBorrowed == ownership) { - SkASSERT(fLayout->getImageLayout() == fInfo.fImageLayout); - if (forSecondaryCB) { - fResource = nullptr; - } else if (fIsBorrowed) { - fResource = new BorrowedResource(gpu, info.fImage, info.fAlloc, info.fImageTiling); - } else { - SkASSERT(VK_NULL_HANDLE != info.fAlloc.fMemory); - fResource = new Resource(gpu, info.fImage, info.fAlloc, info.fImageTiling); - } - } + GrVkImage(const GrVkGpu* gpu, + const GrVkImageInfo& info, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, + GrBackendObjectOwnership ownership, + bool forSecondaryCB = false); + virtual ~GrVkImage(); VkImage image() const { @@ -82,18 +73,31 @@ public: } bool isBorrowed() const { return fIsBorrowed; } - sk_sp<GrVkImageLayout> grVkImageLayout() const { return fLayout; } + sk_sp<GrBackendSurfaceMutableStateImpl> getMutableState() const { return fMutableState; } - VkImageLayout currentLayout() const { - return fLayout->getImageLayout(); - } + VkImageLayout currentLayout() const { return fMutableState->getImageLayout(); } + + void setImageLayoutAndQueueIndex(const GrVkGpu* gpu, + VkImageLayout newLayout, + VkAccessFlags dstAccessMask, + VkPipelineStageFlags dstStageMask, + bool byRegion, + uint32_t newQueueFamilyIndex); void setImageLayout(const GrVkGpu* gpu, VkImageLayout newLayout, VkAccessFlags dstAccessMask, VkPipelineStageFlags dstStageMask, - bool byRegion, - bool releaseFamilyQueue = false); + bool byRegion) { + this->setImageLayoutAndQueueIndex(gpu, newLayout, dstAccessMask, dstStageMask, byRegion, + VK_QUEUE_FAMILY_IGNORED); + } + + uint32_t currentQueueFamilyIndex() const { return fMutableState->getQueueFamilyIndex(); } + + void setQueueFamilyIndex(uint32_t queueFamilyIndex) { + fMutableState->setQueueFamilyIndex(queueFamilyIndex); + } // Returns the image to its original queue family and changes the layout to present if the queue // family is not external or foreign. @@ -109,7 +113,7 @@ public: // Should only be called when we have a real fResource object, i.e. never when being used as // a RT in an external secondary command buffer. SkASSERT(fResource); - fLayout->setImageLayout(newLayout); + fMutableState->setImageLayout(newLayout); } struct ImageDesc { @@ -156,13 +160,13 @@ public: #endif protected: - void releaseImage(GrVkGpu* gpu); + void releaseImage(); bool hasResource() const { return fResource; } - GrVkImageInfo fInfo; - uint32_t fInitialQueueFamily; - sk_sp<GrVkImageLayout> fLayout; - bool fIsBorrowed; + GrVkImageInfo fInfo; + uint32_t fInitialQueueFamily; + sk_sp<GrBackendSurfaceMutableStateImpl> fMutableState; + bool fIsBorrowed; private: class Resource : public GrTextureResource { diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkMemory.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkMemory.cpp index ff07d3ba0a2..08cee6e3462 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkMemory.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkMemory.cpp @@ -31,6 +31,16 @@ static BufferUsage get_buffer_usage(GrVkBuffer::Type type, bool dynamic) { SK_ABORT("Invalid GrVkBuffer::Type"); } +static bool check_result(GrVkGpu* gpu, VkResult result) { + if (result != VK_SUCCESS) { + if (result == VK_ERROR_DEVICE_LOST) { + gpu->setDeviceLost(); + } + return false; + } + return true; +} + bool GrVkMemory::AllocAndBindBufferMemory(GrVkGpu* gpu, VkBuffer buffer, GrVkBuffer::Type type, @@ -57,7 +67,8 @@ bool GrVkMemory::AllocAndBindBufferMemory(GrVkGpu* gpu, propFlags = AllocationPropertyFlags::kNone; } - if (!allocator->allocateMemoryForBuffer(buffer, usage, propFlags, &memory)) { + VkResult result = allocator->allocateBufferMemory(buffer, usage, propFlags, &memory); + if (!check_result(gpu, result)) { return false; } allocator->getAllocInfo(memory, alloc); @@ -76,12 +87,9 @@ bool GrVkMemory::AllocAndBindBufferMemory(GrVkGpu* gpu, void GrVkMemory::FreeBufferMemory(const GrVkGpu* gpu, GrVkBuffer::Type type, const GrVkAlloc& alloc) { - if (alloc.fBackendMemory) { - GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); - allocator->freeMemory(alloc.fBackendMemory); - } else { - GR_VK_CALL(gpu->vkInterface(), FreeMemory(gpu->device(), alloc.fMemory, nullptr)); - } + SkASSERT(alloc.fBackendMemory); + GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); + allocator->freeMemory(alloc.fBackendMemory); } const VkDeviceSize kMaxSmallImageSize = 256 * 1024; @@ -109,9 +117,11 @@ bool GrVkMemory::AllocAndBindImageMemory(GrVkGpu* gpu, propFlags |= AllocationPropertyFlags::kProtected; } - if (!allocator->allocateMemoryForImage(image, propFlags, &memory)) { + VkResult result = allocator->allocateImageMemory(image, propFlags, &memory); + if (!check_result(gpu, result)) { return false; } + allocator->getAllocInfo(memory, alloc); // Bind buffer @@ -128,38 +138,27 @@ bool GrVkMemory::AllocAndBindImageMemory(GrVkGpu* gpu, void GrVkMemory::FreeImageMemory(const GrVkGpu* gpu, bool linearTiling, const GrVkAlloc& alloc) { - if (alloc.fBackendMemory) { - GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); - allocator->freeMemory(alloc.fBackendMemory); - } else { - GR_VK_CALL(gpu->vkInterface(), FreeMemory(gpu->device(), alloc.fMemory, nullptr)); - } + SkASSERT(alloc.fBackendMemory); + GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); + allocator->freeMemory(alloc.fBackendMemory); } void* GrVkMemory::MapAlloc(GrVkGpu* gpu, const GrVkAlloc& alloc) { SkASSERT(GrVkAlloc::kMappable_Flag & alloc.fFlags); - if (alloc.fBackendMemory) { - GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); - return allocator->mapMemory(alloc.fBackendMemory); - } - + SkASSERT(alloc.fBackendMemory); + GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); void* mapPtr; - VkResult err; - GR_VK_CALL_RESULT(gpu, err, MapMemory(gpu->device(), alloc.fMemory, alloc.fOffset, alloc.fSize, - 0, &mapPtr)); - if (err) { - mapPtr = nullptr; + VkResult result = allocator->mapMemory(alloc.fBackendMemory, &mapPtr); + if (!check_result(gpu, result)) { + return nullptr; } return mapPtr; } void GrVkMemory::UnmapAlloc(const GrVkGpu* gpu, const GrVkAlloc& alloc) { - if (alloc.fBackendMemory) { - GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); - allocator->unmapMemory(alloc.fBackendMemory); - } else { - GR_VK_CALL(gpu->vkInterface(), UnmapMemory(gpu->device(), alloc.fMemory)); - } + SkASSERT(alloc.fBackendMemory); + GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); + allocator->unmapMemory(alloc.fBackendMemory); } void GrVkMemory::GetNonCoherentMappedMemoryRange(const GrVkAlloc& alloc, VkDeviceSize offset, @@ -185,41 +184,27 @@ void GrVkMemory::GetNonCoherentMappedMemoryRange(const GrVkAlloc& alloc, VkDevic range->size = size; } -void GrVkMemory::FlushMappedAlloc(const GrVkGpu* gpu, const GrVkAlloc& alloc, VkDeviceSize offset, +void GrVkMemory::FlushMappedAlloc(GrVkGpu* gpu, const GrVkAlloc& alloc, VkDeviceSize offset, VkDeviceSize size) { if (alloc.fFlags & GrVkAlloc::kNoncoherent_Flag) { SkASSERT(offset == 0); SkASSERT(size <= alloc.fSize); - if (alloc.fBackendMemory) { - GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); - allocator->flushMappedMemory(alloc.fBackendMemory, offset, size); - } else { - VkDeviceSize alignment = gpu->physicalDeviceProperties().limits.nonCoherentAtomSize; - VkMappedMemoryRange mappedMemoryRange; - GrVkMemory::GetNonCoherentMappedMemoryRange(alloc, offset, size, alignment, - &mappedMemoryRange); - GR_VK_CALL(gpu->vkInterface(), FlushMappedMemoryRanges(gpu->device(), 1, - &mappedMemoryRange)); - } + SkASSERT(alloc.fBackendMemory); + GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); + VkResult result = allocator->flushMemory(alloc.fBackendMemory, offset, size); + check_result(gpu, result); } } -void GrVkMemory::InvalidateMappedAlloc(const GrVkGpu* gpu, const GrVkAlloc& alloc, +void GrVkMemory::InvalidateMappedAlloc(GrVkGpu* gpu, const GrVkAlloc& alloc, VkDeviceSize offset, VkDeviceSize size) { if (alloc.fFlags & GrVkAlloc::kNoncoherent_Flag) { SkASSERT(offset == 0); SkASSERT(size <= alloc.fSize); - if (alloc.fBackendMemory) { - GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); - allocator->invalidateMappedMemory(alloc.fBackendMemory, offset, size); - } else { - VkDeviceSize alignment = gpu->physicalDeviceProperties().limits.nonCoherentAtomSize; - VkMappedMemoryRange mappedMemoryRange; - GrVkMemory::GetNonCoherentMappedMemoryRange(alloc, offset, size, alignment, - &mappedMemoryRange); - GR_VK_CALL(gpu->vkInterface(), InvalidateMappedMemoryRanges(gpu->device(), 1, - &mappedMemoryRange)); - } + SkASSERT(alloc.fBackendMemory); + GrVkMemoryAllocator* allocator = gpu->memoryAllocator(); + VkResult result = allocator->invalidateMemory(alloc.fBackendMemory, offset, size); + check_result(gpu, result); } } diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkMemory.h b/chromium/third_party/skia/src/gpu/vk/GrVkMemory.h index db2c0e66062..2cb91fd7b2b 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkMemory.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkMemory.h @@ -42,9 +42,9 @@ namespace GrVkMemory { // For the Flush and Invalidate calls, the offset should be relative to the GrVkAlloc. Thus this // will often be 0. The client does not need to make sure the offset and size are aligned to the // nonCoherentAtomSize, the internal calls will handle that. - void FlushMappedAlloc(const GrVkGpu* gpu, const GrVkAlloc& alloc, VkDeviceSize offset, + void FlushMappedAlloc(GrVkGpu* gpu, const GrVkAlloc& alloc, VkDeviceSize offset, VkDeviceSize size); - void InvalidateMappedAlloc(const GrVkGpu* gpu, const GrVkAlloc& alloc, VkDeviceSize offset, + void InvalidateMappedAlloc(GrVkGpu* gpu, const GrVkAlloc& alloc, VkDeviceSize offset, VkDeviceSize size); // Helper for aligning and setting VkMappedMemoryRange for flushing/invalidating noncoherent diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkOpsRenderPass.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkOpsRenderPass.cpp index 3327cf8c8ed..00f54b9008d 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkOpsRenderPass.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkOpsRenderPass.cpp @@ -11,7 +11,6 @@ #include "include/core/SkRect.h" #include "include/gpu/GrBackendDrawableInfo.h" #include "src/gpu/GrContextPriv.h" -#include "src/gpu/GrFixedClip.h" #include "src/gpu/GrOpFlushState.h" #include "src/gpu/GrPipeline.h" #include "src/gpu/GrRenderTargetPriv.h" @@ -61,7 +60,8 @@ GrVkOpsRenderPass::GrVkOpsRenderPass(GrVkGpu* gpu) : fGpu(gpu) {} bool GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, - const SkPMColor4f& clearColor) { + const SkPMColor4f& clearColor, + bool withStencil) { VkAttachmentLoadOp loadOp; VkAttachmentStoreOp storeOp; @@ -87,8 +87,11 @@ bool GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, false); // If we are using a stencil attachment we also need to update its layout - if (GrStencilAttachment* stencil = fRenderTarget->renderTargetPriv().getStencilAttachment()) { - GrVkStencilAttachment* vkStencil = (GrVkStencilAttachment*)stencil; + if (withStencil) { + GrVkStencilAttachment* vkStencil = + (GrVkStencilAttachment*) fRenderTarget->renderTargetPriv().getStencilAttachment(); + SkASSERT(vkStencil); + // We need the write and read access bits since we may load and store the stencil. // The initial load happens in the VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT so we // wait there. @@ -101,7 +104,7 @@ bool GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, } const GrVkResourceProvider::CompatibleRPHandle& rpHandle = - vkRT->compatibleRenderPassHandle(); + vkRT->compatibleRenderPassHandle(withStencil); if (rpHandle.isValid()) { fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(rpHandle, vkColorOps, @@ -109,7 +112,9 @@ bool GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, } else { fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(vkRT, vkColorOps, - vkStencilOps); + vkStencilOps, + nullptr, + withStencil); } if (!fCurrentRenderPass) { return false; @@ -128,7 +133,8 @@ bool GrVkOpsRenderPass::init(const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, fCurrentRenderPass = nullptr; return false; } - fCurrentSecondaryCommandBuffer->begin(fGpu, vkRT->getFramebuffer(), fCurrentRenderPass); + fCurrentSecondaryCommandBuffer->begin(fGpu, vkRT->getFramebuffer(withStencil), + fCurrentRenderPass); } if (!fGpu->beginRenderPass(fCurrentRenderPass, &vkClearColor, vkRT, fOrigin, fBounds, @@ -168,6 +174,9 @@ GrVkCommandBuffer* GrVkOpsRenderPass::currentCommandBuffer() { if (fCurrentSecondaryCommandBuffer) { return fCurrentSecondaryCommandBuffer.get(); } + // We checked this when we setup the GrVkOpsRenderPass and it should not have changed while we + // are still using this object. + SkASSERT(fGpu->currentCommandBuffer()); return fGpu->currentCommandBuffer(); } @@ -196,7 +205,8 @@ void GrVkOpsRenderPass::submit() { fGpu->endRenderPass(fRenderTarget, fOrigin, fBounds); } -bool GrVkOpsRenderPass::set(GrRenderTarget* rt, GrSurfaceOrigin origin, const SkIRect& bounds, +bool GrVkOpsRenderPass::set(GrRenderTarget* rt, GrStencilAttachment* stencil, + GrSurfaceOrigin origin, const SkIRect& bounds, const GrOpsRenderPass::LoadAndStoreInfo& colorInfo, const GrOpsRenderPass::StencilLoadAndStoreInfo& stencilInfo, const SkTArray<GrSurfaceProxy*, true>& sampledProxies) { @@ -207,6 +217,13 @@ bool GrVkOpsRenderPass::set(GrRenderTarget* rt, GrSurfaceOrigin origin, const Sk fIsActive = true; #endif + // We check to make sure the GrVkGpu has a valid current command buffer instead of each time we + // access it. If the command buffer is valid here should be valid throughout the use of the + // render pass since nothing should trigger a submit while this render pass is active. + if (!fGpu->currentCommandBuffer()) { + return false; + } + this->INHERITED::set(rt, origin); for (int i = 0; i < sampledProxies.count(); ++i) { @@ -227,7 +244,7 @@ bool GrVkOpsRenderPass::set(GrRenderTarget* rt, GrSurfaceOrigin origin, const Sk return this->initWrapped(); } - return this->init(colorInfo, stencilInfo, colorInfo.fClearColor); + return this->init(colorInfo, stencilInfo, colorInfo.fClearColor, SkToBool(stencil)); } void GrVkOpsRenderPass::reset() { @@ -257,14 +274,12 @@ bool GrVkOpsRenderPass::wrapsSecondaryCommandBuffer() const { //////////////////////////////////////////////////////////////////////////////// -void GrVkOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, bool insideStencilMask) { +void GrVkOpsRenderPass::onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) { if (!fCurrentRenderPass) { SkASSERT(fGpu->isDeviceLost()); return; } - SkASSERT(!clip.hasWindowRectangles()); - GrStencilAttachment* sb = fRenderTarget->renderTargetPriv().getStencilAttachment(); // this should only be called internally when we know we have a // stencil buffer. @@ -285,14 +300,13 @@ void GrVkOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, bool insideS VkClearRect clearRect; // Flip rect if necessary SkIRect vkRect; - if (!clip.scissorEnabled()) { + if (!scissor.enabled()) { vkRect.setXYWH(0, 0, fRenderTarget->width(), fRenderTarget->height()); } else if (kBottomLeft_GrSurfaceOrigin != fOrigin) { - vkRect = clip.scissorRect(); + vkRect = scissor.rect(); } else { - const SkIRect& scissor = clip.scissorRect(); - vkRect.setLTRB(scissor.fLeft, fRenderTarget->height() - scissor.fBottom, - scissor.fRight, fRenderTarget->height() - scissor.fTop); + vkRect.setLTRB(scissor.rect().fLeft, fRenderTarget->height() - scissor.rect().fBottom, + scissor.rect().fRight, fRenderTarget->height() - scissor.rect().fTop); } clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop }; @@ -313,15 +327,12 @@ void GrVkOpsRenderPass::onClearStencilClip(const GrFixedClip& clip, bool insideS fCurrentCBIsEmpty = false; } -void GrVkOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& color) { +void GrVkOpsRenderPass::onClear(const GrScissorState& scissor, const SkPMColor4f& color) { if (!fCurrentRenderPass) { SkASSERT(fGpu->isDeviceLost()); return; } - // parent class should never let us get here with no RT - SkASSERT(!clip.hasWindowRectangles()); - VkClearColorValue vkColor = {{color.fR, color.fG, color.fB, color.fA}}; // If we end up in a situation where we are calling clear without a scissior then in general it @@ -330,20 +341,19 @@ void GrVkOpsRenderPass::onClear(const GrFixedClip& clip, const SkPMColor4f& colo // load op (e.g. if we needed to execute a wait op). Thus we also have the empty check here. // TODO: Make the waitOp a RenderTask instead so we can clear out the GrOpsTask for a clear. We // can then reenable this assert assuming we can't get messed up by a waitOp. - //SkASSERT(!fCurrentCBIsEmpty || clip.scissorEnabled()); + //SkASSERT(!fCurrentCBIsEmpty || scissor); // We always do a sub rect clear with clearAttachments since we are inside a render pass VkClearRect clearRect; // Flip rect if necessary SkIRect vkRect; - if (!clip.scissorEnabled()) { + if (!scissor.enabled()) { vkRect.setXYWH(0, 0, fRenderTarget->width(), fRenderTarget->height()); } else if (kBottomLeft_GrSurfaceOrigin != fOrigin) { - vkRect = clip.scissorRect(); + vkRect = scissor.rect(); } else { - const SkIRect& scissor = clip.scissorRect(); - vkRect.setLTRB(scissor.fLeft, fRenderTarget->height() - scissor.fBottom, - scissor.fRight, fRenderTarget->height() - scissor.fTop); + vkRect.setLTRB(scissor.rect().fLeft, fRenderTarget->height() - scissor.rect().fBottom, + scissor.rect().fRight, fRenderTarget->height() - scissor.rect().fTop); } clearRect.rect.offset = { vkRect.fLeft, vkRect.fTop }; clearRect.rect.extent = { (uint32_t)vkRect.width(), (uint32_t)vkRect.height() }; @@ -374,8 +384,10 @@ void GrVkOpsRenderPass::addAdditionalRenderPass(bool mustUseSecondaryCommandBuff GrVkRenderPass::LoadStoreOps vkStencilOps(VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE); + bool withStencil = fCurrentRenderPass->hasStencilAttachment(); + const GrVkResourceProvider::CompatibleRPHandle& rpHandle = - vkRT->compatibleRenderPassHandle(); + vkRT->compatibleRenderPassHandle(withStencil); SkASSERT(fCurrentRenderPass); fCurrentRenderPass->unref(); if (rpHandle.isValid()) { @@ -385,7 +397,9 @@ void GrVkOpsRenderPass::addAdditionalRenderPass(bool mustUseSecondaryCommandBuff } else { fCurrentRenderPass = fGpu->resourceProvider().findRenderPass(vkRT, vkColorOps, - vkStencilOps); + vkStencilOps, + nullptr, + withStencil); } if (!fCurrentRenderPass) { return; @@ -402,7 +416,8 @@ void GrVkOpsRenderPass::addAdditionalRenderPass(bool mustUseSecondaryCommandBuff fCurrentRenderPass = nullptr; return; } - fCurrentSecondaryCommandBuffer->begin(fGpu, vkRT->getFramebuffer(), fCurrentRenderPass); + fCurrentSecondaryCommandBuffer->begin(fGpu, vkRT->getFramebuffer(withStencil), + fCurrentRenderPass); } // We use the same fBounds as the whole GrVkOpsRenderPass since we have no way of tracking the @@ -669,4 +684,3 @@ void GrVkOpsRenderPass::onExecuteDrawable(std::unique_ptr<SkDrawable::GpuDrawHan drawable->draw(info); fGpu->addDrawable(std::move(drawable)); } - diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkOpsRenderPass.h b/chromium/third_party/skia/src/gpu/vk/GrVkOpsRenderPass.h index 195bb922c02..ef666ec334b 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkOpsRenderPass.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkOpsRenderPass.h @@ -32,7 +32,8 @@ public: void onExecuteDrawable(std::unique_ptr<SkDrawable::GpuDrawHandler>) override; - bool set(GrRenderTarget*, GrSurfaceOrigin, const SkIRect& bounds, + bool set(GrRenderTarget*, GrStencilAttachment*, + GrSurfaceOrigin, const SkIRect& bounds, const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&, const SkTArray<GrSurfaceProxy*, true>& sampledProxies); @@ -47,7 +48,8 @@ public: private: bool init(const GrOpsRenderPass::LoadAndStoreInfo&, const GrOpsRenderPass::StencilLoadAndStoreInfo&, - const SkPMColor4f& clearColor); + const SkPMColor4f& clearColor, + bool withStencil); // Called instead of init when we are drawing to a render target that already wraps a secondary // command buffer. @@ -82,9 +84,9 @@ private: void onDrawIndexedIndirect(const GrBuffer* drawIndirectBuffer, size_t offset, int drawCount) override; - void onClear(const GrFixedClip&, const SkPMColor4f& color) override; + void onClear(const GrScissorState& scissor, const SkPMColor4f& color) override; - void onClearStencilClip(const GrFixedClip&, bool insideStencilMask) override; + void onClearStencilClip(const GrScissorState& scissor, bool insideStencilMask) override; void addAdditionalRenderPass(bool mustUseSecondaryCommandBuffer); diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateBuilder.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateBuilder.cpp index 4347cf4034a..1e04c61a5b6 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateBuilder.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateBuilder.cpp @@ -19,8 +19,6 @@ #include "src/gpu/vk/GrVkRenderPass.h" #include "src/gpu/vk/GrVkRenderTarget.h" -typedef size_t shader_size; - GrVkPipelineState* GrVkPipelineStateBuilder::CreatePipelineState( GrVkGpu* gpu, GrRenderTarget* renderTarget, @@ -100,39 +98,49 @@ bool GrVkPipelineStateBuilder::installVkShaderModule(VkShaderStageFlagBits stage static constexpr SkFourByteTag kSPIRV_Tag = SkSetFourByteTag('S', 'P', 'R', 'V'); static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L'); -int GrVkPipelineStateBuilder::loadShadersFromCache(SkReader32* cached, +int GrVkPipelineStateBuilder::loadShadersFromCache(SkReadBuffer* cached, VkShaderModule outShaderModules[], VkPipelineShaderStageCreateInfo* outStageInfo) { SkSL::String shaders[kGrShaderTypeCount]; SkSL::Program::Inputs inputs[kGrShaderTypeCount]; - GrPersistentCacheUtils::UnpackCachedShaders(cached, shaders, inputs, kGrShaderTypeCount); + if (!GrPersistentCacheUtils::UnpackCachedShaders(cached, shaders, inputs, kGrShaderTypeCount)) { + return 0; + } - SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT, + bool success = this->installVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT, fVS, &outShaderModules[kVertex_GrShaderType], &outStageInfo[0], shaders[kVertex_GrShaderType], - inputs[kVertex_GrShaderType])); + inputs[kVertex_GrShaderType]); - SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT, - fFS, - &outShaderModules[kFragment_GrShaderType], - &outStageInfo[1], - shaders[kFragment_GrShaderType], - inputs[kFragment_GrShaderType])); + success = success && this->installVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT, + fFS, + &outShaderModules[kFragment_GrShaderType], + &outStageInfo[1], + shaders[kFragment_GrShaderType], + inputs[kFragment_GrShaderType]); if (!shaders[kGeometry_GrShaderType].empty()) { - SkAssertResult(this->installVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT, - fGS, - &outShaderModules[kGeometry_GrShaderType], - &outStageInfo[2], - shaders[kGeometry_GrShaderType], - inputs[kGeometry_GrShaderType])); - return 3; - } else { - return 2; + success = success && this->installVkShaderModule(VK_SHADER_STAGE_GEOMETRY_BIT, + fGS, + &outShaderModules[kGeometry_GrShaderType], + &outStageInfo[2], + shaders[kGeometry_GrShaderType], + inputs[kGeometry_GrShaderType]); + } + + if (!success) { + for (int i = 0; i < kGrShaderTypeCount; ++i) { + if (outShaderModules[i]) { + GR_VK_CALL(fGpu->vkInterface(), + DestroyShaderModule(fGpu->device(), outShaderModules[i], nullptr)); + } + } + return 0; } + return shaders[kGeometry_GrShaderType].empty() ? 2 : 3; } void GrVkPipelineStateBuilder::storeShadersInCache(const SkSL::String shaders[], @@ -211,7 +219,7 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrProgramDesc& desc, SkASSERT(!this->fragColorIsInOut()); sk_sp<SkData> cached; - SkReader32 reader; + SkReadBuffer reader; SkFourByteTag shaderType = 0; auto persistentCache = fGpu->getContext()->priv().getPersistentCache(); if (persistentCache) { @@ -231,7 +239,10 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrProgramDesc& desc, int numShaderStages = 0; if (kSPIRV_Tag == shaderType) { numShaderStages = this->loadShadersFromCache(&reader, shaderModules, shaderStageInfo); - } else { + } + + // Proceed from sources if we didn't get a SPIRV cache (or the cache was invalid) + if (!numShaderStages) { numShaderStages = 2; // We always have at least vertex and fragment stages. SkSL::String shaders[kGrShaderTypeCount]; SkSL::Program::Inputs inputs[kGrShaderTypeCount]; @@ -243,10 +254,11 @@ GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrProgramDesc& desc, }; SkSL::String cached_sksl[kGrShaderTypeCount]; if (kSKSL_Tag == shaderType) { - GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, inputs, - kGrShaderTypeCount); - for (int i = 0; i < kGrShaderTypeCount; ++i) { - sksl[i] = &cached_sksl[i]; + if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, inputs, + kGrShaderTypeCount)) { + for (int i = 0; i < kGrShaderTypeCount; ++i) { + sksl[i] = &cached_sksl[i]; + } } } diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateBuilder.h b/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateBuilder.h index 1eb5290f6a0..d13f47bee3e 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateBuilder.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateBuilder.h @@ -19,7 +19,7 @@ class GrProgramDesc; class GrVkGpu; class GrVkRenderPass; -class SkReader32; +class SkReadBuffer; class GrVkPipelineStateBuilder : public GrGLSLProgramBuilder { public: @@ -48,7 +48,7 @@ private: GrVkPipelineState* finalize(const GrProgramDesc&, VkRenderPass compatibleRenderPass); // returns number of shader stages - int loadShadersFromCache(SkReader32* cached, VkShaderModule outShaderModules[], + int loadShadersFromCache(SkReadBuffer* cached, VkShaderModule outShaderModules[], VkPipelineShaderStageCreateInfo* outStageInfo); void storeShadersInCache(const SkSL::String shaders[], const SkSL::Program::Inputs inputs[], diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateDataManager.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateDataManager.cpp index bd0c8d460f6..8377437afe7 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateDataManager.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateDataManager.cpp @@ -12,11 +12,8 @@ GrVkPipelineStateDataManager::GrVkPipelineStateDataManager(const UniformInfoArray& uniforms, uint32_t uniformSize) - : fUniformSize(uniformSize) - , fUniformsDirty(false) { - fUniformData.reset(uniformSize); - fUniforms.push_back_n(uniforms.count()); - // We must add uniforms in same order is the UniformInfoArray so that UniformHandles already + : INHERITED(uniforms.count(), uniformSize) { + // We must add uniforms in same order as the UniformInfoArray so that UniformHandles already // owned by other objects will still match up here. int i = 0; for (const auto& uniformInfo : uniforms.items()) { @@ -33,306 +30,6 @@ GrVkPipelineStateDataManager::GrVkPipelineStateDataManager(const UniformInfoArra } } -void* GrVkPipelineStateDataManager::getBufferPtrAndMarkDirty(const Uniform& uni) const { - fUniformsDirty = true; - return static_cast<char*>(fUniformData.get())+uni.fOffset; -} - -void GrVkPipelineStateDataManager::set1i(UniformHandle u, int32_t i) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType); - SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); - void* buffer = this->getBufferPtrAndMarkDirty(uni); - memcpy(buffer, &i, sizeof(int32_t)); -} - -void GrVkPipelineStateDataManager::set1iv(UniformHandle u, - int arrayCount, - const int32_t v[]) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kInt_GrSLType || uni.fType == kShort_GrSLType); - SkASSERT(arrayCount > 0); - SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); - - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(int32_t) == 4); - for (int i = 0; i < arrayCount; ++i) { - const int32_t* curVec = &v[i]; - memcpy(buffer, curVec, sizeof(int32_t)); - buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t); - } -} - -void GrVkPipelineStateDataManager::set1f(UniformHandle u, float v0) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType); - SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(float) == 4); - memcpy(buffer, &v0, sizeof(float)); -} - -void GrVkPipelineStateDataManager::set1fv(UniformHandle u, - int arrayCount, - const float v[]) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kFloat_GrSLType || uni.fType == kHalf_GrSLType); - SkASSERT(arrayCount > 0); - SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); - - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(float) == 4); - for (int i = 0; i < arrayCount; ++i) { - const float* curVec = &v[i]; - memcpy(buffer, curVec, sizeof(float)); - buffer = static_cast<char*>(buffer) + 4*sizeof(float); - } -} - -void GrVkPipelineStateDataManager::set2i(UniformHandle u, int32_t i0, int32_t i1) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType); - SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); - void* buffer = this->getBufferPtrAndMarkDirty(uni); - int32_t v[2] = { i0, i1 }; - memcpy(buffer, v, 2 * sizeof(int32_t)); -} - -void GrVkPipelineStateDataManager::set2iv(UniformHandle u, - int arrayCount, - const int32_t v[]) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kInt2_GrSLType || uni.fType == kShort2_GrSLType); - SkASSERT(arrayCount > 0); - SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); - - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(int32_t) == 4); - for (int i = 0; i < arrayCount; ++i) { - const int32_t* curVec = &v[2 * i]; - memcpy(buffer, curVec, 2 * sizeof(int32_t)); - buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t); - } -} - -void GrVkPipelineStateDataManager::set2f(UniformHandle u, float v0, float v1) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType); - SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(float) == 4); - float v[2] = { v0, v1 }; - memcpy(buffer, v, 2 * sizeof(float)); -} - -void GrVkPipelineStateDataManager::set2fv(UniformHandle u, - int arrayCount, - const float v[]) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kFloat2_GrSLType || uni.fType == kHalf2_GrSLType); - SkASSERT(arrayCount > 0); - SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); - - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(float) == 4); - for (int i = 0; i < arrayCount; ++i) { - const float* curVec = &v[2 * i]; - memcpy(buffer, curVec, 2 * sizeof(float)); - buffer = static_cast<char*>(buffer) + 4*sizeof(float); - } -} - -void GrVkPipelineStateDataManager::set3i(UniformHandle u, - int32_t i0, - int32_t i1, - int32_t i2) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType); - SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); - void* buffer = this->getBufferPtrAndMarkDirty(uni); - int32_t v[3] = { i0, i1, i2 }; - memcpy(buffer, v, 3 * sizeof(int32_t)); -} - -void GrVkPipelineStateDataManager::set3iv(UniformHandle u, - int arrayCount, - const int32_t v[]) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kInt3_GrSLType || uni.fType == kShort3_GrSLType); - SkASSERT(arrayCount > 0); - SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); - - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(int32_t) == 4); - for (int i = 0; i < arrayCount; ++i) { - const int32_t* curVec = &v[3 * i]; - memcpy(buffer, curVec, 3 * sizeof(int32_t)); - buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t); - } -} - -void GrVkPipelineStateDataManager::set3f(UniformHandle u, float v0, float v1, float v2) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType); - SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(float) == 4); - float v[3] = { v0, v1, v2 }; - memcpy(buffer, v, 3 * sizeof(float)); -} - -void GrVkPipelineStateDataManager::set3fv(UniformHandle u, - int arrayCount, - const float v[]) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kFloat3_GrSLType || uni.fType == kHalf3_GrSLType); - SkASSERT(arrayCount > 0); - SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); - - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(float) == 4); - for (int i = 0; i < arrayCount; ++i) { - const float* curVec = &v[3 * i]; - memcpy(buffer, curVec, 3 * sizeof(float)); - buffer = static_cast<char*>(buffer) + 4*sizeof(float); - } -} - -void GrVkPipelineStateDataManager::set4i(UniformHandle u, - int32_t i0, - int32_t i1, - int32_t i2, - int32_t i3) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType); - SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); - void* buffer = this->getBufferPtrAndMarkDirty(uni); - int32_t v[4] = { i0, i1, i2, i3 }; - memcpy(buffer, v, 4 * sizeof(int32_t)); -} - -void GrVkPipelineStateDataManager::set4iv(UniformHandle u, - int arrayCount, - const int32_t v[]) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kInt4_GrSLType || uni.fType == kShort4_GrSLType); - SkASSERT(arrayCount > 0); - SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); - - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(int32_t) == 4); - for (int i = 0; i < arrayCount; ++i) { - const int32_t* curVec = &v[4 * i]; - memcpy(buffer, curVec, 4 * sizeof(int32_t)); - buffer = static_cast<char*>(buffer) + 4*sizeof(int32_t); - } -} - -void GrVkPipelineStateDataManager::set4f(UniformHandle u, - float v0, - float v1, - float v2, - float v3) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType); - SkASSERT(GrShaderVar::kNonArray == uni.fArrayCount); - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(float) == 4); - float v[4] = { v0, v1, v2, v3 }; - memcpy(buffer, v, 4 * sizeof(float)); -} - -void GrVkPipelineStateDataManager::set4fv(UniformHandle u, - int arrayCount, - const float v[]) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kFloat4_GrSLType || uni.fType == kHalf4_GrSLType); - SkASSERT(arrayCount > 0); - SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); - - void* buffer = this->getBufferPtrAndMarkDirty(uni); - SkASSERT(sizeof(float) == 4); - memcpy(buffer, v, arrayCount * 4 * sizeof(float)); -} - -void GrVkPipelineStateDataManager::setMatrix2f(UniformHandle u, const float matrix[]) const { - this->setMatrices<2>(u, 1, matrix); -} - -void GrVkPipelineStateDataManager::setMatrix2fv(UniformHandle u, - int arrayCount, - const float m[]) const { - this->setMatrices<2>(u, arrayCount, m); -} - -void GrVkPipelineStateDataManager::setMatrix3f(UniformHandle u, const float matrix[]) const { - this->setMatrices<3>(u, 1, matrix); -} - -void GrVkPipelineStateDataManager::setMatrix3fv(UniformHandle u, - int arrayCount, - const float m[]) const { - this->setMatrices<3>(u, arrayCount, m); -} - -void GrVkPipelineStateDataManager::setMatrix4f(UniformHandle u, const float matrix[]) const { - this->setMatrices<4>(u, 1, matrix); -} - -void GrVkPipelineStateDataManager::setMatrix4fv(UniformHandle u, - int arrayCount, - const float m[]) const { - this->setMatrices<4>(u, arrayCount, m); -} - -template<int N> struct set_uniform_matrix; - -template<int N> inline void GrVkPipelineStateDataManager::setMatrices(UniformHandle u, - int arrayCount, - const float matrices[]) const { - const Uniform& uni = fUniforms[u.toIndex()]; - SkASSERT(uni.fType == kFloat2x2_GrSLType + (N - 2) || - uni.fType == kHalf2x2_GrSLType + (N - 2)); - SkASSERT(arrayCount > 0); - SkASSERT(arrayCount <= uni.fArrayCount || - (1 == arrayCount && GrShaderVar::kNonArray == uni.fArrayCount)); - - void* buffer = fUniformData.get(); - fUniformsDirty = true; - - set_uniform_matrix<N>::set(buffer, uni.fOffset, arrayCount, matrices); -} - -template<int N> struct set_uniform_matrix { - inline static void set(void* buffer, int uniformOffset, int count, const float matrices[]) { - static_assert(sizeof(float) == 4); - buffer = static_cast<char*>(buffer) + uniformOffset; - for (int i = 0; i < count; ++i) { - const float* matrix = &matrices[N * N * i]; - for (int j = 0; j < N; ++j) { - memcpy(buffer, &matrix[j * N], N * sizeof(float)); - buffer = static_cast<char*>(buffer) + 4 * sizeof(float); - } - } - } -}; - -template<> struct set_uniform_matrix<4> { - inline static void set(void* buffer, int uniformOffset, int count, const float matrices[]) { - static_assert(sizeof(float) == 4); - buffer = static_cast<char*>(buffer) + uniformOffset; - memcpy(buffer, matrices, count * 16 * sizeof(float)); - } -}; - bool GrVkPipelineStateDataManager::uploadUniformBuffers(GrVkGpu* gpu, GrVkUniformBuffer* buffer) const { bool updatedBuffer = false; diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateDataManager.h b/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateDataManager.h index 91d50924b68..b090dd6f56c 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateDataManager.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkPipelineStateDataManager.h @@ -8,78 +8,28 @@ #ifndef GrVkPipelineStateDataManager_DEFINED #define GrVkPipelineStateDataManager_DEFINED -#include "src/gpu/glsl/GrGLSLProgramDataManager.h" +#include "src/gpu/GrUniformDataManager.h" #include "include/gpu/vk/GrVkTypes.h" -#include "src/core/SkAutoMalloc.h" #include "src/gpu/vk/GrVkUniformHandler.h" class GrVkGpu; class GrVkUniformBuffer; -class GrVkPipelineStateDataManager : public GrGLSLProgramDataManager { +class GrVkPipelineStateDataManager : public GrUniformDataManager { public: typedef GrVkUniformHandler::UniformInfoArray UniformInfoArray; GrVkPipelineStateDataManager(const UniformInfoArray&, uint32_t uniformSize); - void set1i(UniformHandle, int32_t) const override; - void set1iv(UniformHandle, int arrayCount, const int32_t v[]) const override; - void set1f(UniformHandle, float v0) const override; - void set1fv(UniformHandle, int arrayCount, const float v[]) const override; - void set2i(UniformHandle, int32_t, int32_t) const override; - void set2iv(UniformHandle, int arrayCount, const int32_t v[]) const override; - void set2f(UniformHandle, float, float) const override; - void set2fv(UniformHandle, int arrayCount, const float v[]) const override; - void set3i(UniformHandle, int32_t, int32_t, int32_t) const override; - void set3iv(UniformHandle, int arrayCount, const int32_t v[]) const override; - void set3f(UniformHandle, float, float, float) const override; - void set3fv(UniformHandle, int arrayCount, const float v[]) const override; - void set4i(UniformHandle, int32_t, int32_t, int32_t, int32_t) const override; - void set4iv(UniformHandle, int arrayCount, const int32_t v[]) const override; - void set4f(UniformHandle, float, float, float, float) const override; - void set4fv(UniformHandle, int arrayCount, const float v[]) const override; - // matrices are column-major, the first two upload a single matrix, the latter two upload - // arrayCount matrices into a uniform array. - void setMatrix2f(UniformHandle, const float matrix[]) const override; - void setMatrix3f(UniformHandle, const float matrix[]) const override; - void setMatrix4f(UniformHandle, const float matrix[]) const override; - void setMatrix2fv(UniformHandle, int arrayCount, const float matrices[]) const override; - void setMatrix3fv(UniformHandle, int arrayCount, const float matrices[]) const override; - void setMatrix4fv(UniformHandle, int arrayCount, const float matrices[]) const override; - - // for nvpr only - void setPathFragmentInputTransform(VaryingHandle u, int components, - const SkMatrix& matrix) const override { - SK_ABORT("Only supported in NVPR, which is not in vulkan"); - } - // Returns true if either the geometry or fragment buffers needed to generate a new underlying // VkBuffer object in order upload data. If true is returned, this is a signal to the caller // that they will need to update the descriptor set that is using these buffers. bool uploadUniformBuffers(GrVkGpu* gpu, GrVkUniformBuffer* buffer) const; private: - struct Uniform { - uint32_t fOffset; - SkDEBUGCODE( - GrSLType fType; - int fArrayCount; - ); - }; - - template<int N> inline void setMatrices(UniformHandle, int arrayCount, - const float matrices[]) const; - - void* getBufferPtrAndMarkDirty(const Uniform& uni) const; - - uint32_t fUniformSize; - - SkTArray<Uniform, true> fUniforms; - - mutable SkAutoMalloc fUniformData; - mutable bool fUniformsDirty; + typedef GrUniformDataManager INHERITED; }; #endif diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkRenderPass.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkRenderPass.cpp index 627eb2253e2..281983f8451 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkRenderPass.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkRenderPass.cpp @@ -234,7 +234,7 @@ bool GrVkRenderPass::isCompatible(const GrVkRenderTarget& target) const { AttachmentsDescriptor desc; AttachmentFlags flags; - target.getAttachmentsDescriptor(&desc, &flags); + target.getAttachmentsDescriptor(&desc, &flags, this->hasStencilAttachment()); return this->isCompatible(desc, flags); } diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkRenderPass.h b/chromium/third_party/skia/src/gpu/vk/GrVkRenderPass.h index 8b8c641b18b..5009e1ec3bb 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkRenderPass.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkRenderPass.h @@ -94,6 +94,7 @@ public: // index value. bool colorAttachmentIndex(uint32_t* index) const; bool stencilAttachmentIndex(uint32_t* index) const; + bool hasStencilAttachment() const { return fAttachmentFlags & kStencil_AttachmentFlag; } // Returns whether or not the structure of a RenderTarget matches that of the VkRenderPass in // this object. Specifically this compares that the number of attachments, format of diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkRenderTarget.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkRenderTarget.cpp index 3021298c700..c2afefc6a17 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkRenderTarget.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkRenderTarget.cpp @@ -26,21 +26,23 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, SkISize dimensions, int sampleCnt, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageInfo& msaaInfo, - sk_sp<GrVkImageLayout> msaaLayout, + sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState, const GrVkImageView* colorAttachmentView, const GrVkImageView* resolveAttachmentView) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, std::move(layout), GrBackendObjectOwnership::kBorrowed) + , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kBorrowed) // for the moment we only support 1:1 color to stencil , GrRenderTarget(gpu, dimensions, sampleCnt, info.fProtected) , fColorAttachmentView(colorAttachmentView) - , fMSAAImage(new GrVkImage(gpu, msaaInfo, std::move(msaaLayout), + , fMSAAImage(new GrVkImage(gpu, msaaInfo, std::move(msaaMutableState), GrBackendObjectOwnership::kOwned)) , fResolveAttachmentView(resolveAttachmentView) , fCachedFramebuffer(nullptr) - , fCachedSimpleRenderPass(nullptr) { + , fCachedStencilFramebuffer(nullptr) + , fCachedSimpleRenderPass(nullptr) + , fCachedStencilRenderPass(nullptr) { SkASSERT(info.fProtected == msaaInfo.fProtected); SkASSERT(sampleCnt > 1); this->registerWithCacheWrapped(GrWrapCacheable::kNo); @@ -52,22 +54,24 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, SkISize dimensions, int sampleCnt, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageInfo& msaaInfo, - sk_sp<GrVkImageLayout> msaaLayout, + sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState, const GrVkImageView* colorAttachmentView, const GrVkImageView* resolveAttachmentView, GrBackendObjectOwnership ownership) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, std::move(layout), ownership) + , GrVkImage(gpu, info, std::move(mutableState), ownership) // for the moment we only support 1:1 color to stencil , GrRenderTarget(gpu, dimensions, sampleCnt, info.fProtected) , fColorAttachmentView(colorAttachmentView) - , fMSAAImage(new GrVkImage(gpu, msaaInfo, std::move(msaaLayout), + , fMSAAImage(new GrVkImage(gpu, msaaInfo, std::move(msaaMutableState), GrBackendObjectOwnership::kOwned)) , fResolveAttachmentView(resolveAttachmentView) , fCachedFramebuffer(nullptr) - , fCachedSimpleRenderPass(nullptr) { + , fCachedStencilFramebuffer(nullptr) + , fCachedSimpleRenderPass(nullptr) + , fCachedStencilRenderPass(nullptr) { SkASSERT(info.fProtected == msaaInfo.fProtected); SkASSERT(sampleCnt > 1); } @@ -77,16 +81,18 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* colorAttachmentView) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, std::move(layout), GrBackendObjectOwnership::kBorrowed) + , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kBorrowed) , GrRenderTarget(gpu, dimensions, 1, info.fProtected) , fColorAttachmentView(colorAttachmentView) , fMSAAImage(nullptr) , fResolveAttachmentView(nullptr) , fCachedFramebuffer(nullptr) - , fCachedSimpleRenderPass(nullptr) { + , fCachedStencilFramebuffer(nullptr) + , fCachedSimpleRenderPass(nullptr) + , fCachedStencilRenderPass(nullptr) { this->registerWithCacheWrapped(GrWrapCacheable::kNo); } @@ -95,42 +101,44 @@ GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* colorAttachmentView, GrBackendObjectOwnership ownership) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, std::move(layout), ownership) + , GrVkImage(gpu, info, std::move(mutableState), ownership) , GrRenderTarget(gpu, dimensions, 1, info.fProtected) , fColorAttachmentView(colorAttachmentView) , fMSAAImage(nullptr) , fResolveAttachmentView(nullptr) , fCachedFramebuffer(nullptr) - , fCachedSimpleRenderPass(nullptr) {} + , fCachedStencilFramebuffer(nullptr) + , fCachedSimpleRenderPass(nullptr) + , fCachedStencilRenderPass(nullptr) {} GrVkRenderTarget::GrVkRenderTarget(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkRenderPass* renderPass, VkCommandBuffer secondaryCommandBuffer) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, std::move(layout), GrBackendObjectOwnership::kBorrowed, true) + , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kBorrowed, true) , GrRenderTarget(gpu, dimensions, 1, info.fProtected) , fColorAttachmentView(nullptr) , fMSAAImage(nullptr) , fResolveAttachmentView(nullptr) , fCachedFramebuffer(nullptr) + , fCachedStencilFramebuffer(nullptr) , fCachedSimpleRenderPass(renderPass) + , fCachedStencilRenderPass(nullptr) , fSecondaryCommandBuffer(secondaryCommandBuffer) { SkASSERT(fSecondaryCommandBuffer != VK_NULL_HANDLE); this->registerWithCacheWrapped(GrWrapCacheable::kNo); } -sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu, - SkISize dimensions, - int sampleCnt, - const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout) { +sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget( + GrVkGpu* gpu, SkISize dimensions, int sampleCnt, const GrVkImageInfo& info, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) { SkASSERT(VK_NULL_HANDLE != info.fImage); SkASSERT(1 == info.fLevelCount); @@ -140,7 +148,7 @@ sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu, // create msaa surface if necessary GrVkImageInfo msInfo; - sk_sp<GrVkImageLayout> msLayout; + sk_sp<GrBackendSurfaceMutableStateImpl> msMutableState; const GrVkImageView* resolveAttachmentView = nullptr; if (sampleCnt > 1) { GrVkImage::ImageDesc msImageDesc; @@ -172,7 +180,8 @@ sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu, GrVkImage::DestroyImageInfo(gpu, &msInfo); return nullptr; } - msLayout.reset(new GrVkImageLayout(msInfo.fImageLayout)); + msMutableState.reset(new GrBackendSurfaceMutableStateImpl(msInfo.fImageLayout, + msInfo.fCurrentQueueFamily)); } else { // Set color attachment image colorImage = info.fImage; @@ -192,11 +201,12 @@ sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu, GrVkRenderTarget* vkRT; if (sampleCnt > 1) { - vkRT = new GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(layout), msInfo, - std::move(msLayout), colorAttachmentView, + vkRT = new GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState), + msInfo, std::move(msMutableState), colorAttachmentView, resolveAttachmentView); } else { - vkRT = new GrVkRenderTarget(gpu, dimensions, info, std::move(layout), colorAttachmentView); + vkRT = new GrVkRenderTarget(gpu, dimensions, info, std::move(mutableState), + colorAttachmentView); } return sk_sp<GrVkRenderTarget>(vkRT); @@ -204,14 +214,6 @@ sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeWrappedRenderTarget(GrVkGpu* gpu, sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeSecondaryCBRenderTarget( GrVkGpu* gpu, SkISize dimensions, const GrVkDrawableInfo& vkInfo) { - // We only set the few properties of the GrVkImageInfo that we know like layout and format. The - // others we keep at the default "null" values. - GrVkImageInfo info; - info.fImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - info.fFormat = vkInfo.fFormat; - - sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); - const GrVkRenderPass* rp = gpu->resourceProvider().findCompatibleExternalRenderPass(vkInfo.fCompatibleRenderPass, vkInfo.fColorAttachmentIndex); @@ -223,78 +225,108 @@ sk_sp<GrVkRenderTarget> GrVkRenderTarget::MakeSecondaryCBRenderTarget( return nullptr; } - GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu, dimensions, info, std::move(layout), rp, - vkInfo.fSecondaryCommandBuffer); + // We only set the few properties of the GrVkImageInfo that we know like layout and format. The + // others we keep at the default "null" values. + GrVkImageInfo info; + info.fImageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + info.fFormat = vkInfo.fFormat; + + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState(new GrBackendSurfaceMutableStateImpl( + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_QUEUE_FAMILY_IGNORED)); + + GrVkRenderTarget* vkRT = new GrVkRenderTarget(gpu, dimensions, info, std::move(mutableState), + rp, vkInfo.fSecondaryCommandBuffer); return sk_sp<GrVkRenderTarget>(vkRT); } bool GrVkRenderTarget::completeStencilAttachment() { SkASSERT(!this->wrapsSecondaryCommandBuffer()); - // If we have a previous renderpass or framebuffer it will have been made without stencil, so - // we set it to null to trigger creating a new one the next time we need it. - if (fCachedSimpleRenderPass) { - fCachedSimpleRenderPass->unref(); - fCachedSimpleRenderPass = nullptr; - } - if (fCachedFramebuffer) { - fCachedFramebuffer->unref(); - fCachedFramebuffer = nullptr; - } - fCompatibleRPHandle = GrVkResourceProvider::CompatibleRPHandle(); return true; } -const GrVkRenderPass* GrVkRenderTarget::getSimpleRenderPass() { - if (fCachedSimpleRenderPass) { - return fCachedSimpleRenderPass; +const GrVkRenderPass* GrVkRenderTarget::getSimpleRenderPass(bool withStencil) { + if (withStencil) { + if (fCachedStencilRenderPass) { + return fCachedStencilRenderPass; + } + } else { + if (fCachedSimpleRenderPass) { + return fCachedSimpleRenderPass; + } } - return this->createSimpleRenderPass(); + + return this->createSimpleRenderPass(withStencil); } -const GrVkRenderPass* GrVkRenderTarget::createSimpleRenderPass() { +const GrVkRenderPass* GrVkRenderTarget::createSimpleRenderPass(bool withStencil) { SkASSERT(!this->wrapsSecondaryCommandBuffer()); - SkASSERT(!fCachedSimpleRenderPass); - fCachedSimpleRenderPass = - this->getVkGpu()->resourceProvider().findCompatibleRenderPass(*this, &fCompatibleRPHandle); - return fCachedSimpleRenderPass; + GrVkResourceProvider& rp = this->getVkGpu()->resourceProvider(); + if (withStencil) { + SkASSERT(!fCachedStencilRenderPass); + fCachedStencilRenderPass = rp.findCompatibleRenderPass(*this, &fCompatibleStencilRPHandle, + withStencil); + return fCachedStencilRenderPass; + } else { + SkASSERT(!fCachedSimpleRenderPass); + fCachedSimpleRenderPass = rp.findCompatibleRenderPass(*this, &fCompatibleRPHandle, + withStencil); + return fCachedSimpleRenderPass; + } } -const GrVkFramebuffer* GrVkRenderTarget::getFramebuffer() { - if (fCachedFramebuffer) { - return fCachedFramebuffer; +const GrVkFramebuffer* GrVkRenderTarget::getFramebuffer(bool withStencil) { + if (withStencil) { + if (fCachedStencilFramebuffer) { + return fCachedStencilFramebuffer; + } + } else { + if (fCachedFramebuffer) { + return fCachedFramebuffer; + } } - return this->createFramebuffer(); + return this->createFramebuffer(withStencil); } -const GrVkFramebuffer* GrVkRenderTarget::createFramebuffer() { +const GrVkFramebuffer* GrVkRenderTarget::createFramebuffer(bool withStencil) { SkASSERT(!this->wrapsSecondaryCommandBuffer()); - SkASSERT(!fCachedFramebuffer); - GrVkGpu* gpu = this->getVkGpu(); - // Stencil attachment view is stored in the base RT stencil attachment - const GrVkImageView* stencilView = this->stencilAttachmentView(); - const GrVkRenderPass* renderPass = this->getSimpleRenderPass(); + + const GrVkRenderPass* renderPass = this->getSimpleRenderPass(withStencil); if (!renderPass) { return nullptr; } - fCachedFramebuffer = GrVkFramebuffer::Create(gpu, this->width(), this->height(), renderPass, - fColorAttachmentView, stencilView); - return fCachedFramebuffer; + + // Stencil attachment view is stored in the base RT stencil attachment + const GrVkImageView* stencilView = withStencil ? this->stencilAttachmentView() : nullptr; + GrVkFramebuffer* frameBuffer = GrVkFramebuffer::Create(gpu, this->width(), this->height(), + renderPass, fColorAttachmentView, + stencilView); + + if (withStencil) { + SkASSERT(!fCachedStencilFramebuffer); + fCachedStencilFramebuffer = frameBuffer; + } else { + SkASSERT(!fCachedFramebuffer); + fCachedFramebuffer = frameBuffer; + } + + return frameBuffer; } -void GrVkRenderTarget::getAttachmentsDescriptor( - GrVkRenderPass::AttachmentsDescriptor* desc, - GrVkRenderPass::AttachmentFlags* attachmentFlags) const { +void GrVkRenderTarget::getAttachmentsDescriptor(GrVkRenderPass::AttachmentsDescriptor* desc, + GrVkRenderPass::AttachmentFlags* attachmentFlags, + bool withStencil) const { SkASSERT(!this->wrapsSecondaryCommandBuffer()); desc->fColor.fFormat = this->imageFormat(); desc->fColor.fSamples = this->numSamples(); *attachmentFlags = GrVkRenderPass::kColor_AttachmentFlag; uint32_t attachmentCount = 1; - const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment(); - if (stencil) { + if (withStencil) { + const GrStencilAttachment* stencil = this->renderTargetPriv().getStencilAttachment(); + SkASSERT(stencil); const GrVkStencilAttachment* vkStencil = static_cast<const GrVkStencilAttachment*>(stencil); desc->fStencil.fFormat = vkStencil->imageFormat(); desc->fStencil.fSamples = vkStencil->numSamples(); @@ -317,11 +349,13 @@ GrVkRenderTarget::~GrVkRenderTarget() { SkASSERT(!fResolveAttachmentView); SkASSERT(!fColorAttachmentView); SkASSERT(!fCachedFramebuffer); + SkASSERT(!fCachedStencilFramebuffer); SkASSERT(!fCachedSimpleRenderPass); + SkASSERT(!fCachedStencilRenderPass); } -void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer) { - commandBuffer.addResource(this->getFramebuffer()); +void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer, bool withStencil) { + commandBuffer.addResource(this->getFramebuffer(withStencil)); commandBuffer.addResource(this->colorAttachmentView()); commandBuffer.addResource(this->msaaImageResource() ? this->msaaImageResource() : this->resource()); @@ -332,10 +366,8 @@ void GrVkRenderTarget::addResources(GrVkCommandBuffer& commandBuffer) { } void GrVkRenderTarget::releaseInternalObjects() { - GrVkGpu* gpu = this->getVkGpu(); - if (fMSAAImage) { - fMSAAImage->releaseImage(gpu); + fMSAAImage->releaseImage(); fMSAAImage.reset(); } @@ -351,10 +383,18 @@ void GrVkRenderTarget::releaseInternalObjects() { fCachedFramebuffer->unref(); fCachedFramebuffer = nullptr; } + if (fCachedStencilFramebuffer) { + fCachedStencilFramebuffer->unref(); + fCachedStencilFramebuffer = nullptr; + } if (fCachedSimpleRenderPass) { fCachedSimpleRenderPass->unref(); fCachedSimpleRenderPass = nullptr; } + if (fCachedStencilRenderPass) { + fCachedStencilRenderPass->unref(); + fCachedStencilRenderPass = nullptr; + } for (int i = 0; i < fGrSecondaryCommandBuffers.count(); ++i) { SkASSERT(fGrSecondaryCommandBuffers[i]); fGrSecondaryCommandBuffers[i]->releaseResources(); @@ -364,20 +404,20 @@ void GrVkRenderTarget::releaseInternalObjects() { void GrVkRenderTarget::onRelease() { this->releaseInternalObjects(); - this->releaseImage(this->getVkGpu()); + this->releaseImage(); GrRenderTarget::onRelease(); } void GrVkRenderTarget::onAbandon() { this->releaseInternalObjects(); - this->releaseImage(this->getVkGpu()); + this->releaseImage(); GrRenderTarget::onAbandon(); } GrBackendRenderTarget GrVkRenderTarget::getBackendRenderTarget() const { SkASSERT(!this->wrapsSecondaryCommandBuffer()); return GrBackendRenderTarget(this->width(), this->height(), this->numSamples(), fInfo, - this->grVkImageLayout()); + this->getMutableState()); } const GrManagedResource* GrVkRenderTarget::stencilImageResource() const { diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkRenderTarget.h b/chromium/third_party/skia/src/gpu/vk/GrVkRenderTarget.h index daae1a04a7d..94ad40f353b 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkRenderTarget.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkRenderTarget.h @@ -34,7 +34,7 @@ class GrVkRenderTarget: public GrRenderTarget, public virtual GrVkImage { public: static sk_sp<GrVkRenderTarget> MakeWrappedRenderTarget(GrVkGpu*, SkISize, int sampleCnt, const GrVkImageInfo&, - sk_sp<GrVkImageLayout>); + sk_sp<GrBackendSurfaceMutableStateImpl>); static sk_sp<GrVkRenderTarget> MakeSecondaryCBRenderTarget(GrVkGpu*, SkISize, const GrVkDrawableInfo& vkInfo); @@ -43,7 +43,7 @@ public: GrBackendFormat backendFormat() const override { return this->getBackendFormat(); } - const GrVkFramebuffer* getFramebuffer(); + const GrVkFramebuffer* getFramebuffer(bool withStencil); const GrVkImageView* colorAttachmentView() const { return fColorAttachmentView; } const GrManagedResource* msaaImageResource() const { if (fMSAAImage) { @@ -56,15 +56,26 @@ public: const GrManagedResource* stencilImageResource() const; const GrVkImageView* stencilAttachmentView() const; - const GrVkRenderPass* getSimpleRenderPass(); - GrVkResourceProvider::CompatibleRPHandle compatibleRenderPassHandle() { + const GrVkRenderPass* getSimpleRenderPass(bool withStencil); + GrVkResourceProvider::CompatibleRPHandle compatibleRenderPassHandle(bool withStencil) { SkASSERT(!this->wrapsSecondaryCommandBuffer()); - if (!fCompatibleRPHandle.isValid()) { - SkASSERT(!fCachedSimpleRenderPass); - this->createSimpleRenderPass(); + + auto pRPHandle = withStencil ? &fCompatibleStencilRPHandle : &fCompatibleRPHandle; + if (!pRPHandle->isValid()) { + this->createSimpleRenderPass(withStencil); + } + +#ifdef SK_DEBUG + if (withStencil) { + SkASSERT(pRPHandle->isValid() == SkToBool(fCachedStencilRenderPass)); + SkASSERT(fCachedStencilRenderPass->hasStencilAttachment()); + } else { + SkASSERT(pRPHandle->isValid() == SkToBool(fCachedSimpleRenderPass)); + SkASSERT(!fCachedSimpleRenderPass->hasStencilAttachment()); } - SkASSERT(fCompatibleRPHandle.isValid() == SkToBool(fCachedSimpleRenderPass)); - return fCompatibleRPHandle; +#endif + + return *pRPHandle; } const GrVkRenderPass* externalRenderPass() const { SkASSERT(this->wrapsSecondaryCommandBuffer()); @@ -86,9 +97,10 @@ public: GrBackendRenderTarget getBackendRenderTarget() const override; void getAttachmentsDescriptor(GrVkRenderPass::AttachmentsDescriptor* desc, - GrVkRenderPass::AttachmentFlags* flags) const; + GrVkRenderPass::AttachmentFlags* flags, + bool withStencil) const; - void addResources(GrVkCommandBuffer& commandBuffer); + void addResources(GrVkCommandBuffer& commandBuffer, bool withStencil); void addWrappedGrSecondaryCommandBuffer(std::unique_ptr<GrVkSecondaryCommandBuffer> cmdBuffer) { fGrSecondaryCommandBuffers.push_back(std::move(cmdBuffer)); @@ -99,9 +111,9 @@ protected: SkISize dimensions, int sampleCnt, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageInfo& msaaInfo, - sk_sp<GrVkImageLayout> msaaLayout, + sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState, const GrVkImageView* colorAttachmentView, const GrVkImageView* resolveAttachmentView, GrBackendObjectOwnership); @@ -109,7 +121,7 @@ protected: GrVkRenderTarget(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* colorAttachmentView, GrBackendObjectOwnership); @@ -133,29 +145,29 @@ private: SkISize dimensions, int sampleCnt, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageInfo& msaaInfo, - sk_sp<GrVkImageLayout> msaaLayout, + sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState, const GrVkImageView* colorAttachmentView, const GrVkImageView* resolveAttachmentView); GrVkRenderTarget(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* colorAttachmentView); GrVkRenderTarget(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkRenderPass* renderPass, VkCommandBuffer secondaryCommandBuffer); GrVkGpu* getVkGpu() const; - const GrVkRenderPass* createSimpleRenderPass(); - const GrVkFramebuffer* createFramebuffer(); + const GrVkRenderPass* createSimpleRenderPass(bool withStencil); + const GrVkFramebuffer* createFramebuffer(bool withStencil); bool completeStencilAttachment() override; @@ -173,12 +185,18 @@ private: const GrVkImageView* fResolveAttachmentView; const GrVkFramebuffer* fCachedFramebuffer; + const GrVkFramebuffer* fCachedStencilFramebuffer; - // This is a cached pointer to a simple render pass. The render target should unref it - // once it is done with it. + // Cached pointers to a simple and stencil render passes. The render target should unref them + // once it is done with them. const GrVkRenderPass* fCachedSimpleRenderPass; - // This is a handle to be used to quickly get compatible GrVkRenderPasses for this render target + const GrVkRenderPass* fCachedStencilRenderPass; + + // This is a handle to be used to quickly get a GrVkRenderPass that is compatible with + // this render target if its stencil buffer is ignored. GrVkResourceProvider::CompatibleRPHandle fCompatibleRPHandle; + // Same as above but taking the render target's stencil buffer into account + GrVkResourceProvider::CompatibleRPHandle fCompatibleStencilRPHandle; // If this render target wraps an external VkCommandBuffer, then this handle will be that // VkCommandBuffer and not VK_NULL_HANDLE. In this case the render target will not be backed by diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkResourceProvider.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkResourceProvider.cpp index 017310a8419..e5c2785335b 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkResourceProvider.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkResourceProvider.cpp @@ -102,12 +102,13 @@ GrVkPipeline* GrVkResourceProvider::createPipeline(const GrProgramInfo& programI // RenderPasses as needed that are compatible with the framebuffer. const GrVkRenderPass* GrVkResourceProvider::findCompatibleRenderPass(const GrVkRenderTarget& target, - CompatibleRPHandle* compatibleHandle) { + CompatibleRPHandle* compatibleHandle, + bool withStencil) { // Get attachment information from render target. This includes which attachments the render // target has (color, stencil) and the attachments format and sample count. GrVkRenderPass::AttachmentFlags attachmentFlags; GrVkRenderPass::AttachmentsDescriptor attachmentsDesc; - target.getAttachmentsDescriptor(&attachmentsDesc, &attachmentFlags); + target.getAttachmentsDescriptor(&attachmentsDesc, &attachmentFlags, withStencil); return this->findCompatibleRenderPass(&attachmentsDesc, attachmentFlags, compatibleHandle); } @@ -164,11 +165,12 @@ const GrVkRenderPass* GrVkResourceProvider::findRenderPass( GrVkRenderTarget* target, const GrVkRenderPass::LoadStoreOps& colorOps, const GrVkRenderPass::LoadStoreOps& stencilOps, - CompatibleRPHandle* compatibleHandle) { + CompatibleRPHandle* compatibleHandle, + bool withStencil) { GrVkResourceProvider::CompatibleRPHandle tempRPHandle; GrVkResourceProvider::CompatibleRPHandle* pRPHandle = compatibleHandle ? compatibleHandle : &tempRPHandle; - *pRPHandle = target->compatibleRenderPassHandle(); + *pRPHandle = target->compatibleRenderPassHandle(withStencil); if (!pRPHandle->isValid()) { return nullptr; } @@ -363,12 +365,11 @@ void GrVkResourceProvider::checkCommandBuffers() { } void GrVkResourceProvider::addFinishedProcToActiveCommandBuffers( - GrGpuFinishedProc finishedProc, GrGpuFinishedContext finishedContext) { - sk_sp<GrRefCntedCallback> procRef(new GrRefCntedCallback(finishedProc, finishedContext)); + sk_sp<GrRefCntedCallback> finishedCallback) { for (int i = 0; i < fActiveCommandPools.count(); ++i) { GrVkCommandPool* pool = fActiveCommandPools[i]; GrVkPrimaryCommandBuffer* buffer = pool->getPrimaryCommandBuffer(); - buffer->addFinishedProc(procRef); + buffer->addFinishedProc(finishedCallback); } } diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkResourceProvider.h b/chromium/third_party/skia/src/gpu/vk/GrVkResourceProvider.h index d4ef8632aef..a3d72cf8b98 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkResourceProvider.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkResourceProvider.h @@ -57,7 +57,8 @@ public: // non null it will be set to a handle that can be used in the furutre to quickly return a // compatible GrVkRenderPasses without the need inspecting a GrVkRenderTarget. const GrVkRenderPass* findCompatibleRenderPass(const GrVkRenderTarget& target, - CompatibleRPHandle* compatibleHandle = nullptr); + CompatibleRPHandle* compatibleHandle, + bool withStencil); const GrVkRenderPass* findCompatibleRenderPass(GrVkRenderPass::AttachmentsDescriptor*, GrVkRenderPass::AttachmentFlags, CompatibleRPHandle* compatibleHandle = nullptr); @@ -73,7 +74,8 @@ public: const GrVkRenderPass* findRenderPass(GrVkRenderTarget* target, const GrVkRenderPass::LoadStoreOps& colorOps, const GrVkRenderPass::LoadStoreOps& stencilOps, - CompatibleRPHandle* compatibleHandle = nullptr); + CompatibleRPHandle* compatibleHandle, + bool withStencil); // The CompatibleRPHandle must be a valid handle previously set by a call to findRenderPass or // findCompatibleRenderPass. @@ -89,8 +91,7 @@ public: // that the client cares about before they explicitly called flush and the GPU may reorder // command execution. So we make sure all previously submitted work finishes before we call the // finishedProc. - void addFinishedProcToActiveCommandBuffers(GrGpuFinishedProc finishedProc, - GrGpuFinishedContext finishedContext); + void addFinishedProcToActiveCommandBuffers(sk_sp<GrRefCntedCallback> finishedCallback); // Finds or creates a compatible GrVkDescriptorPool for the requested type and count. // The refcount is incremented and a pointer returned. diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkSamplerYcbcrConversion.h b/chromium/third_party/skia/src/gpu/vk/GrVkSamplerYcbcrConversion.h index 05c10b848ba..829129841ff 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkSamplerYcbcrConversion.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkSamplerYcbcrConversion.h @@ -23,7 +23,7 @@ public: struct Key { Key() : fVkFormat(VK_FORMAT_UNDEFINED), fExternalFormat(0), fConversionKey(0) {} - Key(VkFormat vkFormat, uint64_t externalFormat, uint8_t conversionKey) { + Key(VkFormat vkFormat, int64_t externalFormat, uint8_t conversionKey) { memset(this, 0, sizeof(Key)); fVkFormat = vkFormat; fExternalFormat = externalFormat; @@ -31,7 +31,7 @@ public: } VkFormat fVkFormat; - uint64_t fExternalFormat; + int64_t fExternalFormat; uint8_t fConversionKey; bool operator==(const Key& that) const { diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkSemaphore.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkSemaphore.cpp index ee68cdd68a3..23bf656bf86 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkSemaphore.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkSemaphore.cpp @@ -38,6 +38,7 @@ std::unique_ptr<GrVkSemaphore> GrVkSemaphore::MakeWrapped(GrVkGpu* gpu, WrapType wrapType, GrWrapOwnership ownership) { if (VK_NULL_HANDLE == semaphore) { + SkDEBUGFAIL("Trying to wrap an invalid VkSemaphore"); return nullptr; } bool prohibitSignal = WrapType::kWillWait == wrapType; diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkStencilAttachment.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkStencilAttachment.cpp index 3236ac2a0b8..63a90ddb647 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkStencilAttachment.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkStencilAttachment.cpp @@ -17,10 +17,10 @@ GrVkStencilAttachment::GrVkStencilAttachment(GrVkGpu* gpu, const Format& format, const GrVkImage::ImageDesc& desc, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* stencilView) : GrStencilAttachment(gpu, desc.fWidth, desc.fHeight, format.fStencilBits, desc.fSamples) - , GrVkImage(gpu, info, std::move(layout), GrBackendObjectOwnership::kOwned) + , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kOwned) , fStencilView(stencilView) { this->registerWithCache(SkBudgeted::kYes); stencilView->ref(); @@ -57,9 +57,11 @@ GrVkStencilAttachment* GrVkStencilAttachment::Create(GrVkGpu* gpu, return nullptr; } - sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout)); + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState(new GrBackendSurfaceMutableStateImpl( + info.fImageLayout, info.fCurrentQueueFamily)); GrVkStencilAttachment* stencil = new GrVkStencilAttachment(gpu, format, imageDesc, - info, std::move(layout), imageView); + info, std::move(mutableState), + imageView); imageView->unref(); return stencil; @@ -79,8 +81,7 @@ size_t GrVkStencilAttachment::onGpuMemorySize() const { } void GrVkStencilAttachment::onRelease() { - GrVkGpu* gpu = this->getVkGpu(); - this->releaseImage(gpu); + this->releaseImage(); fStencilView->unref(); fStencilView = nullptr; @@ -88,8 +89,7 @@ void GrVkStencilAttachment::onRelease() { } void GrVkStencilAttachment::onAbandon() { - GrVkGpu* gpu = this->getVkGpu(); - this->releaseImage(gpu); + this->releaseImage(); fStencilView->unref(); fStencilView = nullptr; diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkStencilAttachment.h b/chromium/third_party/skia/src/gpu/vk/GrVkStencilAttachment.h index 8accd289fa4..ad96fae5178 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkStencilAttachment.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkStencilAttachment.h @@ -41,7 +41,7 @@ private: const Format& format, const GrVkImage::ImageDesc&, const GrVkImageInfo&, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* stencilView); GrVkGpu* getVkGpu() const; diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkTexture.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkTexture.cpp index ce3f49a0dd1..c930a288a59 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkTexture.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkTexture.cpp @@ -23,11 +23,11 @@ GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkBudgeted budgeted, SkISize dimensions, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* view, GrMipMapsStatus mipMapsStatus) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, std::move(layout), GrBackendObjectOwnership::kOwned) + , GrVkImage(gpu, info, std::move(mutableState), GrBackendObjectOwnership::kOwned) , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) , fTextureView(view) , fDescSetCache(kMaxCachedDescSets) { @@ -41,11 +41,12 @@ GrVkTexture::GrVkTexture(GrVkGpu* gpu, } GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, const GrVkImageView* view, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, + const GrVkImageView* view, GrMipMapsStatus mipMapsStatus, GrBackendObjectOwnership ownership, GrWrapCacheable cacheable, GrIOType ioType, bool isExternal) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, std::move(layout), ownership) + , GrVkImage(gpu, info, std::move(mutableState), ownership) , INHERITED(gpu, dimensions, info.fProtected, isExternal ? GrTextureType::kExternal : GrTextureType::k2D, mipMapsStatus) , fTextureView(view) @@ -61,12 +62,12 @@ GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& GrVkTexture::GrVkTexture(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* view, GrMipMapsStatus mipMapsStatus, GrBackendObjectOwnership ownership) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, layout, ownership) + , GrVkImage(gpu, info, std::move(mutableState), ownership) , INHERITED(gpu, dimensions, info.fProtected, GrTextureType::k2D, mipMapsStatus) , fTextureView(view) , fDescSetCache(kMaxCachedDescSets) { @@ -94,19 +95,16 @@ sk_sp<GrVkTexture> GrVkTexture::MakeNewTexture(GrVkGpu* gpu, SkBudgeted budgeted GrVkImage::DestroyImageInfo(gpu, &info); return nullptr; } - sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout)); - - return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, dimensions, info, std::move(layout), - imageView, mipMapsStatus)); + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState( + new GrBackendSurfaceMutableStateImpl(info.fImageLayout, info.fCurrentQueueFamily)); + return sk_sp<GrVkTexture>(new GrVkTexture(gpu, budgeted, dimensions, info, + std::move(mutableState), imageView, mipMapsStatus)); } -sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu, - SkISize dimensions, - GrWrapOwnership wrapOwnership, - GrWrapCacheable cacheable, - GrIOType ioType, - const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout) { +sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture( + GrVkGpu* gpu, SkISize dimensions, GrWrapOwnership wrapOwnership, GrWrapCacheable cacheable, + GrIOType ioType, const GrVkImageInfo& info, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) { // Adopted textures require both image and allocation because we're responsible for freeing SkASSERT(VK_NULL_HANDLE != info.fImage && (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory)); @@ -125,9 +123,9 @@ sk_sp<GrVkTexture> GrVkTexture::MakeWrappedTexture(GrVkGpu* gpu, ? GrBackendObjectOwnership::kBorrowed : GrBackendObjectOwnership::kOwned; bool isExternal = info.fYcbcrConversionInfo.isValid() && (info.fYcbcrConversionInfo.fExternalFormat != 0); - return sk_sp<GrVkTexture>(new GrVkTexture(gpu, dimensions, info, std::move(layout), imageView, - mipMapsStatus, ownership, cacheable, ioType, - isExternal)); + return sk_sp<GrVkTexture>(new GrVkTexture(gpu, dimensions, info, std::move(mutableState), + imageView, mipMapsStatus, ownership, cacheable, + ioType, isExternal)); } GrVkTexture::~GrVkTexture() { @@ -151,7 +149,7 @@ void GrVkTexture::onRelease() { fDescSetCache.reset(); - this->releaseImage(this->getVkGpu()); + this->releaseImage(); INHERITED::onRelease(); } @@ -185,12 +183,12 @@ void GrVkTexture::onAbandon() { fDescSetCache.reset(); - this->releaseImage(this->getVkGpu()); + this->releaseImage(); INHERITED::onAbandon(); } GrBackendTexture GrVkTexture::getBackendTexture() const { - return GrBackendTexture(this->width(), this->height(), fInfo, this->grVkImageLayout()); + return GrBackendTexture(this->width(), this->height(), fInfo, this->getMutableState()); } GrVkGpu* GrVkTexture::getVkGpu() const { diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkTexture.h b/chromium/third_party/skia/src/gpu/vk/GrVkTexture.h index 6a13f5af3a0..d719ef16973 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkTexture.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkTexture.h @@ -33,7 +33,7 @@ public: GrWrapCacheable, GrIOType, const GrVkImageInfo&, - sk_sp<GrVkImageLayout>); + sk_sp<GrBackendSurfaceMutableStateImpl>); ~GrVkTexture() override; @@ -61,7 +61,7 @@ protected: GrVkTexture(GrVkGpu*, SkISize dimensions, const GrVkImageInfo&, - sk_sp<GrVkImageLayout>, + sk_sp<GrBackendSurfaceMutableStateImpl>, const GrVkImageView*, GrMipMapsStatus, GrBackendObjectOwnership); @@ -78,9 +78,10 @@ protected: void willRemoveLastRef() override; private: - GrVkTexture(GrVkGpu*, SkBudgeted, SkISize, const GrVkImageInfo&, sk_sp<GrVkImageLayout> layout, - const GrVkImageView* imageView, GrMipMapsStatus); - GrVkTexture(GrVkGpu*, SkISize, const GrVkImageInfo&, sk_sp<GrVkImageLayout>, + GrVkTexture(GrVkGpu*, SkBudgeted, SkISize, const GrVkImageInfo&, + sk_sp<GrBackendSurfaceMutableStateImpl>, const GrVkImageView* imageView, + GrMipMapsStatus); + GrVkTexture(GrVkGpu*, SkISize, const GrVkImageInfo&, sk_sp<GrBackendSurfaceMutableStateImpl>, const GrVkImageView*, GrMipMapsStatus, GrBackendObjectOwnership, GrWrapCacheable, GrIOType, bool isExternal); diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkTextureRenderTarget.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkTextureRenderTarget.cpp index 0ce652a4ba0..39d87d33bc0 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkTextureRenderTarget.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkTextureRenderTarget.cpp @@ -18,82 +18,87 @@ #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X) -GrVkTextureRenderTarget::GrVkTextureRenderTarget(GrVkGpu* gpu, - SkBudgeted budgeted, - SkISize dimensions, - int sampleCnt, - const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, - const GrVkImageView* texView, - const GrVkImageInfo& msaaInfo, - sk_sp<GrVkImageLayout> msaaLayout, - const GrVkImageView* colorAttachmentView, - const GrVkImageView* resolveAttachmentView, - GrMipMapsStatus mipMapsStatus) +GrVkTextureRenderTarget::GrVkTextureRenderTarget( + GrVkGpu* gpu, + SkBudgeted budgeted, + SkISize dimensions, + int sampleCnt, + const GrVkImageInfo& info, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, + const GrVkImageView* texView, + const GrVkImageInfo& msaaInfo, + sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState, + const GrVkImageView* colorAttachmentView, + const GrVkImageView* resolveAttachmentView, + GrMipMapsStatus mipMapsStatus) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, layout, GrBackendObjectOwnership::kOwned) - , GrVkTexture(gpu, dimensions, info, layout, texView, mipMapsStatus, + , GrVkImage(gpu, info, mutableState, GrBackendObjectOwnership::kOwned) + , GrVkTexture(gpu, dimensions, info, mutableState, texView, mipMapsStatus, GrBackendObjectOwnership::kOwned) - , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, layout, msaaInfo, - std::move(msaaLayout), colorAttachmentView, resolveAttachmentView, + , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState), msaaInfo, + std::move(msaaMutableState), colorAttachmentView, resolveAttachmentView, GrBackendObjectOwnership::kOwned) { SkASSERT(info.fProtected == msaaInfo.fProtected); this->registerWithCache(budgeted); } -GrVkTextureRenderTarget::GrVkTextureRenderTarget(GrVkGpu* gpu, - SkBudgeted budgeted, - SkISize dimensions, - const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, - const GrVkImageView* texView, - const GrVkImageView* colorAttachmentView, - GrMipMapsStatus mipMapsStatus) +GrVkTextureRenderTarget::GrVkTextureRenderTarget( + GrVkGpu* gpu, + SkBudgeted budgeted, + SkISize dimensions, + const GrVkImageInfo& info, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, + const GrVkImageView* texView, + const GrVkImageView* colorAttachmentView, + GrMipMapsStatus mipMapsStatus) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, layout, GrBackendObjectOwnership::kOwned) - , GrVkTexture(gpu, dimensions, info, layout, texView, mipMapsStatus, + , GrVkImage(gpu, info, mutableState, GrBackendObjectOwnership::kOwned) + , GrVkTexture(gpu, dimensions, info, mutableState, texView, mipMapsStatus, GrBackendObjectOwnership::kOwned) - , GrVkRenderTarget(gpu, dimensions, info, layout, colorAttachmentView, + , GrVkRenderTarget(gpu, dimensions, info, std::move(mutableState), colorAttachmentView, GrBackendObjectOwnership::kOwned) { this->registerWithCache(budgeted); } -GrVkTextureRenderTarget::GrVkTextureRenderTarget(GrVkGpu* gpu, - SkISize dimensions, - int sampleCnt, - const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, - const GrVkImageView* texView, - const GrVkImageInfo& msaaInfo, - sk_sp<GrVkImageLayout> msaaLayout, - const GrVkImageView* colorAttachmentView, - const GrVkImageView* resolveAttachmentView, - GrMipMapsStatus mipMapsStatus, - GrBackendObjectOwnership ownership, - GrWrapCacheable cacheable) +GrVkTextureRenderTarget::GrVkTextureRenderTarget( + GrVkGpu* gpu, + SkISize dimensions, + int sampleCnt, + const GrVkImageInfo& info, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, + const GrVkImageView* texView, + const GrVkImageInfo& msaaInfo, + sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState, + const GrVkImageView* colorAttachmentView, + const GrVkImageView* resolveAttachmentView, + GrMipMapsStatus mipMapsStatus, + GrBackendObjectOwnership ownership, + GrWrapCacheable cacheable) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, layout, ownership) - , GrVkTexture(gpu, dimensions, info, layout, texView, mipMapsStatus, ownership) - , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, layout, msaaInfo, - std::move(msaaLayout), colorAttachmentView, resolveAttachmentView, + , GrVkImage(gpu, info, mutableState, ownership) + , GrVkTexture(gpu, dimensions, info, mutableState, texView, mipMapsStatus, ownership) + , GrVkRenderTarget(gpu, dimensions, sampleCnt, info, std::move(mutableState), msaaInfo, + std::move(msaaMutableState), colorAttachmentView, resolveAttachmentView, ownership) { SkASSERT(info.fProtected == msaaInfo.fProtected); this->registerWithCacheWrapped(cacheable); } -GrVkTextureRenderTarget::GrVkTextureRenderTarget(GrVkGpu* gpu, - SkISize dimensions, - const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, - const GrVkImageView* texView, - const GrVkImageView* colorAttachmentView, - GrMipMapsStatus mipMapsStatus, - GrBackendObjectOwnership ownership, - GrWrapCacheable cacheable) +GrVkTextureRenderTarget::GrVkTextureRenderTarget( + GrVkGpu* gpu, + SkISize dimensions, + const GrVkImageInfo& info, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, + const GrVkImageView* texView, + const GrVkImageView* colorAttachmentView, + GrMipMapsStatus mipMapsStatus, + GrBackendObjectOwnership ownership, + GrWrapCacheable cacheable) : GrSurface(gpu, dimensions, info.fProtected) - , GrVkImage(gpu, info, layout, ownership) - , GrVkTexture(gpu, dimensions, info, layout, texView, mipMapsStatus, ownership) - , GrVkRenderTarget(gpu, dimensions, info, layout, colorAttachmentView, ownership) { + , GrVkImage(gpu, info, mutableState, ownership) + , GrVkTexture(gpu, dimensions, info, mutableState, texView, mipMapsStatus, ownership) + , GrVkRenderTarget(gpu, dimensions, info, std::move(mutableState), colorAttachmentView, + ownership) { this->registerWithCacheWrapped(cacheable); } @@ -103,7 +108,7 @@ struct Views { const GrVkImageView* colorAttachmentView = nullptr; const GrVkImageView* resolveAttachmentView = nullptr; GrVkImageInfo msInfo; - sk_sp<GrVkImageLayout> msLayout; + sk_sp<GrBackendSurfaceMutableStateImpl> msMutableState; }; } // anonymous namespace @@ -154,7 +159,8 @@ static Views create_views(GrVkGpu* gpu, SkISize dimensions, int sampleCnt, views.imageView->unref(); return {}; } - views.msLayout.reset(new GrVkImageLayout(views.msInfo.fImageLayout)); + views.msMutableState.reset(new GrBackendSurfaceMutableStateImpl( + views.msInfo.fImageLayout, views.msInfo.fCurrentQueueFamily)); } else { // Set color attachment image colorImage = info.fImage; @@ -187,7 +193,8 @@ sk_sp<GrVkTextureRenderTarget> GrVkTextureRenderTarget::MakeNewTextureRenderTarg if (!GrVkImage::InitImageInfo(gpu, imageDesc, &info)) { return nullptr; } - sk_sp<GrVkImageLayout> layout(new GrVkImageLayout(info.fImageLayout)); + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState( + new GrBackendSurfaceMutableStateImpl(info.fImageLayout, info.fCurrentQueueFamily)); Views views = create_views(gpu, dimensions, sampleCnt, info); if (!views.colorAttachmentView) { @@ -196,12 +203,12 @@ sk_sp<GrVkTextureRenderTarget> GrVkTextureRenderTarget::MakeNewTextureRenderTarg } if (sampleCnt > 1) { return sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget( - gpu, budgeted, dimensions, sampleCnt, info, std::move(layout), views.imageView, - views.msInfo, std::move(views.msLayout), views.colorAttachmentView, - views.resolveAttachmentView, mipMapsStatus)); + gpu, budgeted, dimensions, sampleCnt, info, std::move(mutableState), + views.imageView, views.msInfo, std::move(views.msMutableState), + views.colorAttachmentView, views.resolveAttachmentView, mipMapsStatus)); } else { return sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget( - gpu, budgeted, dimensions, info, std::move(layout), views.imageView, + gpu, budgeted, dimensions, info, std::move(mutableState), views.imageView, views.colorAttachmentView, mipMapsStatus)); } } @@ -213,7 +220,7 @@ sk_sp<GrVkTextureRenderTarget> GrVkTextureRenderTarget::MakeWrappedTextureRender GrWrapOwnership wrapOwnership, GrWrapCacheable cacheable, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout) { + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState) { // Adopted textures require both image and allocation because we're responsible for freeing SkASSERT(VK_NULL_HANDLE != info.fImage && (kBorrow_GrWrapOwnership == wrapOwnership || VK_NULL_HANDLE != info.fAlloc.fMemory)); @@ -229,12 +236,12 @@ sk_sp<GrVkTextureRenderTarget> GrVkTextureRenderTarget::MakeWrappedTextureRender } if (sampleCnt > 1) { return sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget( - gpu, dimensions, sampleCnt, info, std::move(layout), views.imageView, views.msInfo, - std::move(views.msLayout), views.colorAttachmentView, views.resolveAttachmentView, - mipMapsStatus, ownership, cacheable)); + gpu, dimensions, sampleCnt, info, std::move(mutableState), views.imageView, + views.msInfo, std::move(views.msMutableState), views.colorAttachmentView, + views.resolveAttachmentView, mipMapsStatus, ownership, cacheable)); } else { return sk_sp<GrVkTextureRenderTarget>(new GrVkTextureRenderTarget( - gpu, dimensions, info, std::move(layout), views.imageView, + gpu, dimensions, info, std::move(mutableState), views.imageView, views.colorAttachmentView, mipMapsStatus, ownership, cacheable)); } } diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkTextureRenderTarget.h b/chromium/third_party/skia/src/gpu/vk/GrVkTextureRenderTarget.h index e3191751819..adc352d48fa 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkTextureRenderTarget.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkTextureRenderTarget.h @@ -32,13 +32,14 @@ public: const GrVkImage::ImageDesc&, GrMipMapsStatus); - static sk_sp<GrVkTextureRenderTarget> MakeWrappedTextureRenderTarget(GrVkGpu*, - SkISize dimensions, - int sampleCnt, - GrWrapOwnership, - GrWrapCacheable, - const GrVkImageInfo&, - sk_sp<GrVkImageLayout>); + static sk_sp<GrVkTextureRenderTarget> MakeWrappedTextureRenderTarget( + GrVkGpu*, + SkISize dimensions, + int sampleCnt, + GrWrapOwnership, + GrWrapCacheable, + const GrVkImageInfo&, + sk_sp<GrBackendSurfaceMutableStateImpl>); GrBackendFormat backendFormat() const override { return this->getBackendFormat(); } @@ -62,10 +63,10 @@ private: SkISize dimensions, int sampleCnt, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* texView, const GrVkImageInfo& msaaInfo, - sk_sp<GrVkImageLayout> msaaLayout, + sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState, const GrVkImageView* colorAttachmentView, const GrVkImageView* resolveAttachmentView, GrMipMapsStatus); @@ -75,7 +76,7 @@ private: SkBudgeted budgeted, SkISize dimensions, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* texView, const GrVkImageView* colorAttachmentView, GrMipMapsStatus); @@ -85,10 +86,10 @@ private: SkISize dimensions, int sampleCnt, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* texView, const GrVkImageInfo& msaaInfo, - sk_sp<GrVkImageLayout> msaaLayout, + sk_sp<GrBackendSurfaceMutableStateImpl> msaaMutableState, const GrVkImageView* colorAttachmentView, const GrVkImageView* resolveAttachmentView, GrMipMapsStatus, @@ -99,7 +100,7 @@ private: GrVkTextureRenderTarget(GrVkGpu* gpu, SkISize dimensions, const GrVkImageInfo& info, - sk_sp<GrVkImageLayout> layout, + sk_sp<GrBackendSurfaceMutableStateImpl> mutableState, const GrVkImageView* texView, const GrVkImageView* colorAttachmentView, GrMipMapsStatus, diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkTypesPriv.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkTypesPriv.cpp index 6f5d0b27f23..5360ab46b5d 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkTypesPriv.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkTypesPriv.cpp @@ -7,44 +7,32 @@ #include "include/private/GrVkTypesPriv.h" +#include "src/gpu/GrBackendSurfaceMutableStateImpl.h" #include "src/gpu/vk/GrVkImageLayout.h" -void GrVkBackendSurfaceInfo::cleanup() { - SkSafeUnref(fLayout); - fLayout = nullptr; -}; +void GrVkBackendSurfaceInfo::cleanup() {}; void GrVkBackendSurfaceInfo::assign(const GrVkBackendSurfaceInfo& that, bool isThisValid) { fImageInfo = that.fImageInfo; - GrVkImageLayout* oldLayout = fLayout; - fLayout = SkSafeRef(that.fLayout); - if (isThisValid) { - SkSafeUnref(oldLayout); - } } -void GrVkBackendSurfaceInfo::setImageLayout(VkImageLayout layout) { - SkASSERT(fLayout); - fLayout->setImageLayout(layout); -} - -sk_sp<GrVkImageLayout> GrVkBackendSurfaceInfo::getGrVkImageLayout() const { - SkASSERT(fLayout); - return sk_ref_sp(fLayout); -} - -GrVkImageInfo GrVkBackendSurfaceInfo::snapImageInfo() const { - return GrVkImageInfo(fImageInfo, fLayout->getImageLayout()); +GrVkImageInfo GrVkBackendSurfaceInfo::snapImageInfo( + const GrBackendSurfaceMutableStateImpl* mutableState) const { + SkASSERT(mutableState); + return GrVkImageInfo(fImageInfo, mutableState->getImageLayout(), + mutableState->getQueueFamilyIndex()); } #if GR_TEST_UTILS bool GrVkBackendSurfaceInfo::operator==(const GrVkBackendSurfaceInfo& that) const { GrVkImageInfo cpyInfoThis = fImageInfo; GrVkImageInfo cpyInfoThat = that.fImageInfo; - // We don't care about the fImageLayout here since we require they use the same - // GrVkImageLayout. + // We don't care about the fImageLayout or fCurrentQueueFamily here since we require they use + // the same mutableState. cpyInfoThis.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; cpyInfoThat.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED; - return cpyInfoThis == cpyInfoThat && fLayout == that.fLayout; + cpyInfoThis.fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED; + cpyInfoThat.fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED; + return cpyInfoThis == cpyInfoThat; } #endif diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkUtil.cpp b/chromium/third_party/skia/src/gpu/vk/GrVkUtil.cpp index bd73858bd65..892d6055831 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkUtil.cpp +++ b/chromium/third_party/skia/src/gpu/vk/GrVkUtil.cpp @@ -151,12 +151,3 @@ bool GrVkFormatIsCompressed(VkFormat vkFormat) { SkUNREACHABLE; } -SkImage::CompressionType GrVkFormatToCompressionType(VkFormat vkFormat) { - switch (vkFormat) { - case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: return SkImage::CompressionType::kETC2_RGB8_UNORM; - case VK_FORMAT_BC1_RGB_UNORM_BLOCK: return SkImage::CompressionType::kBC1_RGB8_UNORM; - case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: return SkImage::CompressionType::kBC1_RGBA8_UNORM; - default: return SkImage::CompressionType::kNone; - } - SkUNREACHABLE; -} diff --git a/chromium/third_party/skia/src/gpu/vk/GrVkUtil.h b/chromium/third_party/skia/src/gpu/vk/GrVkUtil.h index e66cd81fc9f..ba24ea4d2d6 100644 --- a/chromium/third_party/skia/src/gpu/vk/GrVkUtil.h +++ b/chromium/third_party/skia/src/gpu/vk/GrVkUtil.h @@ -21,25 +21,31 @@ class GrVkGpu; // makes a Vk call on the interface #define GR_VK_CALL(IFACE, X) (IFACE)->fFunctions.f##X -#define GR_VK_CALL_RESULT(GPU, RESULT, X) \ - do { \ - (RESULT) = GR_VK_CALL(GPU->vkInterface(), X); \ - SkASSERT(VK_SUCCESS == RESULT || VK_ERROR_DEVICE_LOST == RESULT); \ - if (RESULT != VK_SUCCESS && !GPU->isDeviceLost()) { \ - SkDebugf("Failed vulkan call. Error: %d\n", RESULT); \ - } \ - if (VK_ERROR_DEVICE_LOST == RESULT) { \ - GPU->setDeviceLost(); \ - } \ - } while(false) - -#define GR_VK_CALL_RESULT_NOCHECK(GPU, RESULT, X) \ - do { \ - (RESULT) = GR_VK_CALL(GPU->vkInterface(), X); \ - if (VK_ERROR_DEVICE_LOST == RESULT) { \ - GPU->setDeviceLost(); \ - } \ - } while(false) +#define GR_VK_CALL_RESULT(GPU, RESULT, X) \ + do { \ + (RESULT) = GR_VK_CALL(GPU->vkInterface(), X); \ + SkASSERT(VK_SUCCESS == RESULT || VK_ERROR_DEVICE_LOST == RESULT); \ + if (RESULT != VK_SUCCESS && !GPU->isDeviceLost()) { \ + SkDebugf("Failed vulkan call. Error: %d," #X "\n", RESULT); \ + } \ + if (RESULT == VK_ERROR_DEVICE_LOST) { \ + GPU->setDeviceLost(); \ + } else if (RESULT == VK_ERROR_OUT_OF_HOST_MEMORY || \ + RESULT == VK_ERROR_OUT_OF_DEVICE_MEMORY) { \ + GPU->setOOMed(); \ + } \ + } while (false) + +#define GR_VK_CALL_RESULT_NOCHECK(GPU, RESULT, X) \ + do { \ + (RESULT) = GR_VK_CALL(GPU->vkInterface(), X); \ + if (RESULT == VK_ERROR_DEVICE_LOST) { \ + GPU->setDeviceLost(); \ + } else if (RESULT == VK_ERROR_OUT_OF_HOST_MEMORY || \ + RESULT == VK_ERROR_OUT_OF_DEVICE_MEMORY) { \ + GPU->setOOMed(); \ + } \ + } while (false) // same as GR_VK_CALL but checks for success #define GR_VK_CALL_ERRCHECK(GPU, X) \ @@ -101,11 +107,6 @@ bool GrInstallVkShaderModule(GrVkGpu* gpu, */ bool GrVkFormatIsCompressed(VkFormat); -/** - * Maps a vk format into the CompressionType enum if applicable. - */ -SkImage::CompressionType GrVkFormatToCompressionType(VkFormat vkFormat); - #if GR_TEST_UTILS static constexpr const char* GrVkFormatToStr(VkFormat vkFormat) { switch (vkFormat) { diff --git a/chromium/third_party/skia/src/image/SkImage.cpp b/chromium/third_party/skia/src/image/SkImage.cpp index cbfc769f1ed..4b5afd889e6 100644 --- a/chromium/third_party/skia/src/image/SkImage.cpp +++ b/chromium/third_party/skia/src/image/SkImage.cpp @@ -84,7 +84,14 @@ sk_sp<SkColorSpace> SkImage::refColorSpace() const { return fInfo.refColorSpace( sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy, const SkMatrix* localMatrix) const { - return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy, localMatrix); + return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy, localMatrix, + SkImageShader::kInheritFromPaint); +} + +sk_sp<SkShader> SkImage::makeShader(SkTileMode tmx, SkTileMode tmy, + const SkMatrix* localMatrix, SkFilterQuality filtering) const { + return SkImageShader::Make(sk_ref_sp(const_cast<SkImage*>(this)), tmx, tmy, localMatrix, + SkImageShader::FilterEnum(filtering)); } sk_sp<SkData> SkImage::encodeToData(SkEncodedImageFormat type, int quality) const { @@ -160,7 +167,10 @@ GrSemaphoresSubmitted SkImage::flush(GrContext* context, const GrFlushInfo& flus return as_IB(this)->onFlush(context, flushInfo); } -void SkImage::flush(GrContext* context) { as_IB(this)->onFlush(context, {}); } +void SkImage::flushAndSubmit(GrContext* context) { + this->flush(context, {}); + context->submit(); +} #else @@ -182,7 +192,7 @@ GrSemaphoresSubmitted SkImage::flush(GrContext*, const GrFlushInfo&) { return GrSemaphoresSubmitted::kNo; } -void SkImage::flush(GrContext*) {} +void SkImage::flushAndSubmit(GrContext*) {} #endif @@ -281,7 +291,7 @@ sk_sp<SkImage> SkImage::makeWithFilter(GrContext* grContext, // subset's top left corner. But the clip bounds and any crop rects on the filters are in the // original coordinate system, so configure the CTM to correct crop rects and explicitly adjust // the clip bounds (since it is assumed to already be in image space). - SkImageFilter_Base::Context context(SkMatrix::MakeTrans(-subset.x(), -subset.y()), + SkImageFilter_Base::Context context(SkMatrix::Translate(-subset.x(), -subset.y()), clipBounds.makeOffset(-subset.topLeft()), cache.get(), fInfo.colorType(), fInfo.colorSpace(), srcSpecialImage.get()); diff --git a/chromium/third_party/skia/src/image/SkImage_Gpu.cpp b/chromium/third_party/skia/src/image/SkImage_Gpu.cpp index 13b1917e191..ae1feee6e47 100644 --- a/chromium/third_party/skia/src/image/SkImage_Gpu.cpp +++ b/chromium/third_party/skia/src/image/SkImage_Gpu.cpp @@ -22,9 +22,9 @@ #include "src/gpu/GrAHardwareBufferImageGenerator.h" #include "src/gpu/GrAHardwareBufferUtils.h" #include "src/gpu/GrBackendTextureImageGenerator.h" +#include "src/gpu/GrBackendUtils.h" #include "src/gpu/GrBitmapTextureMaker.h" #include "src/gpu/GrCaps.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrColorSpaceXform.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrDrawingManager.h" @@ -67,6 +67,12 @@ SkImage_Gpu::~SkImage_Gpu() {} GrSemaphoresSubmitted SkImage_Gpu::onFlush(GrContext* context, const GrFlushInfo& info) { if (!context || !fContext->priv().matches(context) || fContext->abandoned()) { + if (info.fSubmittedProc) { + info.fSubmittedProc(info.fSubmittedContext, false); + } + if (info.fFinishedProc) { + info.fFinishedProc(info.fFinishedContext); + } return GrSemaphoresSubmitted::kNo; } @@ -99,7 +105,7 @@ sk_sp<SkImage> SkImage_Gpu::onMakeColorTypeAndColorSpace(GrRecordingContext* con paint.addColorFragmentProcessor(std::move(xform)); } - renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), + renderTargetContext->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), SkRect::MakeIWH(this->width(), this->height())); if (!renderTargetContext->asTextureProxy()) { return nullptr; @@ -124,15 +130,14 @@ static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx, GrColorType colorType, GrSurfaceOrigin origin, SkAlphaType at, sk_sp<SkColorSpace> colorSpace, GrWrapOwnership ownership, - SkImage::TextureReleaseProc releaseProc, - SkImage::ReleaseContext releaseCtx) { + sk_sp<GrRefCntedCallback> releaseHelper) { if (!backendTex.isValid() || backendTex.width() <= 0 || backendTex.height() <= 0) { return nullptr; } GrProxyProvider* proxyProvider = ctx->priv().proxyProvider(); sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture( - backendTex, ownership, GrWrapCacheable::kNo, kRead_GrIOType, releaseProc, releaseCtx); + backendTex, ownership, GrWrapCacheable::kNo, kRead_GrIOType, std::move(releaseHelper)); if (!proxy) { return nullptr; } @@ -150,6 +155,11 @@ sk_sp<SkImage> SkImage::MakeFromCompressedTexture(GrContext* ctx, sk_sp<SkColorSpace> cs, TextureReleaseProc releaseP, ReleaseContext releaseC) { + sk_sp<GrRefCntedCallback> releaseHelper; + if (releaseP) { + releaseHelper.reset(new GrRefCntedCallback(releaseP, releaseC)); + } + if (!ctx) { return nullptr; } @@ -162,12 +172,12 @@ sk_sp<SkImage> SkImage::MakeFromCompressedTexture(GrContext* ctx, GrProxyProvider* proxyProvider = ctx->priv().proxyProvider(); sk_sp<GrTextureProxy> proxy = proxyProvider->wrapCompressedBackendTexture( - tex, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, releaseP, releaseC); + tex, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, std::move(releaseHelper)); if (!proxy) { return nullptr; } - CompressionType type = caps->compressionType(tex.getBackendFormat()); + CompressionType type = GrBackendFormatToCompressionType(tex.getBackendFormat()); SkColorType ct = GrCompressionTypeToSkColorType(type); GrSurfaceProxyView view(std::move(proxy), origin, GrSwizzle::RGBA()); @@ -179,6 +189,13 @@ sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, const GrBackendTexture& tex, GrSurfaceOrigin origin, SkColorType ct, SkAlphaType at, sk_sp<SkColorSpace> cs, TextureReleaseProc releaseP, ReleaseContext releaseC) { +#ifndef SK_LEGACY_MAKEFROMTEXTURE_BEHAVIOR + sk_sp<GrRefCntedCallback> releaseHelper; + if (releaseP) { + releaseHelper.reset(new GrRefCntedCallback(releaseP, releaseC)); + } +#endif + if (!ctx) { return nullptr; } @@ -194,8 +211,15 @@ sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, return nullptr; } +#ifdef SK_LEGACY_MAKEFROMTEXTURE_BEHAVIOR + sk_sp<GrRefCntedCallback> releaseHelper; + if (releaseP) { + releaseHelper.reset(new GrRefCntedCallback(releaseP, releaseC)); + } +#endif + return new_wrapped_texture_common(ctx, tex, grColorType, origin, at, std::move(cs), - kBorrow_GrWrapOwnership, releaseP, releaseC); + kBorrow_GrWrapOwnership, std::move(releaseHelper)); } sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, @@ -219,7 +243,7 @@ sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, } return new_wrapped_texture_common(ctx, tex, grColorType, origin, at, std::move(cs), - kAdopt_GrWrapOwnership, nullptr, nullptr); + kAdopt_GrWrapOwnership, nullptr); } sk_sp<SkImage> SkImage::MakeTextureFromCompressed(GrContext* context, sk_sp<SkData> data, @@ -267,7 +291,7 @@ sk_sp<SkImage> SkImage_Gpu::ConvertYUVATexturesToRGB(GrContext* ctx, SkYUVColorS GrSurfaceProxyView tempViews[4]; if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, yuvaIndices, - origin, tempViews)) { + origin, tempViews, nullptr)) { return nullptr; } @@ -316,6 +340,11 @@ sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopyWithExternalBackend( ReleaseContext releaseContext) { const GrCaps* caps = ctx->priv().caps(); + sk_sp<GrRefCntedCallback> releaseHelper; + if (textureReleaseProc) { + releaseHelper.reset(new GrRefCntedCallback(textureReleaseProc, releaseContext)); + } + GrColorType grColorType = SkColorTypeAndFormatToGrColorType(caps, kRGBA_8888_SkColorType, backendTexture.getBackendFormat()); if (GrColorType::kUnknown == grColorType) { @@ -332,7 +361,7 @@ sk_sp<SkImage> SkImage::MakeFromYUVATexturesCopyWithExternalBackend( // in order to draw to it for the yuv->rgb conversion. auto renderTargetContext = GrRenderTargetContext::MakeFromBackendTexture( ctx, grColorType, std::move(imageColorSpace), backendTexture, 1, imageOrigin, - nullptr, textureReleaseProc, releaseContext); + nullptr, std::move(releaseHelper)); if (!renderTargetContext) { return nullptr; } @@ -517,6 +546,10 @@ sk_sp<SkImage> SkImage_Gpu::MakePromiseTexture(GrContext* context, return nullptr; } + if (!context->priv().caps()->areColorTypeAndFormatCompatible(grColorType, backendFormat)) { + return nullptr; + } + callDone.clear(); auto proxy = MakePromiseImageLazyProxy(context, width, height, backendFormat, mipMapped, textureFulfillProc, textureReleaseProc, @@ -634,6 +667,9 @@ sk_sp<SkImage> SkImage::MakeFromAHardwareBufferWithData(GrContext* context, } SkASSERT(deleteImageProc); + sk_sp<GrRefCntedCallback> releaseHelper(new GrRefCntedCallback(deleteImageProc, + deleteImageCtx)); + SkColorType colorType = GrAHardwareBufferUtils::GetSkColorTypeFromBufferFormat(bufferDesc.format); @@ -641,15 +677,13 @@ sk_sp<SkImage> SkImage::MakeFromAHardwareBufferWithData(GrContext* context, GrProxyProvider* proxyProvider = context->priv().proxyProvider(); if (!proxyProvider) { - deleteImageProc(deleteImageCtx); return nullptr; } sk_sp<GrTextureProxy> proxy = proxyProvider->wrapBackendTexture( backendTexture, kBorrow_GrWrapOwnership, GrWrapCacheable::kNo, kRW_GrIOType, - deleteImageProc, deleteImageCtx); + std::move(releaseHelper)); if (!proxy) { - deleteImageProc(deleteImageCtx); return nullptr; } @@ -680,8 +714,7 @@ sk_sp<SkImage> SkImage::MakeFromAHardwareBufferWithData(GrContext* context, GrFlushInfo info; info.fFlags = kSyncCpu_GrFlushFlag; GrSurfaceProxy* p[1] = {surfaceContext.asSurfaceProxy()}; - drawingManager->flush(p, 1, SkSurface::BackendSurfaceAccess::kNoAccess, info, - GrPrepareForExternalIORequests()); + drawingManager->flush(p, 1, SkSurface::BackendSurfaceAccess::kNoAccess, info, nullptr); return image; } diff --git a/chromium/third_party/skia/src/image/SkImage_GpuBase.cpp b/chromium/third_party/skia/src/image/SkImage_GpuBase.cpp index e156e4e368f..07b8b8a4445 100644 --- a/chromium/third_party/skia/src/image/SkImage_GpuBase.cpp +++ b/chromium/third_party/skia/src/image/SkImage_GpuBase.cpp @@ -13,7 +13,6 @@ #include "include/private/GrRecordingContext.h" #include "src/core/SkBitmapCache.h" #include "src/core/SkTLList.h" -#include "src/gpu/GrClip.h" #include "src/gpu/GrContextPriv.h" #include "src/gpu/GrImageInfo.h" #include "src/gpu/GrProxyProvider.h" @@ -262,10 +261,13 @@ bool SkImage_GpuBase::onIsValid(GrContext* context) const { return true; } -bool SkImage_GpuBase::MakeTempTextureProxies(GrContext* ctx, const GrBackendTexture yuvaTextures[], - int numTextures, const SkYUVAIndex yuvaIndices[4], +bool SkImage_GpuBase::MakeTempTextureProxies(GrContext* ctx, + const GrBackendTexture yuvaTextures[], + int numTextures, + const SkYUVAIndex yuvaIndices[4], GrSurfaceOrigin imageOrigin, - GrSurfaceProxyView tempViews[4]) { + GrSurfaceProxyView tempViews[4], + sk_sp<GrRefCntedCallback> releaseHelper) { GrProxyProvider* proxyProvider = ctx->priv().proxyProvider(); for (int textureIndex = 0; textureIndex < numTextures; ++textureIndex) { const GrBackendFormat& backendFormat = yuvaTextures[textureIndex].getBackendFormat(); @@ -277,7 +279,8 @@ bool SkImage_GpuBase::MakeTempTextureProxies(GrContext* ctx, const GrBackendText auto proxy = proxyProvider->wrapBackendTexture(yuvaTextures[textureIndex], kBorrow_GrWrapOwnership, - GrWrapCacheable::kNo, kRead_GrIOType); + GrWrapCacheable::kNo, kRead_GrIOType, + releaseHelper); if (!proxy) { return false; } @@ -323,7 +326,7 @@ bool SkImage_GpuBase::RenderYUVAToRGBA(GrContext* ctx, GrRenderTargetContext* re } paint.addColorFragmentProcessor(std::move(fp)); - renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, SkMatrix::I(), rect); + renderTargetContext->drawRect(nullptr, std::move(paint), GrAA::kNo, SkMatrix::I(), rect); return true; } diff --git a/chromium/third_party/skia/src/image/SkImage_GpuBase.h b/chromium/third_party/skia/src/image/SkImage_GpuBase.h index 67b53c8eda9..ae332fc9722 100644 --- a/chromium/third_party/skia/src/image/SkImage_GpuBase.h +++ b/chromium/third_party/skia/src/image/SkImage_GpuBase.h @@ -55,7 +55,8 @@ public: static bool MakeTempTextureProxies(GrContext* ctx, const GrBackendTexture yuvaTextures[], int numTextures, const SkYUVAIndex [4], GrSurfaceOrigin imageOrigin, - GrSurfaceProxyView tempViews[4]); + GrSurfaceProxyView tempViews[4], + sk_sp<GrRefCntedCallback> releaseHelper); static SkAlphaType GetAlphaTypeFromYUVAIndices(const SkYUVAIndex yuvaIndices[4]) { return -1 != yuvaIndices[SkYUVAIndex::kA_Index].fIndex ? kPremul_SkAlphaType diff --git a/chromium/third_party/skia/src/image/SkImage_GpuYUVA.cpp b/chromium/third_party/skia/src/image/SkImage_GpuYUVA.cpp index 8aa15cbff39..0a76fedd1e7 100644 --- a/chromium/third_party/skia/src/image/SkImage_GpuYUVA.cpp +++ b/chromium/third_party/skia/src/image/SkImage_GpuYUVA.cpp @@ -117,6 +117,12 @@ bool SkImage_GpuYUVA::setupMipmapsForPlanes(GrRecordingContext* context) const { GrSemaphoresSubmitted SkImage_GpuYUVA::onFlush(GrContext* context, const GrFlushInfo& info) { if (!context || !fContext->priv().matches(context) || fContext->abandoned()) { + if (info.fSubmittedProc) { + info.fSubmittedProc(info.fSubmittedContext, false); + } + if (info.fFinishedProc) { + info.fFinishedProc(info.fFinishedContext); + } return GrSemaphoresSubmitted::kNo; } @@ -229,7 +235,14 @@ sk_sp<SkImage> SkImage::MakeFromYUVATextures(GrContext* ctx, const SkYUVAIndex yuvaIndices[4], SkISize imageSize, GrSurfaceOrigin imageOrigin, - sk_sp<SkColorSpace> imageColorSpace) { + sk_sp<SkColorSpace> imageColorSpace, + TextureReleaseProc textureReleaseProc, + ReleaseContext releaseContext) { + sk_sp<GrRefCntedCallback> releaseHelper; + if (textureReleaseProc) { + releaseHelper.reset(new GrRefCntedCallback(textureReleaseProc, releaseContext)); + } + int numTextures; if (!SkYUVAIndex::AreValidIndices(yuvaIndices, &numTextures)) { return nullptr; @@ -237,7 +250,8 @@ sk_sp<SkImage> SkImage::MakeFromYUVATextures(GrContext* ctx, GrSurfaceProxyView tempViews[4]; if (!SkImage_GpuBase::MakeTempTextureProxies(ctx, yuvaTextures, numTextures, yuvaIndices, - imageOrigin, tempViews)) { + imageOrigin, tempViews, + std::move(releaseHelper))) { return nullptr; } diff --git a/chromium/third_party/skia/src/image/SkImage_Lazy.cpp b/chromium/third_party/skia/src/image/SkImage_Lazy.cpp index fbfaac6dfa5..47be6901c23 100644 --- a/chromium/third_party/skia/src/image/SkImage_Lazy.cpp +++ b/chromium/third_party/skia/src/image/SkImage_Lazy.cpp @@ -128,7 +128,6 @@ SkImage_Lazy::SkImage_Lazy(Validator* validator) , fSharedGenerator(std::move(validator->fSharedGenerator)) , fOrigin(validator->fOrigin) { SkASSERT(fSharedGenerator); - fUniqueID = validator->fUniqueID; } diff --git a/chromium/third_party/skia/src/image/SkImage_Lazy.h b/chromium/third_party/skia/src/image/SkImage_Lazy.h index f27881401d0..dd18780f8e5 100644 --- a/chromium/third_party/skia/src/image/SkImage_Lazy.h +++ b/chromium/third_party/skia/src/image/SkImage_Lazy.h @@ -82,8 +82,6 @@ private: sk_sp<SharedGenerator> fSharedGenerator; const SkIPoint fOrigin; - uint32_t fUniqueID; - // Repeated calls to onMakeColorTypeAndColorSpace will result in a proliferation of unique IDs // and SkImage_Lazy instances. Cache the result of the last successful call. mutable SkMutex fOnMakeColorTypeAndSpaceMutex; diff --git a/chromium/third_party/skia/src/image/SkSurface.cpp b/chromium/third_party/skia/src/image/SkSurface.cpp index db8ec537862..18a125e11e3 100644 --- a/chromium/third_party/skia/src/image/SkSurface.cpp +++ b/chromium/third_party/skia/src/image/SkSurface.cpp @@ -444,43 +444,13 @@ bool SkSurface::replaceBackendTexture(const GrBackendTexture& backendTexture, releaseContext); } -void SkSurface::flushAndSubmit() { - this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo()); -} - GrSemaphoresSubmitted SkSurface::flush(BackendSurfaceAccess access, const GrFlushInfo& flushInfo) { - return asSB(this)->onFlush(access, flushInfo); -} - -GrSemaphoresSubmitted SkSurface::flush(BackendSurfaceAccess access, GrFlushFlags flags, - int numSemaphores, GrBackendSemaphore signalSemaphores[], - GrGpuFinishedProc finishedProc, - GrGpuFinishedContext finishedContext) { - GrFlushInfo info; - info.fFlags = flags; - info.fNumSemaphores = numSemaphores; - info.fSignalSemaphores = signalSemaphores; - info.fFinishedProc = finishedProc; - info.fFinishedContext = finishedContext; - return this->flush(access, info); + return asSB(this)->onFlush(access, flushInfo, nullptr); } -GrSemaphoresSubmitted SkSurface::flush(BackendSurfaceAccess access, FlushFlags flags, - int numSemaphores, GrBackendSemaphore signalSemaphores[]) { - GrFlushFlags grFlags = flags == kSyncCpu_FlushFlag ? kSyncCpu_GrFlushFlag : kNone_GrFlushFlags; - GrFlushInfo info; - info.fFlags = grFlags; - info.fNumSemaphores = numSemaphores; - info.fSignalSemaphores = signalSemaphores; - return this->flush(access, info); -} - -GrSemaphoresSubmitted SkSurface::flushAndSignalSemaphores(int numSemaphores, - GrBackendSemaphore signalSemaphores[]) { - GrFlushInfo info; - info.fNumSemaphores = numSemaphores; - info.fSignalSemaphores = signalSemaphores; - return this->flush(BackendSurfaceAccess::kNoAccess, info); +GrSemaphoresSubmitted SkSurface::flush(const GrFlushInfo& info, + const GrBackendSurfaceMutableState* newState) { + return asSB(this)->onFlush(BackendSurfaceAccess::kNoAccess, info, newState); } bool SkSurface::wait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) { @@ -558,14 +528,8 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext*, return nullptr; } -sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext*, - const GrBackendTexture&, - GrSurfaceOrigin origin, - int sampleCnt, - SkColorType, - sk_sp<SkColorSpace>, - const SkSurfaceProps*) { - return nullptr; +void SkSurface::flushAndSubmit() { + this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo()); } #endif diff --git a/chromium/third_party/skia/src/image/SkSurface_Base.h b/chromium/third_party/skia/src/image/SkSurface_Base.h index b38edd8d9f2..e4b750c6d03 100644 --- a/chromium/third_party/skia/src/image/SkSurface_Base.h +++ b/chromium/third_party/skia/src/image/SkSurface_Base.h @@ -107,7 +107,8 @@ public: * Inserts the requested number of semaphores for the gpu to signal when work is complete on the * gpu and inits the array of GrBackendSemaphores with the signaled semaphores. */ - virtual GrSemaphoresSubmitted onFlush(BackendSurfaceAccess access, const GrFlushInfo&) { + virtual GrSemaphoresSubmitted onFlush(BackendSurfaceAccess access, const GrFlushInfo&, + const GrBackendSurfaceMutableState*) { return GrSemaphoresSubmitted::kNo; } diff --git a/chromium/third_party/skia/src/image/SkSurface_Gpu.cpp b/chromium/third_party/skia/src/image/SkSurface_Gpu.cpp index 173af27fb99..3113b805bb4 100644 --- a/chromium/third_party/skia/src/image/SkSurface_Gpu.cpp +++ b/chromium/third_party/skia/src/image/SkSurface_Gpu.cpp @@ -5,12 +5,15 @@ * found in the LICENSE file. */ +#include "src/image/SkSurface_Gpu.h" + #include "include/core/SkCanvas.h" #include "include/core/SkDeferredDisplayList.h" #include "include/core/SkSurfaceCharacterization.h" #include "include/gpu/GrBackendSurface.h" #include "include/private/GrRecordingContext.h" #include "src/core/SkImagePriv.h" +#include "src/core/SkScopeExit.h" #include "src/gpu/GrAHardwareBufferUtils.h" #include "src/gpu/GrCaps.h" #include "src/gpu/GrContextPriv.h" @@ -24,7 +27,6 @@ #include "src/image/SkImage_Base.h" #include "src/image/SkImage_Gpu.h" #include "src/image/SkSurface_Base.h" -#include "src/image/SkSurface_Gpu.h" #if SK_SUPPORT_GPU @@ -54,7 +56,7 @@ static GrRenderTarget* prepare_rt_for_external_access(SkSurface_Gpu* surface, } // Grab the render target *after* firing notifications, as it may get switched if CoW kicks in. - surface->getDevice()->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo()); + surface->getDevice()->flush(SkSurface::BackendSurfaceAccess::kNoAccess, GrFlushInfo(), nullptr); GrRenderTargetContext* rtc = surface->getDevice()->accessRenderTargetContext(); return rtc->accessRenderTarget(); } @@ -185,9 +187,9 @@ void SkSurface_Gpu::onDiscard() { fDevice->accessRenderTargetContext()->discard(); } -GrSemaphoresSubmitted SkSurface_Gpu::onFlush(BackendSurfaceAccess access, - const GrFlushInfo& info) { - return fDevice->flush(access, info); +GrSemaphoresSubmitted SkSurface_Gpu::onFlush(BackendSurfaceAccess access, const GrFlushInfo& info, + const GrBackendSurfaceMutableState* newState) { + return fDevice->flush(access, info, newState); } bool SkSurface_Gpu::onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) { @@ -233,7 +235,6 @@ void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPai // If the dst is also GPU we try to not force a new image snapshot (by calling the base class // onDraw) since that may not always perform the copy-on-write optimization. auto tryDraw = [&] { - SkASSERT(fDevice->context()->priv().asDirectContext()); GrContext* context = fDevice->context(); GrContext* canvasContext = canvas->getGrContext(); if (!canvasContext) { @@ -418,6 +419,11 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrBackendTexture& backendTexture, TextureReleaseProc textureReleaseProc, ReleaseContext releaseContext) { + sk_sp<GrRefCntedCallback> releaseHelper; + if (textureReleaseProc) { + releaseHelper.reset(new GrRefCntedCallback(textureReleaseProc, releaseContext)); + } + if (!context || !c.isValid()) { return nullptr; } @@ -444,7 +450,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, auto rtc = GrRenderTargetContext::MakeFromBackendTexture( context, grCT, c.refColorSpace(), backendTexture, c.sampleCount(), c.origin(), - &c.surfaceProps(), textureReleaseProc, releaseContext); + &c.surfaceProps(), std::move(releaseHelper)); if (!rtc) { return nullptr; } @@ -508,6 +514,11 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrB const SkSurfaceProps* props, SkSurface::TextureReleaseProc textureReleaseProc, SkSurface::ReleaseContext releaseContext) { + sk_sp<GrRefCntedCallback> releaseHelper; + if (textureReleaseProc) { + releaseHelper.reset(new GrRefCntedCallback(textureReleaseProc, releaseContext)); + } + if (!context) { return nullptr; } @@ -525,7 +536,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrB auto rtc = GrRenderTargetContext::MakeFromBackendTexture( context, grColorType, std::move(colorSpace), tex, sampleCnt, origin, props, - textureReleaseProc, releaseContext); + std::move(releaseHelper)); if (!rtc) { return nullptr; } @@ -538,8 +549,15 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTexture(GrContext* context, const GrB } bool SkSurface_Gpu::onReplaceBackendTexture(const GrBackendTexture& backendTexture, - GrSurfaceOrigin origin, ContentChangeMode mode, TextureReleaseProc releaseProc, + GrSurfaceOrigin origin, + ContentChangeMode mode, + TextureReleaseProc releaseProc, ReleaseContext releaseContext) { + sk_sp<GrRefCntedCallback> releaseHelper; + if (releaseProc) { + releaseHelper.reset(new GrRefCntedCallback(releaseProc, releaseContext)); + } + auto context = this->fDevice->context(); if (context->abandoned()) { return false; @@ -578,7 +596,7 @@ bool SkSurface_Gpu::onReplaceBackendTexture(const GrBackendTexture& backendTextu } auto rtc = GrRenderTargetContext::MakeFromBackendTexture( context, oldRTC->colorInfo().colorType(), std::move(colorSpace), backendTexture, - sampleCnt, origin, &this->props(), releaseProc, releaseContext); + sampleCnt, origin, &this->props(), std::move(releaseHelper)); if (!rtc) { return false; } @@ -606,6 +624,12 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context, const SkSurfaceProps* props, SkSurface::RenderTargetReleaseProc relProc, SkSurface::ReleaseContext releaseContext) { + SkScopeExit callProc([&] { + if (relProc) { + relProc(releaseContext); + } + }); + if (!context) { return nullptr; } @@ -626,6 +650,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context, if (!rtc) { return nullptr; } + callProc.clear(); auto device = SkGpuDevice::Make(context, std::move(rtc), SkGpuDevice::kUninit_InitContents); if (!device) { @@ -635,6 +660,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendRenderTarget(GrContext* context, return sk_make_sp<SkSurface_Gpu>(std::move(device)); } +#if GR_TEST_UTILS sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* context, const GrBackendTexture& tex, GrSurfaceOrigin origin, @@ -668,6 +694,7 @@ sk_sp<SkSurface> SkSurface::MakeFromBackendTextureAsRenderTarget(GrContext* cont } return sk_make_sp<SkSurface_Gpu>(std::move(device)); } +#endif #if defined(SK_BUILD_FOR_ANDROID) && __ANDROID_API__ >= 26 sk_sp<SkSurface> SkSurface::MakeFromAHardwareBuffer(GrContext* context, @@ -732,4 +759,11 @@ sk_sp<SkSurface> SkSurface::MakeFromAHardwareBuffer(GrContext* context, } #endif +void SkSurface::flushAndSubmit() { + this->flush(BackendSurfaceAccess::kNoAccess, GrFlushInfo()); + if (this->getContext()) { + this->getContext()->submit(); + } +} + #endif diff --git a/chromium/third_party/skia/src/image/SkSurface_Gpu.h b/chromium/third_party/skia/src/image/SkSurface_Gpu.h index 9ee67dc360b..0667b33a1e7 100644 --- a/chromium/third_party/skia/src/image/SkSurface_Gpu.h +++ b/chromium/third_party/skia/src/image/SkSurface_Gpu.h @@ -51,7 +51,8 @@ public: void onCopyOnWrite(ContentChangeMode) override; void onDiscard() override; - GrSemaphoresSubmitted onFlush(BackendSurfaceAccess access, const GrFlushInfo& info) override; + GrSemaphoresSubmitted onFlush(BackendSurfaceAccess access, const GrFlushInfo& info, + const GrBackendSurfaceMutableState*) override; bool onWait(int numSemaphores, const GrBackendSemaphore* waitSemaphores) override; bool onCharacterize(SkSurfaceCharacterization*) const override; bool onIsCompatible(const SkSurfaceCharacterization&) const override; diff --git a/chromium/third_party/skia/src/images/SkWebpEncoder.cpp b/chromium/third_party/skia/src/images/SkWebpEncoder.cpp index de7aae353f3..07b8fa018e4 100644 --- a/chromium/third_party/skia/src/images/SkWebpEncoder.cpp +++ b/chromium/third_party/skia/src/images/SkWebpEncoder.cpp @@ -14,6 +14,7 @@ #include "include/core/SkUnPreMultiply.h" #include "include/encode/SkWebpEncoder.h" #include "include/private/SkColorData.h" +#include "include/private/SkImageInfoPriv.h" #include "include/private/SkTemplates.h" #include "src/images/SkImageEncoderFns.h" #include "src/utils/SkUTF.h" @@ -32,85 +33,25 @@ extern "C" { #include "webp/mux.h" } -static transform_scanline_proc choose_proc(const SkImageInfo& info) { - switch (info.colorType()) { - case kRGBA_8888_SkColorType: - switch (info.alphaType()) { - case kOpaque_SkAlphaType: - return transform_scanline_RGBX; - case kUnpremul_SkAlphaType: - return transform_scanline_memcpy; - case kPremul_SkAlphaType: - return transform_scanline_rgbA; - default: - return nullptr; - } - case kBGRA_8888_SkColorType: - switch (info.alphaType()) { - case kOpaque_SkAlphaType: - return transform_scanline_BGRX; - case kUnpremul_SkAlphaType: - return transform_scanline_BGRA; - case kPremul_SkAlphaType: - return transform_scanline_bgrA; - default: - return nullptr; - } - case kRGB_565_SkColorType: - if (!info.isOpaque()) { - return nullptr; - } - - return transform_scanline_565; - case kARGB_4444_SkColorType: - switch (info.alphaType()) { - case kOpaque_SkAlphaType: - return transform_scanline_444; - case kPremul_SkAlphaType: - return transform_scanline_4444; - default: - return nullptr; - } - case kGray_8_SkColorType: - return transform_scanline_gray; - case kRGBA_F16_SkColorType: - switch (info.alphaType()) { - case kOpaque_SkAlphaType: - case kUnpremul_SkAlphaType: - return transform_scanline_F16_to_8888; - case kPremul_SkAlphaType: - return transform_scanline_F16_premul_to_8888; - default: - return nullptr; - } - default: - return nullptr; - } -} - static int stream_writer(const uint8_t* data, size_t data_size, const WebPPicture* const picture) { SkWStream* const stream = (SkWStream*)picture->custom_ptr; return stream->write(data, data_size) ? 1 : 0; } +using WebPPictureImportProc = int (*) (WebPPicture* picture, const uint8_t* pixels, int stride); + bool SkWebpEncoder::Encode(SkWStream* stream, const SkPixmap& pixmap, const Options& opts) { if (!SkPixmapIsValid(pixmap)) { return false; } - const transform_scanline_proc proc = choose_proc(pixmap.info()); - if (!proc) { + if (SkColorTypeIsAlphaOnly(pixmap.colorType())) { + // Maintain the existing behavior of not supporting encoding alpha-only images. + // TODO: Support encoding alpha only to an image with alpha but no color? return false; } - int bpp; - if (kRGBA_F16_SkColorType == pixmap.colorType()) { - bpp = 4; - } else { - bpp = pixmap.isOpaque() ? 3 : 4; - } - if (nullptr == pixmap.addr()) { return false; } @@ -150,31 +91,32 @@ bool SkWebpEncoder::Encode(SkWStream* stream, const SkPixmap& pixmap, const Opti SkDynamicMemoryWStream tmp; pic.custom_ptr = icc ? (void*)&tmp : (void*)stream; - const uint8_t* src = (uint8_t*)pixmap.addr(); - const int rgbStride = pic.width * bpp; - const size_t rowBytes = pixmap.rowBytes(); - - // Import (for each scanline) the bit-map image (in appropriate color-space) - // to RGB color space. - std::unique_ptr<uint8_t[]> rgb(new uint8_t[rgbStride * pic.height]); - for (int y = 0; y < pic.height; ++y) { - proc((char*) &rgb[y * rgbStride], - (const char*) &src[y * rowBytes], - pic.width, - bpp); - } - - auto importProc = WebPPictureImportRGB; - if (3 != bpp) { - if (pixmap.isOpaque()) { - importProc = WebPPictureImportRGBX; - } else { + { + const SkColorType ct = pixmap.colorType(); + const bool premul = pixmap.alphaType() == kPremul_SkAlphaType; + + SkBitmap tmpBm; + WebPPictureImportProc importProc = nullptr; + const SkPixmap* src = &pixmap; + if ( ct == kRGB_888x_SkColorType) { importProc = WebPPictureImportRGBX; } + else if (!premul && ct == kRGBA_8888_SkColorType) { importProc = WebPPictureImportRGBA; } +#ifdef WebPPictureImportBGRA + else if (!premul && ct == kBGRA_8888_SkColorType) { importProc = WebPPictureImportBGRA; } +#endif + else { importProc = WebPPictureImportRGBA; + auto info = pixmap.info().makeColorType(kRGBA_8888_SkColorType) + .makeAlphaType(kUnpremul_SkAlphaType); + if (!tmpBm.tryAllocPixels(info) + || !pixmap.readPixels(tmpBm.info(), tmpBm.getPixels(), tmpBm.rowBytes())) { + return false; + } + src = &tmpBm.pixmap(); } - } - if (!importProc(&pic, &rgb[0], rgbStride)) { - return false; + if (!importProc(&pic, reinterpret_cast<const uint8_t*>(src->addr()), src->rowBytes())) { + return false; + } } if (!WebPEncode(&webp_config, &pic)) { diff --git a/chromium/third_party/skia/src/opts/SkChecksum_opts.h b/chromium/third_party/skia/src/opts/SkChecksum_opts.h index 78808476ca7..67c3ba22bad 100644 --- a/chromium/third_party/skia/src/opts/SkChecksum_opts.h +++ b/chromium/third_party/skia/src/opts/SkChecksum_opts.h @@ -191,8 +191,8 @@ namespace SK_OPTS_NS { // Handle last 0-3 bytes. uint32_t k = 0; switch (bytes & 3) { - case 3: k ^= data[2] << 16; - case 2: k ^= data[1] << 8; + case 3: k ^= data[2] << 16; [[fallthrough]]; + case 2: k ^= data[1] << 8; [[fallthrough]]; case 1: k ^= data[0] << 0; k *= 0xcc9e2d51; k = (k << 15) | (k >> 17); diff --git a/chromium/third_party/skia/src/opts/SkOpts_avx.cpp b/chromium/third_party/skia/src/opts/SkOpts_avx.cpp index 80ccf54703a..99d828fd232 100644 --- a/chromium/third_party/skia/src/opts/SkOpts_avx.cpp +++ b/chromium/third_party/skia/src/opts/SkOpts_avx.cpp @@ -8,7 +8,6 @@ #include "src/core/SkOpts.h" #define SK_OPTS_NS avx -#include "src/opts/SkRasterPipeline_opts.h" #include "src/opts/SkUtils_opts.h" namespace SkOpts { @@ -20,17 +19,5 @@ namespace SkOpts { rect_memset16 = SK_OPTS_NS::rect_memset16; rect_memset32 = SK_OPTS_NS::rect_memset32; rect_memset64 = SK_OPTS_NS::rect_memset64; - - #define M(st) stages_highp[SkRasterPipeline::st] = (StageFn)SK_OPTS_NS::st; - SK_RASTER_PIPELINE_STAGES(M) - just_return_highp = (StageFn)SK_OPTS_NS::just_return; - start_pipeline_highp = SK_OPTS_NS::start_pipeline; - #undef M - - #define M(st) stages_lowp[SkRasterPipeline::st] = (StageFn)SK_OPTS_NS::lowp::st; - SK_RASTER_PIPELINE_STAGES(M) - just_return_lowp = (StageFn)SK_OPTS_NS::lowp::just_return; - start_pipeline_lowp = SK_OPTS_NS::lowp::start_pipeline; - #undef M } } diff --git a/chromium/third_party/skia/src/opts/SkOpts_hsw.cpp b/chromium/third_party/skia/src/opts/SkOpts_hsw.cpp index 21f4109f2a4..94c4ed26902 100644 --- a/chromium/third_party/skia/src/opts/SkOpts_hsw.cpp +++ b/chromium/third_party/skia/src/opts/SkOpts_hsw.cpp @@ -12,6 +12,7 @@ #include "src/opts/SkBitmapProcState_opts.h" #include "src/opts/SkBlitRow_opts.h" #include "src/opts/SkRasterPipeline_opts.h" +#include "src/opts/SkSwizzler_opts.h" #include "src/opts/SkUtils_opts.h" #include "src/opts/SkVM_opts.h" @@ -24,6 +25,15 @@ namespace SkOpts { cubic_solver = SK_OPTS_NS::cubic_solver; + RGBA_to_BGRA = SK_OPTS_NS::RGBA_to_BGRA; + RGBA_to_rgbA = SK_OPTS_NS::RGBA_to_rgbA; + RGBA_to_bgrA = SK_OPTS_NS::RGBA_to_bgrA; + gray_to_RGB1 = SK_OPTS_NS::gray_to_RGB1; + grayA_to_RGBA = SK_OPTS_NS::grayA_to_RGBA; + grayA_to_rgbA = SK_OPTS_NS::grayA_to_rgbA; + inverted_CMYK_to_RGB1 = SK_OPTS_NS::inverted_CMYK_to_RGB1; + inverted_CMYK_to_BGR1 = SK_OPTS_NS::inverted_CMYK_to_BGR1; + #define M(st) stages_highp[SkRasterPipeline::st] = (StageFn)SK_OPTS_NS::st; SK_RASTER_PIPELINE_STAGES(M) just_return_highp = (StageFn)SK_OPTS_NS::just_return; diff --git a/chromium/third_party/skia/src/opts/SkOpts_skx.cpp b/chromium/third_party/skia/src/opts/SkOpts_skx.cpp new file mode 100644 index 00000000000..a13743c24b9 --- /dev/null +++ b/chromium/third_party/skia/src/opts/SkOpts_skx.cpp @@ -0,0 +1,27 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "src/core/SkOpts.h" + +#define SK_OPTS_NS skx +#include "src/opts/SkBlitRow_opts.h" +#include "src/opts/SkSwizzler_opts.h" +#include "src/opts/SkVM_opts.h" + +namespace SkOpts { + void Init_skx() { + blit_row_s32a_opaque = SK_OPTS_NS::blit_row_s32a_opaque; + interpret_skvm = SK_OPTS_NS::interpret_skvm; + RGBA_to_BGRA = SK_OPTS_NS::RGBA_to_BGRA; + RGBA_to_rgbA = SK_OPTS_NS::RGBA_to_rgbA; + RGBA_to_bgrA = SK_OPTS_NS::RGBA_to_bgrA; + grayA_to_RGBA = SK_OPTS_NS::grayA_to_RGBA; + grayA_to_rgbA = SK_OPTS_NS::grayA_to_rgbA; + inverted_CMYK_to_RGB1 = SK_OPTS_NS::inverted_CMYK_to_RGB1; + inverted_CMYK_to_BGR1 = SK_OPTS_NS::inverted_CMYK_to_BGR1; + } +} diff --git a/chromium/third_party/skia/src/opts/SkOpts_sse41.cpp b/chromium/third_party/skia/src/opts/SkOpts_sse41.cpp index 8e525968dab..abd47969c4f 100644 --- a/chromium/third_party/skia/src/opts/SkOpts_sse41.cpp +++ b/chromium/third_party/skia/src/opts/SkOpts_sse41.cpp @@ -5,27 +5,4 @@ * found in the LICENSE file. */ -#include "src/core/SkOpts.h" - -#define SK_OPTS_NS sse41 -#include "src/opts/SkBlitRow_opts.h" -#include "src/opts/SkRasterPipeline_opts.h" - -namespace SkOpts { - void Init_sse41() { - blit_row_color32 = sse41::blit_row_color32; - blit_row_s32a_opaque = sse41::blit_row_s32a_opaque; - - #define M(st) stages_highp[SkRasterPipeline::st] = (StageFn)SK_OPTS_NS::st; - SK_RASTER_PIPELINE_STAGES(M) - just_return_highp = (StageFn)SK_OPTS_NS::just_return; - start_pipeline_highp = SK_OPTS_NS::start_pipeline; - #undef M - - #define M(st) stages_lowp[SkRasterPipeline::st] = (StageFn)SK_OPTS_NS::lowp::st; - SK_RASTER_PIPELINE_STAGES(M) - just_return_lowp = (StageFn)SK_OPTS_NS::lowp::just_return; - start_pipeline_lowp = SK_OPTS_NS::lowp::start_pipeline; - #undef M - } -} +// Intentionally empty, to be cleaned up. diff --git a/chromium/third_party/skia/src/opts/SkRasterPipeline_opts.h b/chromium/third_party/skia/src/opts/SkRasterPipeline_opts.h index 7e9558efc71..ad745a6b5e3 100644 --- a/chromium/third_party/skia/src/opts/SkRasterPipeline_opts.h +++ b/chromium/third_party/skia/src/opts/SkRasterPipeline_opts.h @@ -625,13 +625,13 @@ namespace SK_OPTS_NS { F _04, _15, _26, _37; _04 = _15 = _26 = _37 = 0; switch (tail) { - case 0: _37 = _mm256_insertf128_ps(_37, _mm_loadu_ps(ptr+28), 1); - case 7: _26 = _mm256_insertf128_ps(_26, _mm_loadu_ps(ptr+24), 1); - case 6: _15 = _mm256_insertf128_ps(_15, _mm_loadu_ps(ptr+20), 1); - case 5: _04 = _mm256_insertf128_ps(_04, _mm_loadu_ps(ptr+16), 1); - case 4: _37 = _mm256_insertf128_ps(_37, _mm_loadu_ps(ptr+12), 0); - case 3: _26 = _mm256_insertf128_ps(_26, _mm_loadu_ps(ptr+ 8), 0); - case 2: _15 = _mm256_insertf128_ps(_15, _mm_loadu_ps(ptr+ 4), 0); + case 0: _37 = _mm256_insertf128_ps(_37, _mm_loadu_ps(ptr+28), 1); [[fallthrough]]; + case 7: _26 = _mm256_insertf128_ps(_26, _mm_loadu_ps(ptr+24), 1); [[fallthrough]]; + case 6: _15 = _mm256_insertf128_ps(_15, _mm_loadu_ps(ptr+20), 1); [[fallthrough]]; + case 5: _04 = _mm256_insertf128_ps(_04, _mm_loadu_ps(ptr+16), 1); [[fallthrough]]; + case 4: _37 = _mm256_insertf128_ps(_37, _mm_loadu_ps(ptr+12), 0); [[fallthrough]]; + case 3: _26 = _mm256_insertf128_ps(_26, _mm_loadu_ps(ptr+ 8), 0); [[fallthrough]]; + case 2: _15 = _mm256_insertf128_ps(_15, _mm_loadu_ps(ptr+ 4), 0); [[fallthrough]]; case 1: _04 = _mm256_insertf128_ps(_04, _mm_loadu_ps(ptr+ 0), 0); } @@ -978,11 +978,7 @@ SI F approx_exp(F x) { } SI F approx_powf(F x, F y) { -#if defined(SK_LEGACY_APPROX_POWF_SPECIALCASE) - return if_then_else((x == 0) , 0 -#else return if_then_else((x == 0)|(x == 1), x -#endif , approx_pow2(approx_log2(x) * y)); } @@ -1152,11 +1148,11 @@ SI V load(const T* src, size_t tail) { if (__builtin_expect(tail, 0)) { V v{}; // Any inactive lanes are zeroed. switch (tail) { - case 7: v[6] = src[6]; - case 6: v[5] = src[5]; - case 5: v[4] = src[4]; + case 7: v[6] = src[6]; [[fallthrough]]; + case 6: v[5] = src[5]; [[fallthrough]]; + case 5: v[4] = src[4]; [[fallthrough]]; case 4: memcpy(&v, src, 4*sizeof(T)); break; - case 3: v[2] = src[2]; + case 3: v[2] = src[2]; [[fallthrough]]; case 2: memcpy(&v, src, 2*sizeof(T)); break; case 1: memcpy(&v, src, 1*sizeof(T)); break; } @@ -1172,11 +1168,11 @@ SI void store(T* dst, V v, size_t tail) { __builtin_assume(tail < N); if (__builtin_expect(tail, 0)) { switch (tail) { - case 7: dst[6] = v[6]; - case 6: dst[5] = v[5]; - case 5: dst[4] = v[4]; + case 7: dst[6] = v[6]; [[fallthrough]]; + case 6: dst[5] = v[5]; [[fallthrough]]; + case 5: dst[4] = v[4]; [[fallthrough]]; case 4: memcpy(dst, &v, 4*sizeof(T)); break; - case 3: dst[2] = v[2]; + case 3: dst[2] = v[2]; [[fallthrough]]; case 2: memcpy(dst, &v, 2*sizeof(T)); break; case 1: memcpy(dst, &v, 1*sizeof(T)); break; } @@ -1916,45 +1912,6 @@ STAGE(HLGinvish, const skcms_TransferFunction* ctx) { b = fn(b); } -STAGE(from_srgb, Ctx::None) { - auto fn = [](F s) { - U32 sign; - s = strip_sign(s, &sign); - auto lo = s * (1/12.92f); - auto hi = mad(s*s, mad(s, 0.3000f, 0.6975f), 0.0025f); - return apply_sign(if_then_else(s < 0.055f, lo, hi), sign); - }; - r = fn(r); - g = fn(g); - b = fn(b); -} -STAGE(to_srgb, Ctx::None) { - auto fn = [](F l) { - U32 sign; - l = strip_sign(l, &sign); - // We tweak c and d for each instruction set to make sure fn(1) is exactly 1. - #if defined(JUMPER_IS_SSE2) || defined(JUMPER_IS_SSE41) || \ - defined(JUMPER_IS_AVX ) || defined(JUMPER_IS_HSW ) || defined(JUMPER_IS_SKX) - const float c = 1.130048394203f, - d = 0.141357362270f; - #elif defined(JUMPER_IS_NEON) - const float c = 1.129999995232f, - d = 0.141381442547f; - #else - const float c = 1.129999995232f, - d = 0.141377761960f; - #endif - F t = rsqrt(l); - auto lo = l * 12.92f; - auto hi = mad(t, mad(t, -0.0024542345f, 0.013832027f), c) - * rcp(d + t); - return apply_sign(if_then_else(l < 0.00465985f, lo, hi), sign); - }; - r = fn(r); - g = fn(g); - b = fn(b); -} - STAGE(load_a8, const SkRasterPipeline_MemoryCtx* ctx) { auto ptr = ptr_at_xy<const uint8_t>(ctx, dx,dy); @@ -3446,20 +3403,20 @@ SI V load(const T* ptr, size_t tail) { switch (tail & (N-1)) { case 0: memcpy(&v, ptr, sizeof(v)); break; #if defined(JUMPER_IS_HSW) || defined(JUMPER_IS_SKX) - case 15: v[14] = ptr[14]; - case 14: v[13] = ptr[13]; - case 13: v[12] = ptr[12]; + case 15: v[14] = ptr[14]; [[fallthrough]]; + case 14: v[13] = ptr[13]; [[fallthrough]]; + case 13: v[12] = ptr[12]; [[fallthrough]]; case 12: memcpy(&v, ptr, 12*sizeof(T)); break; - case 11: v[10] = ptr[10]; - case 10: v[ 9] = ptr[ 9]; - case 9: v[ 8] = ptr[ 8]; + case 11: v[10] = ptr[10]; [[fallthrough]]; + case 10: v[ 9] = ptr[ 9]; [[fallthrough]]; + case 9: v[ 8] = ptr[ 8]; [[fallthrough]]; case 8: memcpy(&v, ptr, 8*sizeof(T)); break; #endif - case 7: v[ 6] = ptr[ 6]; - case 6: v[ 5] = ptr[ 5]; - case 5: v[ 4] = ptr[ 4]; + case 7: v[ 6] = ptr[ 6]; [[fallthrough]]; + case 6: v[ 5] = ptr[ 5]; [[fallthrough]]; + case 5: v[ 4] = ptr[ 4]; [[fallthrough]]; case 4: memcpy(&v, ptr, 4*sizeof(T)); break; - case 3: v[ 2] = ptr[ 2]; + case 3: v[ 2] = ptr[ 2]; [[fallthrough]]; case 2: memcpy(&v, ptr, 2*sizeof(T)); break; case 1: v[ 0] = ptr[ 0]; } @@ -3470,20 +3427,20 @@ SI void store(T* ptr, size_t tail, V v) { switch (tail & (N-1)) { case 0: memcpy(ptr, &v, sizeof(v)); break; #if defined(JUMPER_IS_HSW) || defined(JUMPER_IS_SKX) - case 15: ptr[14] = v[14]; - case 14: ptr[13] = v[13]; - case 13: ptr[12] = v[12]; + case 15: ptr[14] = v[14]; [[fallthrough]]; + case 14: ptr[13] = v[13]; [[fallthrough]]; + case 13: ptr[12] = v[12]; [[fallthrough]]; case 12: memcpy(ptr, &v, 12*sizeof(T)); break; - case 11: ptr[10] = v[10]; - case 10: ptr[ 9] = v[ 9]; - case 9: ptr[ 8] = v[ 8]; + case 11: ptr[10] = v[10]; [[fallthrough]]; + case 10: ptr[ 9] = v[ 9]; [[fallthrough]]; + case 9: ptr[ 8] = v[ 8]; [[fallthrough]]; case 8: memcpy(ptr, &v, 8*sizeof(T)); break; #endif - case 7: ptr[ 6] = v[ 6]; - case 6: ptr[ 5] = v[ 5]; - case 5: ptr[ 4] = v[ 4]; + case 7: ptr[ 6] = v[ 6]; [[fallthrough]]; + case 6: ptr[ 5] = v[ 5]; [[fallthrough]]; + case 5: ptr[ 4] = v[ 4]; [[fallthrough]]; case 4: memcpy(ptr, &v, 4*sizeof(T)); break; - case 3: ptr[ 2] = v[ 2]; + case 3: ptr[ 2] = v[ 2]; [[fallthrough]]; case 2: memcpy(ptr, &v, 2*sizeof(T)); break; case 1: ptr[ 0] = v[ 0]; } @@ -3556,12 +3513,12 @@ SI void load_8888_(const uint32_t* ptr, size_t tail, U16* r, U16* g, U16* b, U16 uint8x8x4_t rgba; switch (tail & (N-1)) { case 0: rgba = vld4_u8 ((const uint8_t*)(ptr+0) ); break; - case 7: rgba = vld4_lane_u8((const uint8_t*)(ptr+6), rgba, 6); - case 6: rgba = vld4_lane_u8((const uint8_t*)(ptr+5), rgba, 5); - case 5: rgba = vld4_lane_u8((const uint8_t*)(ptr+4), rgba, 4); - case 4: rgba = vld4_lane_u8((const uint8_t*)(ptr+3), rgba, 3); - case 3: rgba = vld4_lane_u8((const uint8_t*)(ptr+2), rgba, 2); - case 2: rgba = vld4_lane_u8((const uint8_t*)(ptr+1), rgba, 1); + case 7: rgba = vld4_lane_u8((const uint8_t*)(ptr+6), rgba, 6); [[fallthrough]]; + case 6: rgba = vld4_lane_u8((const uint8_t*)(ptr+5), rgba, 5); [[fallthrough]]; + case 5: rgba = vld4_lane_u8((const uint8_t*)(ptr+4), rgba, 4); [[fallthrough]]; + case 4: rgba = vld4_lane_u8((const uint8_t*)(ptr+3), rgba, 3); [[fallthrough]]; + case 3: rgba = vld4_lane_u8((const uint8_t*)(ptr+2), rgba, 2); [[fallthrough]]; + case 2: rgba = vld4_lane_u8((const uint8_t*)(ptr+1), rgba, 1); [[fallthrough]]; case 1: rgba = vld4_lane_u8((const uint8_t*)(ptr+0), rgba, 0); } *r = cast<U16>(rgba.val[0]); @@ -3582,12 +3539,12 @@ SI void store_8888_(uint32_t* ptr, size_t tail, U16 r, U16 g, U16 b, U16 a) { }}; switch (tail & (N-1)) { case 0: vst4_u8 ((uint8_t*)(ptr+0), rgba ); break; - case 7: vst4_lane_u8((uint8_t*)(ptr+6), rgba, 6); - case 6: vst4_lane_u8((uint8_t*)(ptr+5), rgba, 5); - case 5: vst4_lane_u8((uint8_t*)(ptr+4), rgba, 4); - case 4: vst4_lane_u8((uint8_t*)(ptr+3), rgba, 3); - case 3: vst4_lane_u8((uint8_t*)(ptr+2), rgba, 2); - case 2: vst4_lane_u8((uint8_t*)(ptr+1), rgba, 1); + case 7: vst4_lane_u8((uint8_t*)(ptr+6), rgba, 6); [[fallthrough]]; + case 6: vst4_lane_u8((uint8_t*)(ptr+5), rgba, 5); [[fallthrough]]; + case 5: vst4_lane_u8((uint8_t*)(ptr+4), rgba, 4); [[fallthrough]]; + case 4: vst4_lane_u8((uint8_t*)(ptr+3), rgba, 3); [[fallthrough]]; + case 3: vst4_lane_u8((uint8_t*)(ptr+2), rgba, 2); [[fallthrough]]; + case 2: vst4_lane_u8((uint8_t*)(ptr+1), rgba, 1); [[fallthrough]]; case 1: vst4_lane_u8((uint8_t*)(ptr+0), rgba, 0); } #else @@ -3712,12 +3669,12 @@ SI void load_88_(const uint16_t* ptr, size_t tail, U16* r, U16* g) { uint8x8x2_t rg; switch (tail & (N-1)) { case 0: rg = vld2_u8 ((const uint8_t*)(ptr+0) ); break; - case 7: rg = vld2_lane_u8((const uint8_t*)(ptr+6), rg, 6); - case 6: rg = vld2_lane_u8((const uint8_t*)(ptr+5), rg, 5); - case 5: rg = vld2_lane_u8((const uint8_t*)(ptr+4), rg, 4); - case 4: rg = vld2_lane_u8((const uint8_t*)(ptr+3), rg, 3); - case 3: rg = vld2_lane_u8((const uint8_t*)(ptr+2), rg, 2); - case 2: rg = vld2_lane_u8((const uint8_t*)(ptr+1), rg, 1); + case 7: rg = vld2_lane_u8((const uint8_t*)(ptr+6), rg, 6); [[fallthrough]]; + case 6: rg = vld2_lane_u8((const uint8_t*)(ptr+5), rg, 5); [[fallthrough]]; + case 5: rg = vld2_lane_u8((const uint8_t*)(ptr+4), rg, 4); [[fallthrough]]; + case 4: rg = vld2_lane_u8((const uint8_t*)(ptr+3), rg, 3); [[fallthrough]]; + case 3: rg = vld2_lane_u8((const uint8_t*)(ptr+2), rg, 2); [[fallthrough]]; + case 2: rg = vld2_lane_u8((const uint8_t*)(ptr+1), rg, 1); [[fallthrough]]; case 1: rg = vld2_lane_u8((const uint8_t*)(ptr+0), rg, 0); } *r = cast<U16>(rg.val[0]); @@ -3735,12 +3692,12 @@ SI void store_88_(uint16_t* ptr, size_t tail, U16 r, U16 g) { }}; switch (tail & (N-1)) { case 0: vst2_u8 ((uint8_t*)(ptr+0), rg ); break; - case 7: vst2_lane_u8((uint8_t*)(ptr+6), rg, 6); - case 6: vst2_lane_u8((uint8_t*)(ptr+5), rg, 5); - case 5: vst2_lane_u8((uint8_t*)(ptr+4), rg, 4); - case 4: vst2_lane_u8((uint8_t*)(ptr+3), rg, 3); - case 3: vst2_lane_u8((uint8_t*)(ptr+2), rg, 2); - case 2: vst2_lane_u8((uint8_t*)(ptr+1), rg, 1); + case 7: vst2_lane_u8((uint8_t*)(ptr+6), rg, 6); [[fallthrough]]; + case 6: vst2_lane_u8((uint8_t*)(ptr+5), rg, 5); [[fallthrough]]; + case 5: vst2_lane_u8((uint8_t*)(ptr+4), rg, 4); [[fallthrough]]; + case 4: vst2_lane_u8((uint8_t*)(ptr+3), rg, 3); [[fallthrough]]; + case 3: vst2_lane_u8((uint8_t*)(ptr+2), rg, 2); [[fallthrough]]; + case 2: vst2_lane_u8((uint8_t*)(ptr+1), rg, 1); [[fallthrough]]; case 1: vst2_lane_u8((uint8_t*)(ptr+0), rg, 0); } #else @@ -4257,8 +4214,6 @@ STAGE_PP(swizzle, void* ctx) { NOT_IMPLEMENTED(unbounded_uniform_color) NOT_IMPLEMENTED(unpremul) NOT_IMPLEMENTED(dither) // TODO - NOT_IMPLEMENTED(from_srgb) - NOT_IMPLEMENTED(to_srgb) NOT_IMPLEMENTED(load_16161616) NOT_IMPLEMENTED(load_16161616_dst) NOT_IMPLEMENTED(store_16161616) diff --git a/chromium/third_party/skia/src/opts/SkSwizzler_opts.h b/chromium/third_party/skia/src/opts/SkSwizzler_opts.h index f7f7c254570..3ef8cc68109 100644 --- a/chromium/third_party/skia/src/opts/SkSwizzler_opts.h +++ b/chromium/third_party/skia/src/opts/SkSwizzler_opts.h @@ -65,41 +65,6 @@ static void RGBA_to_BGRA_portable(uint32_t* dst, const uint32_t* src, int count) } } -static void RGB_to_RGB1_portable(uint32_t dst[], const uint8_t* src, int count) { - for (int i = 0; i < count; i++) { - uint8_t r = src[0], - g = src[1], - b = src[2]; - src += 3; - dst[i] = (uint32_t)0xFF << 24 - | (uint32_t)b << 16 - | (uint32_t)g << 8 - | (uint32_t)r << 0; - } -} - -static void RGB_to_BGR1_portable(uint32_t dst[], const uint8_t* src, int count) { - for (int i = 0; i < count; i++) { - uint8_t r = src[0], - g = src[1], - b = src[2]; - src += 3; - dst[i] = (uint32_t)0xFF << 24 - | (uint32_t)r << 16 - | (uint32_t)g << 8 - | (uint32_t)b << 0; - } -} - -static void gray_to_RGB1_portable(uint32_t dst[], const uint8_t* src, int count) { - for (int i = 0; i < count; i++) { - dst[i] = (uint32_t)0xFF << 24 - | (uint32_t)src[i] << 16 - | (uint32_t)src[i] << 8 - | (uint32_t)src[i] << 0; - } -} - static void grayA_to_RGBA_portable(uint32_t dst[], const uint8_t* src, int count) { for (int i = 0; i < count; i++) { uint8_t g = src[0], @@ -189,8 +154,7 @@ static uint8x8_t scale(uint8x8_t x, uint8x8_t y) { return div255_round(vmull_u8(x, y)); } -template <bool kSwapRB> -static void premul_should_swapRB(uint32_t* dst, const uint32_t* src, int count) { +static void premul_should_swapRB(bool kSwapRB, uint32_t* dst, const uint32_t* src, int count) { while (count >= 8) { // Load 8 pixels. uint8x8x4_t rgba = vld4_u8((const uint8_t*) src); @@ -227,11 +191,11 @@ static void premul_should_swapRB(uint32_t* dst, const uint32_t* src, int count) } /*not static*/ inline void RGBA_to_rgbA(uint32_t* dst, const uint32_t* src, int count) { - premul_should_swapRB<false>(dst, src, count); + premul_should_swapRB(false, dst, src, count); } /*not static*/ inline void RGBA_to_bgrA(uint32_t* dst, const uint32_t* src, int count) { - premul_should_swapRB<true>(dst, src, count); + premul_should_swapRB(true, dst, src, count); } /*not static*/ inline void RGBA_to_BGRA(uint32_t* dst, const uint32_t* src, int count) { @@ -267,109 +231,7 @@ static void premul_should_swapRB(uint32_t* dst, const uint32_t* src, int count) RGBA_to_BGRA_portable(dst, src, count); } -template <bool kSwapRB> -static void insert_alpha_should_swaprb(uint32_t dst[], const uint8_t* src, int count) { - while (count >= 16) { - // Load 16 pixels. - uint8x16x3_t rgb = vld3q_u8(src); - - // Insert an opaque alpha channel and swap if needed. - uint8x16x4_t rgba; - if (kSwapRB) { - rgba.val[0] = rgb.val[2]; - rgba.val[2] = rgb.val[0]; - } else { - rgba.val[0] = rgb.val[0]; - rgba.val[2] = rgb.val[2]; - } - rgba.val[1] = rgb.val[1]; - rgba.val[3] = vdupq_n_u8(0xFF); - - // Store 16 pixels. - vst4q_u8((uint8_t*) dst, rgba); - src += 16*3; - dst += 16; - count -= 16; - } - - if (count >= 8) { - // Load 8 pixels. - uint8x8x3_t rgb = vld3_u8(src); - - // Insert an opaque alpha channel and swap if needed. - uint8x8x4_t rgba; - if (kSwapRB) { - rgba.val[0] = rgb.val[2]; - rgba.val[2] = rgb.val[0]; - } else { - rgba.val[0] = rgb.val[0]; - rgba.val[2] = rgb.val[2]; - } - rgba.val[1] = rgb.val[1]; - rgba.val[3] = vdup_n_u8(0xFF); - - // Store 8 pixels. - vst4_u8((uint8_t*) dst, rgba); - src += 8*3; - dst += 8; - count -= 8; - } - - // Call portable code to finish up the tail of [0,8) pixels. - auto proc = kSwapRB ? RGB_to_BGR1_portable : RGB_to_RGB1_portable; - proc(dst, src, count); -} - -/*not static*/ inline void RGB_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { - insert_alpha_should_swaprb<false>(dst, src, count); -} - -/*not static*/ inline void RGB_to_BGR1(uint32_t dst[], const uint8_t* src, int count) { - insert_alpha_should_swaprb<true>(dst, src, count); -} - -/*not static*/ inline void gray_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { - while (count >= 16) { - // Load 16 pixels. - uint8x16_t gray = vld1q_u8(src); - - // Set each of the color channels. - uint8x16x4_t rgba; - rgba.val[0] = gray; - rgba.val[1] = gray; - rgba.val[2] = gray; - rgba.val[3] = vdupq_n_u8(0xFF); - - // Store 16 pixels. - vst4q_u8((uint8_t*) dst, rgba); - src += 16; - dst += 16; - count -= 16; - } - - if (count >= 8) { - // Load 8 pixels. - uint8x8_t gray = vld1_u8(src); - - // Set each of the color channels. - uint8x8x4_t rgba; - rgba.val[0] = gray; - rgba.val[1] = gray; - rgba.val[2] = gray; - rgba.val[3] = vdup_n_u8(0xFF); - - // Store 8 pixels. - vst4_u8((uint8_t*) dst, rgba); - src += 8; - dst += 8; - count -= 8; - } - - gray_to_RGB1_portable(dst, src, count); -} - -template <bool kPremul> -static void expand_grayA(uint32_t dst[], const uint8_t* src, int count) { +static void expand_grayA(bool kPremul, uint32_t dst[], const uint8_t* src, int count) { while (count >= 16) { // Load 16 pixels. uint8x16x2_t ga = vld2q_u8(src); @@ -423,16 +285,15 @@ static void expand_grayA(uint32_t dst[], const uint8_t* src, int count) { } /*not static*/ inline void grayA_to_RGBA(uint32_t dst[], const uint8_t* src, int count) { - expand_grayA<false>(dst, src, count); + expand_grayA(false, dst, src, count); } /*not static*/ inline void grayA_to_rgbA(uint32_t dst[], const uint8_t* src, int count) { - expand_grayA<true>(dst, src, count); + expand_grayA(true, dst, src, count); } enum Format { kRGB1, kBGR1 }; -template <Format format> -static void inverted_cmyk_to(uint32_t* dst, const uint32_t* src, int count) { +static void inverted_cmyk_to(Format format, uint32_t* dst, const uint32_t* src, int count) { while (count >= 8) { // Load 8 cmyk pixels. uint8x8x4_t pixels = vld4_u8((const uint8_t*) src); @@ -470,11 +331,540 @@ static void inverted_cmyk_to(uint32_t* dst, const uint32_t* src, int count) { } /*not static*/ inline void inverted_CMYK_to_RGB1(uint32_t dst[], const uint32_t* src, int count) { - inverted_cmyk_to<kRGB1>(dst, src, count); + inverted_cmyk_to(kRGB1, dst, src, count); } /*not static*/ inline void inverted_CMYK_to_BGR1(uint32_t dst[], const uint32_t* src, int count) { - inverted_cmyk_to<kBGR1>(dst, src, count); + inverted_cmyk_to(kBGR1, dst, src, count); +} + +#elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SKX +// Scale a byte by another. +// Inputs are stored in 16-bit lanes, but are not larger than 8-bits. +static __m512i scale(__m512i x, __m512i y) { + const __m512i _128 = _mm512_set1_epi16(128); + const __m512i _257 = _mm512_set1_epi16(257); + + // (x+127)/255 == ((x+128)*257)>>16 for 0 <= x <= 255*255. + return _mm512_mulhi_epu16(_mm512_add_epi16(_mm512_mullo_epi16(x, y), _128), _257); +} + +static void premul_should_swapRB(bool kSwapRB, uint32_t* dst, const uint32_t* src, int count) { + + auto premul8 = [=](__m512i* lo, __m512i* hi) { + const __m512i zeros = _mm512_setzero_si512(); + skvx::Vec<64, uint8_t> mask; + if (kSwapRB) { + mask = { 2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15, + 2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15, + 2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15, + 2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15 }; + } else { + mask = { 0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15, + 0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15, + 0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15, + 0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15 }; + } + __m512i planar = skvx::bit_pun<__m512i>(mask); + + // Swizzle the pixels to 8-bit planar. + *lo = _mm512_shuffle_epi8(*lo, planar); + *hi = _mm512_shuffle_epi8(*hi, planar); + __m512i rg = _mm512_unpacklo_epi32(*lo, *hi), + ba = _mm512_unpackhi_epi32(*lo, *hi); + + // Unpack to 16-bit planar. + __m512i r = _mm512_unpacklo_epi8(rg, zeros), + g = _mm512_unpackhi_epi8(rg, zeros), + b = _mm512_unpacklo_epi8(ba, zeros), + a = _mm512_unpackhi_epi8(ba, zeros); + + // Premultiply! + r = scale(r, a); + g = scale(g, a); + b = scale(b, a); + + // Repack into interlaced pixels. + rg = _mm512_or_si512(r, _mm512_slli_epi16(g, 8)); + ba = _mm512_or_si512(b, _mm512_slli_epi16(a, 8)); + *lo = _mm512_unpacklo_epi16(rg, ba); + *hi = _mm512_unpackhi_epi16(rg, ba); + }; + + while (count >= 32) { + __m512i lo = _mm512_loadu_si512((const __m512i*) (src + 0)), + hi = _mm512_loadu_si512((const __m512i*) (src + 16)); + + premul8(&lo, &hi); + + _mm512_storeu_si512((__m512i*) (dst + 0), lo); + _mm512_storeu_si512((__m512i*) (dst + 16), hi); + + src += 32; + dst += 32; + count -= 32; + } + + if (count >= 16) { + __m512i lo = _mm512_loadu_si512((const __m512i*) src), + hi = _mm512_setzero_si512(); + + premul8(&lo, &hi); + + _mm512_storeu_si512((__m512i*) dst, lo); + + src += 16; + dst += 16; + count -= 16; + } + + // Call portable code to finish up the tail of [0,16) pixels. + auto proc = kSwapRB ? RGBA_to_bgrA_portable : RGBA_to_rgbA_portable; + proc(dst, src, count); +} + +/*not static*/ inline void RGBA_to_rgbA(uint32_t* dst, const uint32_t* src, int count) { + premul_should_swapRB(false, dst, src, count); +} + +/*not static*/ inline void RGBA_to_bgrA(uint32_t* dst, const uint32_t* src, int count) { + premul_should_swapRB(true, dst, src, count); +} + +/*not static*/ inline void RGBA_to_BGRA(uint32_t* dst, const uint32_t* src, int count) { + const uint8_t mask[64] = { 2,1,0,3, 6,5,4,7, 10,9,8,11, 14,13,12,15, + 2,1,0,3, 6,5,4,7, 10,9,8,11, 14,13,12,15, + 2,1,0,3, 6,5,4,7, 10,9,8,11, 14,13,12,15, + 2,1,0,3, 6,5,4,7, 10,9,8,11, 14,13,12,15 }; + const __m512i swapRB = _mm512_loadu_si512(mask); + + while (count >= 16) { + __m512i rgba = _mm512_loadu_si512((const __m512i*) src); + __m512i bgra = _mm512_shuffle_epi8(rgba, swapRB); + _mm512_storeu_si512((__m512i*) dst, bgra); + + src += 16; + dst += 16; + count -= 16; + } + + RGBA_to_BGRA_portable(dst, src, count); +} + +// Use SSSE3 impl as AVX2 / AVX-512 impl regresses performance for RGB_to_RGB1 / RGB_to_BGR1. + +// Use AVX2 impl as AVX-512 impl regresses performance for gray_to_RGB1. + +/*not static*/ inline void grayA_to_RGBA(uint32_t dst[], const uint8_t* src, int count) { + while (count >= 32) { + __m512i ga = _mm512_loadu_si512((const __m512i*) src); + + __m512i gg = _mm512_or_si512(_mm512_and_si512(ga, _mm512_set1_epi16(0x00FF)), + _mm512_slli_epi16(ga, 8)); + + __m512i ggga_lo = _mm512_unpacklo_epi16(gg, ga); + __m512i ggga_hi = _mm512_unpackhi_epi16(gg, ga); + + // 1st shuffle for pixel reorder. + // Note. 'p' stands for 'ggga' + // Before 1st shuffle: + // ggga_lo = p0 p1 p2 p3 | p8 p9 p10 p11 | p16 p17 p18 p19 | p24 p25 p26 p27 + // ggga_hi = p4 p5 p6 p7 | p12 p13 p14 p15 | p20 p21 p22 p23 | p28 p29 p30 p31 + // + // After 1st shuffle: + // ggga_lo_shuffle_1 = + // p0 p1 p2 p3 | p8 p9 p10 p11 | p4 p5 p6 p7 | p12 p13 p14 p15 + // ggga_hi_shuffle_1 = + // p16 p17 p18 p19 | p24 p25 p26 p27 | p20 p21 p22 p23 | p28 p29 p30 p31 + __m512i ggga_lo_shuffle_1 = _mm512_shuffle_i32x4(ggga_lo, ggga_hi, 0x44), + ggga_hi_shuffle_1 = _mm512_shuffle_i32x4(ggga_lo, ggga_hi, 0xee); + + // 2nd shuffle for pixel reorder. + // After the 2nd shuffle: + // ggga_lo_shuffle_2 = + // p0 p1 p2 p3 | p4 p5 p6 p7 | p8 p9 p10 p11 | p12 p13 p14 p15 + // ggga_hi_shuffle_2 = + // p16 p17 p18 p19 | p20 p21 p22 p23 | p24 p25 p26 p27 | p28 p29 p30 p31 + __m512i ggga_lo_shuffle_2 = _mm512_shuffle_i32x4(ggga_lo_shuffle_1, + ggga_lo_shuffle_1, 0xd8), + ggga_hi_shuffle_2 = _mm512_shuffle_i32x4(ggga_hi_shuffle_1, + ggga_hi_shuffle_1, 0xd8); + + _mm512_storeu_si512((__m512i*) (dst + 0), ggga_lo_shuffle_2); + _mm512_storeu_si512((__m512i*) (dst + 16), ggga_hi_shuffle_2); + + src += 32*2; + dst += 32; + count -= 32; + } + + grayA_to_RGBA_portable(dst, src, count); +} + +/*not static*/ inline void grayA_to_rgbA(uint32_t dst[], const uint8_t* src, int count) { + while (count >= 32) { + __m512i grayA = _mm512_loadu_si512((const __m512i*) src); + + __m512i g0 = _mm512_and_si512(grayA, _mm512_set1_epi16(0x00FF)); + __m512i a0 = _mm512_srli_epi16(grayA, 8); + + // Premultiply + g0 = scale(g0, a0); + + __m512i gg = _mm512_or_si512(g0, _mm512_slli_epi16(g0, 8)); + __m512i ga = _mm512_or_si512(g0, _mm512_slli_epi16(a0, 8)); + + __m512i ggga_lo = _mm512_unpacklo_epi16(gg, ga); + __m512i ggga_hi = _mm512_unpackhi_epi16(gg, ga); + + // 1st shuffle for pixel reorder, same as grayA_to_RGBA. + __m512i ggga_lo_shuffle_1 = _mm512_shuffle_i32x4(ggga_lo, ggga_hi, 0x44), + ggga_hi_shuffle_1 = _mm512_shuffle_i32x4(ggga_lo, ggga_hi, 0xee); + + // 2nd shuffle for pixel reorder, same as grayA_to_RGBA. + __m512i ggga_lo_shuffle_2 = _mm512_shuffle_i32x4(ggga_lo_shuffle_1, + ggga_lo_shuffle_1, 0xd8), + ggga_hi_shuffle_2 = _mm512_shuffle_i32x4(ggga_hi_shuffle_1, + ggga_hi_shuffle_1, 0xd8); + + _mm512_storeu_si512((__m512i*) (dst + 0), ggga_lo_shuffle_2); + _mm512_storeu_si512((__m512i*) (dst + 16), ggga_hi_shuffle_2); + + src += 32*2; + dst += 32; + count -= 32; + } + + grayA_to_rgbA_portable(dst, src, count); +} + +enum Format { kRGB1, kBGR1 }; +static void inverted_cmyk_to(Format format, uint32_t* dst, const uint32_t* src, int count) { + auto convert8 = [=](__m512i* lo, __m512i* hi) { + const __m512i zeros = _mm512_setzero_si512(); + skvx::Vec<64, uint8_t> mask; + if (kBGR1 == format) { + mask = { 2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15, + 2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15, + 2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15, + 2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15 }; + } else { + mask = { 0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15, + 0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15, + 0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15, + 0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15 }; + } + __m512i planar = skvx::bit_pun<__m512i>(mask); + + // Swizzle the pixels to 8-bit planar. + *lo = _mm512_shuffle_epi8(*lo, planar); + *hi = _mm512_shuffle_epi8(*hi, planar); + __m512i cm = _mm512_unpacklo_epi32(*lo, *hi), + yk = _mm512_unpackhi_epi32(*lo, *hi); + + // Unpack to 16-bit planar. + __m512i c = _mm512_unpacklo_epi8(cm, zeros), + m = _mm512_unpackhi_epi8(cm, zeros), + y = _mm512_unpacklo_epi8(yk, zeros), + k = _mm512_unpackhi_epi8(yk, zeros); + + // Scale to r, g, b. + __m512i r = scale(c, k), + g = scale(m, k), + b = scale(y, k); + + // Repack into interlaced pixels. + __m512i rg = _mm512_or_si512(r, _mm512_slli_epi16(g, 8)), + ba = _mm512_or_si512(b, _mm512_set1_epi16((uint16_t) 0xFF00)); + *lo = _mm512_unpacklo_epi16(rg, ba); + *hi = _mm512_unpackhi_epi16(rg, ba); + }; + + while (count >= 32) { + __m512i lo = _mm512_loadu_si512((const __m512i*) (src + 0)), + hi = _mm512_loadu_si512((const __m512i*) (src + 16)); + + convert8(&lo, &hi); + + _mm512_storeu_si512((__m512i*) (dst + 0), lo); + _mm512_storeu_si512((__m512i*) (dst + 16), hi); + + src += 32; + dst += 32; + count -= 32; + } + + if (count >= 16) { + __m512i lo = _mm512_loadu_si512((const __m512i*) src), + hi = _mm512_setzero_si512(); + + convert8(&lo, &hi); + + _mm512_storeu_si512((__m512i*) dst, lo); + + src += 16; + dst += 16; + count -= 16; + } + + auto proc = (kBGR1 == format) ? inverted_CMYK_to_BGR1_portable : inverted_CMYK_to_RGB1_portable; + proc(dst, src, count); +} + +/*not static*/ inline void inverted_CMYK_to_RGB1(uint32_t dst[], const uint32_t* src, int count) { + inverted_cmyk_to(kRGB1, dst, src, count); +} + +/*not static*/ inline void inverted_CMYK_to_BGR1(uint32_t dst[], const uint32_t* src, int count) { + inverted_cmyk_to(kBGR1, dst, src, count); +} + +#elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2 + +// Scale a byte by another. +// Inputs are stored in 16-bit lanes, but are not larger than 8-bits. +static __m256i scale(__m256i x, __m256i y) { + const __m256i _128 = _mm256_set1_epi16(128); + const __m256i _257 = _mm256_set1_epi16(257); + + // (x+127)/255 == ((x+128)*257)>>16 for 0 <= x <= 255*255. + return _mm256_mulhi_epu16(_mm256_add_epi16(_mm256_mullo_epi16(x, y), _128), _257); +} + +static void premul_should_swapRB(bool kSwapRB, uint32_t* dst, const uint32_t* src, int count) { + + auto premul8 = [=](__m256i* lo, __m256i* hi) { + const __m256i zeros = _mm256_setzero_si256(); + __m256i planar; + if (kSwapRB) { + planar = _mm256_setr_epi8(2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15, + 2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15); + } else { + planar = _mm256_setr_epi8(0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15, + 0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15); + } + + // Swizzle the pixels to 8-bit planar. + *lo = _mm256_shuffle_epi8(*lo, planar); // rrrrgggg bbbbaaaa rrrrgggg bbbbaaaa + *hi = _mm256_shuffle_epi8(*hi, planar); // RRRRGGGG BBBBAAAA RRRRGGGG BBBBAAAA + __m256i rg = _mm256_unpacklo_epi32(*lo, *hi), // rrrrRRRR ggggGGGG rrrrRRRR ggggGGGG + ba = _mm256_unpackhi_epi32(*lo, *hi); // bbbbBBBB aaaaAAAA bbbbBBBB aaaaAAAA + + // Unpack to 16-bit planar. + __m256i r = _mm256_unpacklo_epi8(rg, zeros), // r_r_r_r_ R_R_R_R_ r_r_r_r_ R_R_R_R_ + g = _mm256_unpackhi_epi8(rg, zeros), // g_g_g_g_ G_G_G_G_ g_g_g_g_ G_G_G_G_ + b = _mm256_unpacklo_epi8(ba, zeros), // b_b_b_b_ B_B_B_B_ b_b_b_b_ B_B_B_B_ + a = _mm256_unpackhi_epi8(ba, zeros); // a_a_a_a_ A_A_A_A_ a_a_a_a_ A_A_A_A_ + + // Premultiply! + r = scale(r, a); + g = scale(g, a); + b = scale(b, a); + + // Repack into interlaced pixels. + rg = _mm256_or_si256(r, _mm256_slli_epi16(g, 8)); // rgrgrgrg RGRGRGRG rgrgrgrg RGRGRGRG + ba = _mm256_or_si256(b, _mm256_slli_epi16(a, 8)); // babababa BABABABA babababa BABABABA + *lo = _mm256_unpacklo_epi16(rg, ba); // rgbargba rgbargba rgbargba rgbargba + *hi = _mm256_unpackhi_epi16(rg, ba); // RGBARGBA RGBARGBA RGBARGBA RGBARGBA + }; + + while (count >= 16) { + __m256i lo = _mm256_loadu_si256((const __m256i*) (src + 0)), + hi = _mm256_loadu_si256((const __m256i*) (src + 8)); + + premul8(&lo, &hi); + + _mm256_storeu_si256((__m256i*) (dst + 0), lo); + _mm256_storeu_si256((__m256i*) (dst + 8), hi); + + src += 16; + dst += 16; + count -= 16; + } + + if (count >= 8) { + __m256i lo = _mm256_loadu_si256((const __m256i*) src), + hi = _mm256_setzero_si256(); + + premul8(&lo, &hi); + + _mm256_storeu_si256((__m256i*) dst, lo); + + src += 8; + dst += 8; + count -= 8; + } + + // Call portable code to finish up the tail of [0,8) pixels. + auto proc = kSwapRB ? RGBA_to_bgrA_portable : RGBA_to_rgbA_portable; + proc(dst, src, count); +} + +/*not static*/ inline void RGBA_to_rgbA(uint32_t* dst, const uint32_t* src, int count) { + premul_should_swapRB(false, dst, src, count); +} + +/*not static*/ inline void RGBA_to_bgrA(uint32_t* dst, const uint32_t* src, int count) { + premul_should_swapRB(true, dst, src, count); +} + +/*not static*/ inline void RGBA_to_BGRA(uint32_t* dst, const uint32_t* src, int count) { + const __m256i swapRB = _mm256_setr_epi8(2,1,0,3, 6,5,4,7, 10,9,8,11, 14,13,12,15, + 2,1,0,3, 6,5,4,7, 10,9,8,11, 14,13,12,15); + + while (count >= 8) { + __m256i rgba = _mm256_loadu_si256((const __m256i*) src); + __m256i bgra = _mm256_shuffle_epi8(rgba, swapRB); + _mm256_storeu_si256((__m256i*) dst, bgra); + + src += 8; + dst += 8; + count -= 8; + } + + RGBA_to_BGRA_portable(dst, src, count); +} + +/*not static*/ inline void grayA_to_RGBA(uint32_t dst[], const uint8_t* src, int count) { + while (count >= 16) { + __m256i ga = _mm256_loadu_si256((const __m256i*) src); + + __m256i gg = _mm256_or_si256(_mm256_and_si256(ga, _mm256_set1_epi16(0x00FF)), + _mm256_slli_epi16(ga, 8)); + + __m256i ggga_lo = _mm256_unpacklo_epi16(gg, ga); + __m256i ggga_hi = _mm256_unpackhi_epi16(gg, ga); + + // Shuffle for pixel reorder + // Note. 'p' stands for 'ggga' + // Before shuffle: + // ggga_lo = p0 p1 p2 p3 | p8 p9 p10 p11 + // ggga_hi = p4 p5 p6 p7 | p12 p13 p14 p15 + // + // After shuffle: + // ggga_lo_shuffle = p0 p1 p2 p3 | p4 p5 p6 p7 + // ggga_hi_shuffle = p8 p9 p10 p11 | p12 p13 p14 p15 + __m256i ggga_lo_shuffle = _mm256_permute2x128_si256(ggga_lo, ggga_hi, 0x20), + ggga_hi_shuffle = _mm256_permute2x128_si256(ggga_lo, ggga_hi, 0x31); + + _mm256_storeu_si256((__m256i*) (dst + 0), ggga_lo_shuffle); + _mm256_storeu_si256((__m256i*) (dst + 8), ggga_hi_shuffle); + + src += 16*2; + dst += 16; + count -= 16; + } + + grayA_to_RGBA_portable(dst, src, count); +} + +/*not static*/ inline void grayA_to_rgbA(uint32_t dst[], const uint8_t* src, int count) { + while (count >= 16) { + __m256i grayA = _mm256_loadu_si256((const __m256i*) src); + + __m256i g0 = _mm256_and_si256(grayA, _mm256_set1_epi16(0x00FF)); + __m256i a0 = _mm256_srli_epi16(grayA, 8); + + // Premultiply + g0 = scale(g0, a0); + + __m256i gg = _mm256_or_si256(g0, _mm256_slli_epi16(g0, 8)); + __m256i ga = _mm256_or_si256(g0, _mm256_slli_epi16(a0, 8)); + + __m256i ggga_lo = _mm256_unpacklo_epi16(gg, ga); + __m256i ggga_hi = _mm256_unpackhi_epi16(gg, ga); + + // Shuffle for pixel reorder, similar as grayA_to_RGBA + __m256i ggga_lo_shuffle = _mm256_permute2x128_si256(ggga_lo, ggga_hi, 0x20), + ggga_hi_shuffle = _mm256_permute2x128_si256(ggga_lo, ggga_hi, 0x31); + + _mm256_storeu_si256((__m256i*) (dst + 0), ggga_lo_shuffle); + _mm256_storeu_si256((__m256i*) (dst + 8), ggga_hi_shuffle); + + src += 16*2; + dst += 16; + count -= 16; + } + + grayA_to_rgbA_portable(dst, src, count); +} + +enum Format { kRGB1, kBGR1 }; +static void inverted_cmyk_to(Format format, uint32_t* dst, const uint32_t* src, int count) { + auto convert8 = [=](__m256i* lo, __m256i* hi) { + const __m256i zeros = _mm256_setzero_si256(); + __m256i planar; + if (kBGR1 == format) { + planar = _mm256_setr_epi8(2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15, + 2,6,10,14, 1,5,9,13, 0,4,8,12, 3,7,11,15); + } else { + planar = _mm256_setr_epi8(0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15, + 0,4,8,12, 1,5,9,13, 2,6,10,14, 3,7,11,15); + } + + // Swizzle the pixels to 8-bit planar. + *lo = _mm256_shuffle_epi8(*lo, planar); // ccccmmmm yyyykkkk ccccmmmm yyyykkkk + *hi = _mm256_shuffle_epi8(*hi, planar); // CCCCMMMM YYYYKKKK CCCCMMMM YYYYKKKK + __m256i cm = _mm256_unpacklo_epi32(*lo, *hi), // ccccCCCC mmmmMMMM ccccCCCC mmmmMMMM + yk = _mm256_unpackhi_epi32(*lo, *hi); // yyyyYYYY kkkkKKKK yyyyYYYY kkkkKKKK + + // Unpack to 16-bit planar. + __m256i c = _mm256_unpacklo_epi8(cm, zeros), // c_c_c_c_ C_C_C_C_ c_c_c_c_ C_C_C_C_ + m = _mm256_unpackhi_epi8(cm, zeros), // m_m_m_m_ M_M_M_M_ m_m_m_m_ M_M_M_M_ + y = _mm256_unpacklo_epi8(yk, zeros), // y_y_y_y_ Y_Y_Y_Y_ y_y_y_y_ Y_Y_Y_Y_ + k = _mm256_unpackhi_epi8(yk, zeros); // k_k_k_k_ K_K_K_K_ k_k_k_k_ K_K_K_K_ + + // Scale to r, g, b. + __m256i r = scale(c, k), + g = scale(m, k), + b = scale(y, k); + + // Repack into interlaced pixels: + // rg = rgrgrgrg RGRGRGRG rgrgrgrg RGRGRGRG + // ba = b1b1b1b1 B1B1B1B1 b1b1b1b1 B1B1B1B1 + __m256i rg = _mm256_or_si256(r, _mm256_slli_epi16(g, 8)), + ba = _mm256_or_si256(b, _mm256_set1_epi16((uint16_t) 0xFF00)); + *lo = _mm256_unpacklo_epi16(rg, ba); // rgb1rgb1 rgb1rgb1 rgb1rgb1 rgb1rgb1 + *hi = _mm256_unpackhi_epi16(rg, ba); // RGB1RGB1 RGB1RGB1 RGB1RGB1 RGB1RGB1 + }; + + while (count >= 16) { + __m256i lo = _mm256_loadu_si256((const __m256i*) (src + 0)), + hi = _mm256_loadu_si256((const __m256i*) (src + 8)); + + convert8(&lo, &hi); + + _mm256_storeu_si256((__m256i*) (dst + 0), lo); + _mm256_storeu_si256((__m256i*) (dst + 8), hi); + + src += 16; + dst += 16; + count -= 16; + } + + if (count >= 8) { + __m256i lo = _mm256_loadu_si256((const __m256i*) src), + hi = _mm256_setzero_si256(); + + convert8(&lo, &hi); + + _mm256_storeu_si256((__m256i*) dst, lo); + + src += 8; + dst += 8; + count -= 8; + } + + auto proc = (kBGR1 == format) ? inverted_CMYK_to_BGR1_portable : inverted_CMYK_to_RGB1_portable; + proc(dst, src, count); +} + +/*not static*/ inline void inverted_CMYK_to_RGB1(uint32_t dst[], const uint32_t* src, int count) { + inverted_cmyk_to(kRGB1, dst, src, count); +} + +/*not static*/ inline void inverted_CMYK_to_BGR1(uint32_t dst[], const uint32_t* src, int count) { + inverted_cmyk_to(kBGR1, dst, src, count); } #elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 @@ -489,10 +879,9 @@ static __m128i scale(__m128i x, __m128i y) { return _mm_mulhi_epu16(_mm_add_epi16(_mm_mullo_epi16(x, y), _128), _257); } -template <bool kSwapRB> -static void premul_should_swapRB(uint32_t* dst, const uint32_t* src, int count) { +static void premul_should_swapRB(bool kSwapRB, uint32_t* dst, const uint32_t* src, int count) { - auto premul8 = [](__m128i* lo, __m128i* hi) { + auto premul8 = [=](__m128i* lo, __m128i* hi) { const __m128i zeros = _mm_setzero_si128(); __m128i planar; if (kSwapRB) { @@ -558,11 +947,11 @@ static void premul_should_swapRB(uint32_t* dst, const uint32_t* src, int count) } /*not static*/ inline void RGBA_to_rgbA(uint32_t* dst, const uint32_t* src, int count) { - premul_should_swapRB<false>(dst, src, count); + premul_should_swapRB(false, dst, src, count); } /*not static*/ inline void RGBA_to_bgrA(uint32_t* dst, const uint32_t* src, int count) { - premul_should_swapRB<true>(dst, src, count); + premul_should_swapRB(true, dst, src, count); } /*not static*/ inline void RGBA_to_BGRA(uint32_t* dst, const uint32_t* src, int count) { @@ -581,75 +970,6 @@ static void premul_should_swapRB(uint32_t* dst, const uint32_t* src, int count) RGBA_to_BGRA_portable(dst, src, count); } -template <bool kSwapRB> -static void insert_alpha_should_swaprb(uint32_t dst[], const uint8_t* src, int count) { - const __m128i alphaMask = _mm_set1_epi32(0xFF000000); - __m128i expand; - const uint8_t X = 0xFF; // Used a placeholder. The value of X is irrelevant. - if (kSwapRB) { - expand = _mm_setr_epi8(2,1,0,X, 5,4,3,X, 8,7,6,X, 11,10,9,X); - } else { - expand = _mm_setr_epi8(0,1,2,X, 3,4,5,X, 6,7,8,X, 9,10,11,X); - } - - while (count >= 6) { - // Load a vector. While this actually contains 5 pixels plus an - // extra component, we will discard all but the first four pixels on - // this iteration. - __m128i rgb = _mm_loadu_si128((const __m128i*) src); - - // Expand the first four pixels to RGBX and then mask to RGB(FF). - __m128i rgba = _mm_or_si128(_mm_shuffle_epi8(rgb, expand), alphaMask); - - // Store 4 pixels. - _mm_storeu_si128((__m128i*) dst, rgba); - - src += 4*3; - dst += 4; - count -= 4; - } - - // Call portable code to finish up the tail of [0,4) pixels. - auto proc = kSwapRB ? RGB_to_BGR1_portable : RGB_to_RGB1_portable; - proc(dst, src, count); -} - -/*not static*/ inline void RGB_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { - insert_alpha_should_swaprb<false>(dst, src, count); -} - -/*not static*/ inline void RGB_to_BGR1(uint32_t dst[], const uint8_t* src, int count) { - insert_alpha_should_swaprb<true>(dst, src, count); -} - -/*not static*/ inline void gray_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { - const __m128i alphas = _mm_set1_epi8((uint8_t) 0xFF); - while (count >= 16) { - __m128i grays = _mm_loadu_si128((const __m128i*) src); - - __m128i gg_lo = _mm_unpacklo_epi8(grays, grays); - __m128i gg_hi = _mm_unpackhi_epi8(grays, grays); - __m128i ga_lo = _mm_unpacklo_epi8(grays, alphas); - __m128i ga_hi = _mm_unpackhi_epi8(grays, alphas); - - __m128i ggga0 = _mm_unpacklo_epi16(gg_lo, ga_lo); - __m128i ggga1 = _mm_unpackhi_epi16(gg_lo, ga_lo); - __m128i ggga2 = _mm_unpacklo_epi16(gg_hi, ga_hi); - __m128i ggga3 = _mm_unpackhi_epi16(gg_hi, ga_hi); - - _mm_storeu_si128((__m128i*) (dst + 0), ggga0); - _mm_storeu_si128((__m128i*) (dst + 4), ggga1); - _mm_storeu_si128((__m128i*) (dst + 8), ggga2); - _mm_storeu_si128((__m128i*) (dst + 12), ggga3); - - src += 16; - dst += 16; - count -= 16; - } - - gray_to_RGB1_portable(dst, src, count); -} - /*not static*/ inline void grayA_to_RGBA(uint32_t dst[], const uint8_t* src, int count) { while (count >= 8) { __m128i ga = _mm_loadu_si128((const __m128i*) src); @@ -700,9 +1020,8 @@ static void insert_alpha_should_swaprb(uint32_t dst[], const uint8_t* src, int c } enum Format { kRGB1, kBGR1 }; -template <Format format> -static void inverted_cmyk_to(uint32_t* dst, const uint32_t* src, int count) { - auto convert8 = [](__m128i* lo, __m128i* hi) { +static void inverted_cmyk_to(Format format, uint32_t* dst, const uint32_t* src, int count) { + auto convert8 = [=](__m128i* lo, __m128i* hi) { const __m128i zeros = _mm_setzero_si128(); __m128i planar; if (kBGR1 == format) { @@ -767,11 +1086,11 @@ static void inverted_cmyk_to(uint32_t* dst, const uint32_t* src, int count) { } /*not static*/ inline void inverted_CMYK_to_RGB1(uint32_t dst[], const uint32_t* src, int count) { - inverted_cmyk_to<kRGB1>(dst, src, count); + inverted_cmyk_to(kRGB1, dst, src, count); } /*not static*/ inline void inverted_CMYK_to_BGR1(uint32_t dst[], const uint32_t* src, int count) { - inverted_cmyk_to<kBGR1>(dst, src, count); + inverted_cmyk_to(kBGR1, dst, src, count); } #else @@ -788,18 +1107,6 @@ static void inverted_cmyk_to(uint32_t* dst, const uint32_t* src, int count) { RGBA_to_BGRA_portable(dst, src, count); } -/*not static*/ inline void RGB_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { - RGB_to_RGB1_portable(dst, src, count); -} - -/*not static*/ inline void RGB_to_BGR1(uint32_t dst[], const uint8_t* src, int count) { - RGB_to_BGR1_portable(dst, src, count); -} - -/*not static*/ inline void gray_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { - gray_to_RGB1_portable(dst, src, count); -} - /*not static*/ inline void grayA_to_RGBA(uint32_t dst[], const uint8_t* src, int count) { grayA_to_RGBA_portable(dst, src, count); } @@ -818,6 +1125,265 @@ static void inverted_cmyk_to(uint32_t* dst, const uint32_t* src, int count) { #endif +// Basically as above, but we found no benefit from AVX-512 for gray_to_RGB1. +static void gray_to_RGB1_portable(uint32_t dst[], const uint8_t* src, int count) { + for (int i = 0; i < count; i++) { + dst[i] = (uint32_t)0xFF << 24 + | (uint32_t)src[i] << 16 + | (uint32_t)src[i] << 8 + | (uint32_t)src[i] << 0; + } +} +#if defined(SK_ARM_HAS_NEON) + /*not static*/ inline void gray_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { + while (count >= 16) { + // Load 16 pixels. + uint8x16_t gray = vld1q_u8(src); + + // Set each of the color channels. + uint8x16x4_t rgba; + rgba.val[0] = gray; + rgba.val[1] = gray; + rgba.val[2] = gray; + rgba.val[3] = vdupq_n_u8(0xFF); + + // Store 16 pixels. + vst4q_u8((uint8_t*) dst, rgba); + src += 16; + dst += 16; + count -= 16; + } + if (count >= 8) { + // Load 8 pixels. + uint8x8_t gray = vld1_u8(src); + + // Set each of the color channels. + uint8x8x4_t rgba; + rgba.val[0] = gray; + rgba.val[1] = gray; + rgba.val[2] = gray; + rgba.val[3] = vdup_n_u8(0xFF); + + // Store 8 pixels. + vst4_u8((uint8_t*) dst, rgba); + src += 8; + dst += 8; + count -= 8; + } + gray_to_RGB1_portable(dst, src, count); + } +#elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2 + /*not static*/ inline void gray_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { + const __m256i alphas = _mm256_set1_epi8((uint8_t) 0xFF); + while (count >= 32) { + __m256i grays = _mm256_loadu_si256((const __m256i*) src); + + __m256i gg_lo = _mm256_unpacklo_epi8(grays, grays); + __m256i gg_hi = _mm256_unpackhi_epi8(grays, grays); + __m256i ga_lo = _mm256_unpacklo_epi8(grays, alphas); + __m256i ga_hi = _mm256_unpackhi_epi8(grays, alphas); + + __m256i ggga0 = _mm256_unpacklo_epi16(gg_lo, ga_lo); + __m256i ggga1 = _mm256_unpackhi_epi16(gg_lo, ga_lo); + __m256i ggga2 = _mm256_unpacklo_epi16(gg_hi, ga_hi); + __m256i ggga3 = _mm256_unpackhi_epi16(gg_hi, ga_hi); + + // Shuffle for pixel reorder. + // Note. 'p' stands for 'ggga' + // Before shuffle: + // ggga0 = p0 p1 p2 p3 | p16 p17 p18 p19 + // ggga1 = p4 p5 p6 p7 | p20 p21 p22 p23 + // ggga2 = p8 p9 p10 p11 | p24 p25 p26 p27 + // ggga3 = p12 p13 p14 p15 | p28 p29 p30 p31 + // + // After shuffle: + // ggga0_shuffle = p0 p1 p2 p3 | p4 p5 p6 p7 + // ggga1_shuffle = p8 p9 p10 p11 | p12 p13 p14 p15 + // ggga2_shuffle = p16 p17 p18 p19 | p20 p21 p22 p23 + // ggga3_shuffle = p24 p25 p26 p27 | p28 p29 p30 p31 + __m256i ggga0_shuffle = _mm256_permute2x128_si256(ggga0, ggga1, 0x20), + ggga1_shuffle = _mm256_permute2x128_si256(ggga2, ggga3, 0x20), + ggga2_shuffle = _mm256_permute2x128_si256(ggga0, ggga1, 0x31), + ggga3_shuffle = _mm256_permute2x128_si256(ggga2, ggga3, 0x31); + + _mm256_storeu_si256((__m256i*) (dst + 0), ggga0_shuffle); + _mm256_storeu_si256((__m256i*) (dst + 8), ggga1_shuffle); + _mm256_storeu_si256((__m256i*) (dst + 16), ggga2_shuffle); + _mm256_storeu_si256((__m256i*) (dst + 24), ggga3_shuffle); + + src += 32; + dst += 32; + count -= 32; + } + gray_to_RGB1_portable(dst, src, count); + } +#elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 // TODO: just check >= SSE2? + /*not static*/ inline void gray_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { + const __m128i alphas = _mm_set1_epi8((uint8_t) 0xFF); + while (count >= 16) { + __m128i grays = _mm_loadu_si128((const __m128i*) src); + + __m128i gg_lo = _mm_unpacklo_epi8(grays, grays); + __m128i gg_hi = _mm_unpackhi_epi8(grays, grays); + __m128i ga_lo = _mm_unpacklo_epi8(grays, alphas); + __m128i ga_hi = _mm_unpackhi_epi8(grays, alphas); + + __m128i ggga0 = _mm_unpacklo_epi16(gg_lo, ga_lo); + __m128i ggga1 = _mm_unpackhi_epi16(gg_lo, ga_lo); + __m128i ggga2 = _mm_unpacklo_epi16(gg_hi, ga_hi); + __m128i ggga3 = _mm_unpackhi_epi16(gg_hi, ga_hi); + + _mm_storeu_si128((__m128i*) (dst + 0), ggga0); + _mm_storeu_si128((__m128i*) (dst + 4), ggga1); + _mm_storeu_si128((__m128i*) (dst + 8), ggga2); + _mm_storeu_si128((__m128i*) (dst + 12), ggga3); + + src += 16; + dst += 16; + count -= 16; + } + gray_to_RGB1_portable(dst, src, count); + } +#else + /*not static*/ inline void gray_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { + gray_to_RGB1_portable(dst, src, count); + } +#endif + +// Again as above, this time not even finding benefit from AVX2 for RGB_to_{RGB,BGR}1. +static void RGB_to_RGB1_portable(uint32_t dst[], const uint8_t* src, int count) { + for (int i = 0; i < count; i++) { + uint8_t r = src[0], + g = src[1], + b = src[2]; + src += 3; + dst[i] = (uint32_t)0xFF << 24 + | (uint32_t)b << 16 + | (uint32_t)g << 8 + | (uint32_t)r << 0; + } +} +static void RGB_to_BGR1_portable(uint32_t dst[], const uint8_t* src, int count) { + for (int i = 0; i < count; i++) { + uint8_t r = src[0], + g = src[1], + b = src[2]; + src += 3; + dst[i] = (uint32_t)0xFF << 24 + | (uint32_t)r << 16 + | (uint32_t)g << 8 + | (uint32_t)b << 0; + } +} +#if defined(SK_ARM_HAS_NEON) + static void insert_alpha_should_swaprb(bool kSwapRB, + uint32_t dst[], const uint8_t* src, int count) { + while (count >= 16) { + // Load 16 pixels. + uint8x16x3_t rgb = vld3q_u8(src); + + // Insert an opaque alpha channel and swap if needed. + uint8x16x4_t rgba; + if (kSwapRB) { + rgba.val[0] = rgb.val[2]; + rgba.val[2] = rgb.val[0]; + } else { + rgba.val[0] = rgb.val[0]; + rgba.val[2] = rgb.val[2]; + } + rgba.val[1] = rgb.val[1]; + rgba.val[3] = vdupq_n_u8(0xFF); + + // Store 16 pixels. + vst4q_u8((uint8_t*) dst, rgba); + src += 16*3; + dst += 16; + count -= 16; + } + + if (count >= 8) { + // Load 8 pixels. + uint8x8x3_t rgb = vld3_u8(src); + + // Insert an opaque alpha channel and swap if needed. + uint8x8x4_t rgba; + if (kSwapRB) { + rgba.val[0] = rgb.val[2]; + rgba.val[2] = rgb.val[0]; + } else { + rgba.val[0] = rgb.val[0]; + rgba.val[2] = rgb.val[2]; + } + rgba.val[1] = rgb.val[1]; + rgba.val[3] = vdup_n_u8(0xFF); + + // Store 8 pixels. + vst4_u8((uint8_t*) dst, rgba); + src += 8*3; + dst += 8; + count -= 8; + } + + // Call portable code to finish up the tail of [0,8) pixels. + auto proc = kSwapRB ? RGB_to_BGR1_portable : RGB_to_RGB1_portable; + proc(dst, src, count); + } + + /*not static*/ inline void RGB_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { + insert_alpha_should_swaprb(false, dst, src, count); + } + /*not static*/ inline void RGB_to_BGR1(uint32_t dst[], const uint8_t* src, int count) { + insert_alpha_should_swaprb(true, dst, src, count); + } +#elif SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3 + static void insert_alpha_should_swaprb(bool kSwapRB, + uint32_t dst[], const uint8_t* src, int count) { + const __m128i alphaMask = _mm_set1_epi32(0xFF000000); + __m128i expand; + const uint8_t X = 0xFF; // Used a placeholder. The value of X is irrelevant. + if (kSwapRB) { + expand = _mm_setr_epi8(2,1,0,X, 5,4,3,X, 8,7,6,X, 11,10,9,X); + } else { + expand = _mm_setr_epi8(0,1,2,X, 3,4,5,X, 6,7,8,X, 9,10,11,X); + } + + while (count >= 6) { + // Load a vector. While this actually contains 5 pixels plus an + // extra component, we will discard all but the first four pixels on + // this iteration. + __m128i rgb = _mm_loadu_si128((const __m128i*) src); + + // Expand the first four pixels to RGBX and then mask to RGB(FF). + __m128i rgba = _mm_or_si128(_mm_shuffle_epi8(rgb, expand), alphaMask); + + // Store 4 pixels. + _mm_storeu_si128((__m128i*) dst, rgba); + + src += 4*3; + dst += 4; + count -= 4; + } + + // Call portable code to finish up the tail of [0,4) pixels. + auto proc = kSwapRB ? RGB_to_BGR1_portable : RGB_to_RGB1_portable; + proc(dst, src, count); + } + + /*not static*/ inline void RGB_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { + insert_alpha_should_swaprb(false, dst, src, count); + } + /*not static*/ inline void RGB_to_BGR1(uint32_t dst[], const uint8_t* src, int count) { + insert_alpha_should_swaprb(true, dst, src, count); + } +#else + /*not static*/ inline void RGB_to_RGB1(uint32_t dst[], const uint8_t* src, int count) { + RGB_to_RGB1_portable(dst, src, count); + } + /*not static*/ inline void RGB_to_BGR1(uint32_t dst[], const uint8_t* src, int count) { + RGB_to_BGR1_portable(dst, src, count); + } +#endif + } #endif // SkSwizzler_opts_DEFINED diff --git a/chromium/third_party/skia/src/opts/SkVM_opts.h b/chromium/third_party/skia/src/opts/SkVM_opts.h index 2a953b76eb0..a4a719b8da1 100644 --- a/chromium/third_party/skia/src/opts/SkVM_opts.h +++ b/chromium/third_party/skia/src/opts/SkVM_opts.h @@ -229,6 +229,7 @@ namespace SK_OPTS_NS { CASE(Op::pack): r(d).u32 = r(x).u32 | (r(y).u32 << immz); break; + CASE(Op::ceil): r(d).f32 = skvx::ceil(r(x).f32) ; break; CASE(Op::floor): r(d).f32 = skvx::floor(r(x).f32) ; break; CASE(Op::to_f32): r(d).f32 = skvx::cast<float>( r(x).i32 ); break; CASE(Op::trunc): r(d).i32 = skvx::cast<int> ( r(x).f32 ); break; diff --git a/chromium/third_party/skia/src/pathops/SkPathOpsCubic.cpp b/chromium/third_party/skia/src/pathops/SkPathOpsCubic.cpp index ebf195d7b0a..1275fababd0 100644 --- a/chromium/third_party/skia/src/pathops/SkPathOpsCubic.cpp +++ b/chromium/third_party/skia/src/pathops/SkPathOpsCubic.cpp @@ -257,7 +257,7 @@ int SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t) { return (int) (t[0] > 0 && t[0] < 1); } } - // fall through if no t value found + [[fallthrough]]; // fall through if no t value found case SkCubicType::kSerpentine: case SkCubicType::kLocalCusp: case SkCubicType::kCuspAtInfinity: { @@ -313,9 +313,10 @@ int SkDCubic::ComplexBreak(const SkPoint pointsPtr[4], SkScalar* t) { } return resultCount; } + break; } default: - ; + break; } return 0; } diff --git a/chromium/third_party/skia/src/pdf/SkPDFDevice.cpp b/chromium/third_party/skia/src/pdf/SkPDFDevice.cpp index c06bb27299e..b31ec0588b4 100644 --- a/chromium/third_party/skia/src/pdf/SkPDFDevice.cpp +++ b/chromium/third_party/skia/src/pdf/SkPDFDevice.cpp @@ -75,7 +75,7 @@ public: : fOut(out) , fMarkId(-1) { if (nodeId) { - fMarkId = document->getMarkIdForNodeId(nodeId); + fMarkId = document->createMarkIdForNodeId(nodeId); } if (fMarkId != -1) { @@ -740,7 +740,7 @@ struct PositionedGlyph { static SkRect get_glyph_bounds_device_space(const SkGlyph* glyph, SkScalar xScale, SkScalar yScale, SkPoint xy, const SkMatrix& ctm) { - SkRect glyphBounds = SkMatrix::MakeScale(xScale, yScale).mapRect(glyph->rect()); + SkRect glyphBounds = SkMatrix::Scale(xScale, yScale).mapRect(glyph->rect()); glyphBounds.offset(xy); ctm.mapRect(&glyphBounds); // now in dev space. return glyphBounds; @@ -1000,7 +1000,7 @@ void SkPDFDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& return; } - SkMatrix matrix = SkMatrix::MakeTrans(SkIntToScalar(x), SkIntToScalar(y)); + SkMatrix matrix = SkMatrix::Translate(SkIntToScalar(x), SkIntToScalar(y)); ScopedContentEntry content(this, &this->cs(), matrix, paint); if (!content) { return; @@ -1658,7 +1658,7 @@ void SkPDFDevice::internalDrawImageRect(SkKeyedImage imageSubset, canvas->setMatrix(offsetMatrix); canvas->drawImage(imageSubset.image(), 0, 0); // Make sure the final bits are in the bitmap. - surface->flush(); + surface->flushAndSubmit(); // In the new space, we use the identity matrix translated // and scaled to reflect DPI. @@ -1722,8 +1722,7 @@ void SkPDFDevice::internalDrawImageRect(SkKeyedImage imageSubset, #include "include/core/SkImageFilter.h" #include "src/core/SkSpecialImage.h" -void SkPDFDevice::drawSpecial(SkSpecialImage* srcImg, int x, int y, const SkPaint& paint, - SkImage* clipImage, const SkMatrix& clipMatrix) { +void SkPDFDevice::drawSpecial(SkSpecialImage* srcImg, int x, int y, const SkPaint& paint) { if (this->hasEmptyClip()) { return; } diff --git a/chromium/third_party/skia/src/pdf/SkPDFDevice.h b/chromium/third_party/skia/src/pdf/SkPDFDevice.h index c0c2d7419f3..cee58904b7a 100644 --- a/chromium/third_party/skia/src/pdf/SkPDFDevice.h +++ b/chromium/third_party/skia/src/pdf/SkPDFDevice.h @@ -111,8 +111,7 @@ protected: void drawAnnotation(const SkRect&, const char key[], SkData* value) override; - void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&, - SkImage*, const SkMatrix&) override; + void drawSpecial(SkSpecialImage*, int x, int y, const SkPaint&) override; sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override; sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override; SkImageFilterCache* getImageFilterCache() override; diff --git a/chromium/third_party/skia/src/pdf/SkPDFDocument.cpp b/chromium/third_party/skia/src/pdf/SkPDFDocument.cpp index f13ec2dc330..653fa221703 100644 --- a/chromium/third_party/skia/src/pdf/SkPDFDocument.cpp +++ b/chromium/third_party/skia/src/pdf/SkPDFDocument.cpp @@ -334,10 +334,17 @@ std::unique_ptr<SkPDFArray> SkPDFDocument::getAnnotations() { SkDEBUGFAIL("Unknown link type."); } + if (link->fNodeId) { + int structParentKey = createStructParentKeyForNodeId(link->fNodeId); + if (structParentKey != -1) { + annotation.insertInt("StructParent", structParentKey); + } + } + SkPDFIndirectReference annotationRef = emit(annotation); array->appendRef(annotationRef); if (link->fNodeId) { - fTagTree.addNodeAnnotation(link->fNodeId, annotationRef); + fTagTree.addNodeAnnotation(link->fNodeId, annotationRef, SkToUInt(this->currentPageIndex())); } } return array; @@ -519,8 +526,12 @@ const SkMatrix& SkPDFDocument::currentPageTransform() const { return fPageDevice->initialTransform(); } -int SkPDFDocument::getMarkIdForNodeId(int nodeId) { - return fTagTree.getMarkIdForNodeId(nodeId, SkToUInt(this->currentPageIndex())); +int SkPDFDocument::createMarkIdForNodeId(int nodeId) { + return fTagTree.createMarkIdForNodeId(nodeId, SkToUInt(this->currentPageIndex())); +} + +int SkPDFDocument::createStructParentKeyForNodeId(int nodeId) { + return fTagTree.createStructParentKeyForNodeId(nodeId, SkToUInt(this->currentPageIndex())); } static std::vector<const SkPDFFont*> get_fonts(const SkPDFDocument& canon) { diff --git a/chromium/third_party/skia/src/pdf/SkPDFDocumentPriv.h b/chromium/third_party/skia/src/pdf/SkPDFDocumentPriv.h index 523eeb32777..6d9220d0fd5 100644 --- a/chromium/third_party/skia/src/pdf/SkPDFDocumentPriv.h +++ b/chromium/third_party/skia/src/pdf/SkPDFDocumentPriv.h @@ -116,8 +116,14 @@ public: SkPDFIndirectReference currentPage() const { return SkASSERT(!fPageRefs.empty()), fPageRefs.back(); } - // Returns -1 if no mark ID. - int getMarkIdForNodeId(int nodeId); + // Used to allow marked content to refer to its corresponding structure + // tree node, via a page entry in the parent tree. Returns -1 if no + // mark ID. + int createMarkIdForNodeId(int nodeId); + // Used to allow annotations to refer to their corresponding structure + // tree node, via the struct parent tree. Returns -1 if no struct parent + // key. + int createStructParentKeyForNodeId(int nodeId); std::unique_ptr<SkPDFArray> getAnnotations(); diff --git a/chromium/third_party/skia/src/pdf/SkPDFTag.cpp b/chromium/third_party/skia/src/pdf/SkPDFTag.cpp index 90bafbb0e2a..44919de7089 100644 --- a/chromium/third_party/skia/src/pdf/SkPDFTag.cpp +++ b/chromium/third_party/skia/src/pdf/SkPDFTag.cpp @@ -66,6 +66,56 @@ static const char* tag_name_from_type(SkPDF::DocumentStructureType type) { SK_ABORT("bad tag"); } +// The struct parent tree consists of one entry per page, followed by +// entries for individual struct tree nodes corresponding to +// annotations. Each entry is a key/value pair with an integer key +// and an indirect reference key. +// +// The page entries get consecutive keys starting at 0. Since we don't +// know the total number of pages in the document at the time we start +// processing annotations, start the key for annotations with a large +// number, which effectively becomes the maximum number of pages in a +// PDF we can handle. +const int kFirstAnnotationStructParentKey = 100000; + +struct SkPDFTagNode { + // Structure element nodes need a unique alphanumeric ID, + // and we need to be able to output them sorted in lexicographic + // order. This helper function takes one of our node IDs and + // builds an ID string that zero-pads the digits so that lexicographic + // order matches numeric order. + static SkString nodeIdToString(int nodeId) { + SkString idString; + idString.printf("node%08d", nodeId); + return idString; + } + + SkPDFTagNode* fChildren = nullptr; + size_t fChildCount = 0; + struct MarkedContentInfo { + unsigned fPageIndex; + int fMarkId; + }; + SkTArray<MarkedContentInfo> fMarkedContent; + int fNodeId; + SkPDF::DocumentStructureType fType; + SkString fTypeString; + SkString fAlt; + SkString fLang; + SkPDFIndirectReference fRef; + enum State { + kUnknown, + kYes, + kNo, + } fCanDiscard = kUnknown; + std::unique_ptr<SkPDFArray> fAttributes; + struct AnnotationInfo { + unsigned fPageIndex; + SkPDFIndirectReference fAnnotationRef; + }; + std::vector<AnnotationInfo> fAnnotations; +}; + SkPDF::AttributeList::AttributeList() = default; SkPDF::AttributeList::~AttributeList() = default; @@ -90,7 +140,7 @@ void SkPDF::AttributeList::appendFloat( fAttrs->appendObject(std::move(attrDict)); } -void SkPDF::AttributeList::appendString( +void SkPDF::AttributeList::appendName( const char* owner, const char* name, const char* value) { if (!fAttrs) fAttrs = SkPDFMakeArray(); @@ -100,6 +150,16 @@ void SkPDF::AttributeList::appendString( fAttrs->appendObject(std::move(attrDict)); } +void SkPDF::AttributeList::appendString( + const char* owner, const char* name, const char* value) { + if (!fAttrs) + fAttrs = SkPDFMakeArray(); + std::unique_ptr<SkPDFDict> attrDict = SkPDFMakeDict(); + attrDict->insertName("O", owner); + attrDict->insertString(name, value); + fAttrs->appendObject(std::move(attrDict)); +} + void SkPDF::AttributeList::appendFloatArray( const char* owner, const char* name, const std::vector<float>& value) { if (!fAttrs) @@ -114,45 +174,41 @@ void SkPDF::AttributeList::appendFloatArray( fAttrs->appendObject(std::move(attrDict)); } +// Deprecated. void SkPDF::AttributeList::appendStringArray( + const char* owner, + const char* name, + const std::vector<SkString>& values) { + if (!fAttrs) + fAttrs = SkPDFMakeArray(); + std::unique_ptr<SkPDFDict> attrDict = SkPDFMakeDict(); + attrDict->insertName("O", owner); + std::unique_ptr<SkPDFArray> pdfArray = SkPDFMakeArray(); + for (SkString element : values) { + pdfArray->appendString(element); + } + attrDict->insertObject(name, std::move(pdfArray)); + fAttrs->appendObject(std::move(attrDict)); +} + + +void SkPDF::AttributeList::appendNodeIdArray( const char* owner, const char* name, - const std::vector<SkString>& value) { + const std::vector<int>& nodeIds) { if (!fAttrs) fAttrs = SkPDFMakeArray(); std::unique_ptr<SkPDFDict> attrDict = SkPDFMakeDict(); attrDict->insertName("O", owner); std::unique_ptr<SkPDFArray> pdfArray = SkPDFMakeArray(); - for (SkString element : value) { - pdfArray->appendName(element); + for (int nodeId : nodeIds) { + SkString idString = SkPDFTagNode::nodeIdToString(nodeId); + pdfArray->appendString(idString); } attrDict->insertObject(name, std::move(pdfArray)); fAttrs->appendObject(std::move(attrDict)); } -struct SkPDFTagNode { - SkPDFTagNode* fChildren = nullptr; - size_t fChildCount = 0; - struct MarkedContentInfo { - unsigned fPageIndex; - int fMarkId; - }; - SkTArray<MarkedContentInfo> fMarkedContent; - int fNodeId; - SkPDF::DocumentStructureType fType; - SkString fTypeString; - SkString fAlt; - SkString fLang; - SkPDFIndirectReference fRef; - enum State { - kUnknown, - kYes, - kNo, - } fCanDiscard = kUnknown; - std::unique_ptr<SkPDFArray> fAttributes; - std::vector<SkPDFIndirectReference> fAnnotations; -}; - SkPDFTagTree::SkPDFTagTree() : fArena(4 * sizeof(SkPDFTagNode)) {} SkPDFTagTree::~SkPDFTagTree() = default; @@ -173,23 +229,12 @@ void SkPDFTagTree::Copy(SkPDF::StructureElementNode& node, dst->fAlt = node.fAlt; dst->fLang = node.fLang; - // Temporarily support both raw fChildren and fChildVector. - if (node.fChildren) { - size_t childCount = node.fChildCount; - SkPDFTagNode* children = arena->makeArray<SkPDFTagNode>(childCount); - dst->fChildCount = childCount; - dst->fChildren = children; - for (size_t i = 0; i < childCount; ++i) { - Copy(node.fChildren[i], &children[i], arena, nodeMap); - } - } else { - size_t childCount = node.fChildVector.size(); - SkPDFTagNode* children = arena->makeArray<SkPDFTagNode>(childCount); - dst->fChildCount = childCount; - dst->fChildren = children; - for (size_t i = 0; i < childCount; ++i) { - Copy(*node.fChildVector[i], &children[i], arena, nodeMap); - } + size_t childCount = node.fChildVector.size(); + SkPDFTagNode* children = arena->makeArray<SkPDFTagNode>(childCount); + dst->fChildCount = childCount; + dst->fChildren = children; + for (size_t i = 0; i < childCount; ++i) { + Copy(*node.fChildVector[i], &children[i], arena, nodeMap); } dst->fAttributes = std::move(node.fAttributes.fAttrs); @@ -209,7 +254,7 @@ void SkPDFTagTree::reset() { fRoot = nullptr; } -int SkPDFTagTree::getMarkIdForNodeId(int nodeId, unsigned pageIndex) { +int SkPDFTagTree::createMarkIdForNodeId(int nodeId, unsigned pageIndex) { if (!fRoot) { return -1; } @@ -229,6 +274,25 @@ int SkPDFTagTree::getMarkIdForNodeId(int nodeId, unsigned pageIndex) { return markId; } +int SkPDFTagTree::createStructParentKeyForNodeId(int nodeId, unsigned pageIndex) { + if (!fRoot) { + return -1; + } + SkPDFTagNode** tagPtr = fNodeMap.find(nodeId); + if (!tagPtr) { + return -1; + } + SkPDFTagNode* tag = *tagPtr; + SkASSERT(tag); + + tag->fCanDiscard = SkPDFTagNode::kNo; + + int nextStructParentKey = kFirstAnnotationStructParentKey + + static_cast<int>(fParentTreeAnnotationNodeIds.size()); + fParentTreeAnnotationNodeIds.push_back(nodeId); + return nextStructParentKey; +} + static bool can_discard(SkPDFTagNode* node) { if (node->fCanDiscard == SkPDFTagNode::kYes) { return true; @@ -250,10 +314,9 @@ static bool can_discard(SkPDFTagNode* node) { return true; } - -SkPDFIndirectReference prepare_tag_tree_to_emit(SkPDFIndirectReference parent, - SkPDFTagNode* node, - SkPDFDocument* doc) { +SkPDFIndirectReference SkPDFTagTree::PrepareTagTreeToEmit(SkPDFIndirectReference parent, + SkPDFTagNode* node, + SkPDFDocument* doc) { SkPDFIndirectReference ref = doc->reserveRef(); std::unique_ptr<SkPDFArray> kids = SkPDFMakeArray(); SkPDFTagNode* children = node->fChildren; @@ -261,7 +324,7 @@ SkPDFIndirectReference prepare_tag_tree_to_emit(SkPDFIndirectReference parent, for (size_t i = 0; i < childCount; ++i) { SkPDFTagNode* child = &children[i]; if (!(can_discard(child))) { - kids->appendRef(prepare_tag_tree_to_emit(ref, child, doc)); + kids->appendRef(PrepareTagTreeToEmit(ref, child, doc)); } } for (const SkPDFTagNode::MarkedContentInfo& info : node->fMarkedContent) { @@ -270,9 +333,10 @@ SkPDFIndirectReference prepare_tag_tree_to_emit(SkPDFIndirectReference parent, mcr->insertInt("MCID", info.fMarkId); kids->appendObject(std::move(mcr)); } - for (SkPDFIndirectReference annotationRef : node->fAnnotations) { + for (const SkPDFTagNode::AnnotationInfo& annotationInfo : node->fAnnotations) { std::unique_ptr<SkPDFDict> annotationDict = SkPDFMakeDict("OBJR"); - annotationDict->insertRef("Obj", annotationRef); + annotationDict->insertRef("Obj", annotationInfo.fAnnotationRef); + annotationDict->insertRef("Pg", doc->getPage(annotationInfo.fPageIndex)); kids->appendObject(std::move(annotationDict)); } node->fRef = ref; @@ -290,17 +354,22 @@ SkPDFIndirectReference prepare_tag_tree_to_emit(SkPDFIndirectReference parent, } dict.insertRef("P", parent); dict.insertObject("K", std::move(kids)); - SkString idString; - idString.printf("%d", node->fNodeId); - dict.insertName("ID", idString.c_str()); if (node->fAttributes) { dict.insertObject("A", std::move(node->fAttributes)); } + // Each node has a unique ID that also needs to be referenced + // in a separate IDTree node, along with the lowest and highest + // unique ID string. + SkString idString = SkPDFTagNode::nodeIdToString(node->fNodeId); + dict.insertString("ID", idString.c_str()); + IDTreeEntry idTreeEntry = {node->fNodeId, ref}; + fIdTreeEntries.push_back(idTreeEntry); + return doc->emit(dict, ref); } -void SkPDFTagTree::addNodeAnnotation(int nodeId, SkPDFIndirectReference annotationRef) { +void SkPDFTagTree::addNodeAnnotation(int nodeId, SkPDFIndirectReference annotationRef, unsigned pageIndex) { if (!fRoot) { return; } @@ -310,9 +379,10 @@ void SkPDFTagTree::addNodeAnnotation(int nodeId, SkPDFIndirectReference annotati } SkPDFTagNode* tag = *tagPtr; SkASSERT(tag); - tag->fAnnotations.push_back(annotationRef); -} + SkPDFTagNode::AnnotationInfo annotationInfo = {pageIndex, annotationRef}; + tag->fAnnotations.push_back(annotationInfo); +} SkPDFIndirectReference SkPDFTagTree::makeStructTreeRoot(SkPDFDocument* doc) { if (!fRoot) { @@ -327,14 +397,18 @@ SkPDFIndirectReference SkPDFTagTree::makeStructTreeRoot(SkPDFDocument* doc) { // Build the StructTreeRoot. SkPDFDict structTreeRoot("StructTreeRoot"); - structTreeRoot.insertRef("K", prepare_tag_tree_to_emit(ref, fRoot, doc)); + structTreeRoot.insertRef("K", PrepareTagTreeToEmit(ref, fRoot, doc)); structTreeRoot.insertInt("ParentTreeNextKey", SkToInt(pageCount)); - // Build the parent tree, which is a mapping from the marked - // content IDs on each page to their corressponding tags. + // Build the parent tree, which consists of two things: + // (1) For each page, a mapping from the marked content IDs on + // each page to their corresponding tags + // (2) For each annotation, an indirect reference to that + // annotation's struct tree element. SkPDFDict parentTree("ParentTree"); auto parentTreeNums = SkPDFMakeArray(); + // First, one entry per page. SkASSERT(fMarksPerPage.size() <= pageCount); for (size_t j = 0; j < fMarksPerPage.size(); ++j) { const SkTArray<SkPDFTagNode*>& pageMarks = fMarksPerPage[j]; @@ -346,7 +420,54 @@ SkPDFIndirectReference SkPDFTagTree::makeStructTreeRoot(SkPDFDocument* doc) { parentTreeNums->appendInt(j); parentTreeNums->appendRef(doc->emit(markToTagArray)); } + + // Then, one entry per annotation. + for (size_t j = 0; j < fParentTreeAnnotationNodeIds.size(); ++j) { + int nodeId = fParentTreeAnnotationNodeIds[j]; + int structParentKey = kFirstAnnotationStructParentKey + static_cast<int>(j); + + SkPDFTagNode** tagPtr = fNodeMap.find(nodeId); + if (!tagPtr) { + continue; + } + SkPDFTagNode* tag = *tagPtr; + parentTreeNums->appendInt(structParentKey); + parentTreeNums->appendRef(tag->fRef); + } + parentTree.insertObject("Nums", std::move(parentTreeNums)); structTreeRoot.insertRef("ParentTree", doc->emit(parentTree)); + + // Build the IDTree, a mapping from every unique ID string to + // a reference to its corresponding structure element node. + if (!fIdTreeEntries.empty()) { + std::sort(fIdTreeEntries.begin(), fIdTreeEntries.end(), + [](const IDTreeEntry& a, const IDTreeEntry& b) { + return a.nodeId < b.nodeId; + }); + + SkPDFDict idTree; + SkPDFDict idTreeLeaf; + auto limits = SkPDFMakeArray(); + SkString lowestNodeIdString = SkPDFTagNode::nodeIdToString( + fIdTreeEntries.begin()->nodeId); + limits->appendString(lowestNodeIdString); + SkString highestNodeIdString = SkPDFTagNode::nodeIdToString( + fIdTreeEntries.rbegin()->nodeId); + limits->appendString(highestNodeIdString); + idTreeLeaf.insertObject("Limits", std::move(limits)); + auto names = SkPDFMakeArray(); + for (const IDTreeEntry& entry : fIdTreeEntries) { + SkString idString = SkPDFTagNode::nodeIdToString(entry.nodeId); + names->appendString(idString); + names->appendRef(entry.ref); + } + idTreeLeaf.insertObject("Names", std::move(names)); + auto idTreeKids = SkPDFMakeArray(); + idTreeKids->appendRef(doc->emit(idTreeLeaf)); + idTree.insertObject("Kids", std::move(idTreeKids)); + structTreeRoot.insertRef("IDTree", doc->emit(idTree)); + } + return doc->emit(structTreeRoot, ref); } diff --git a/chromium/third_party/skia/src/pdf/SkPDFTag.h b/chromium/third_party/skia/src/pdf/SkPDFTag.h index 00152290da6..63972ffe45a 100644 --- a/chromium/third_party/skia/src/pdf/SkPDFTag.h +++ b/chromium/third_party/skia/src/pdf/SkPDFTag.h @@ -23,20 +23,40 @@ public: ~SkPDFTagTree(); void init(SkPDF::StructureElementNode*); void reset(); - int getMarkIdForNodeId(int nodeId, unsigned pageIndex); - void addNodeAnnotation(int nodeId, SkPDFIndirectReference annotationRef); + // Used to allow marked content to refer to its corresponding structure + // tree node, via a page entry in the parent tree. Returns -1 if no + // mark ID. + int createMarkIdForNodeId(int nodeId, unsigned pageIndex); + // Used to allow annotations to refer to their corresponding structure + // tree node, via the struct parent tree. Returns -1 if no struct parent + // key. + int createStructParentKeyForNodeId(int nodeId, unsigned pageIndex); + + void addNodeAnnotation(int nodeId, SkPDFIndirectReference annotationRef, unsigned pageIndex); SkPDFIndirectReference makeStructTreeRoot(SkPDFDocument* doc); private: + // An entry in a map from a node ID to an indirect reference to its + // corresponding structure element node. + struct IDTreeEntry { + int nodeId; + SkPDFIndirectReference ref; + }; + static void Copy(SkPDF::StructureElementNode& node, SkPDFTagNode* dst, SkArenaAlloc* arena, SkTHashMap<int, SkPDFTagNode*>* nodeMap); + SkPDFIndirectReference PrepareTagTreeToEmit(SkPDFIndirectReference parent, + SkPDFTagNode* node, + SkPDFDocument* doc); SkArenaAlloc fArena; SkTHashMap<int, SkPDFTagNode*> fNodeMap; SkPDFTagNode* fRoot = nullptr; SkTArray<SkTArray<SkPDFTagNode*>> fMarksPerPage; + std::vector<IDTreeEntry> fIdTreeEntries; + std::vector<int> fParentTreeAnnotationNodeIds; SkPDFTagTree(const SkPDFTagTree&) = delete; SkPDFTagTree& operator=(const SkPDFTagTree&) = delete; diff --git a/chromium/third_party/skia/src/ports/SkFontHost_FreeType.cpp b/chromium/third_party/skia/src/ports/SkFontHost_FreeType.cpp index 35b87bb10f0..5a6f6d7c5f6 100644 --- a/chromium/third_party/skia/src/ports/SkFontHost_FreeType.cpp +++ b/chromium/third_party/skia/src/ports/SkFontHost_FreeType.cpp @@ -1817,7 +1817,7 @@ SkTypeface_FreeType::Scanner::~Scanner() { FT_Face SkTypeface_FreeType::Scanner::openFace(SkStreamAsset* stream, int ttcIndex, FT_Stream ftStream) const { - if (fLibrary == nullptr) { + if (fLibrary == nullptr || stream == nullptr) { return nullptr; } diff --git a/chromium/third_party/skia/src/ports/SkFontHost_mac.cpp b/chromium/third_party/skia/src/ports/SkFontHost_mac.cpp deleted file mode 100644 index 9e29b5cee6c..00000000000 --- a/chromium/third_party/skia/src/ports/SkFontHost_mac.cpp +++ /dev/null @@ -1,3226 +0,0 @@ -/* - * Copyright 2006 The Android Open Source Project - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "include/core/SkTypes.h" -#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) - -#ifdef SK_BUILD_FOR_MAC -#import <ApplicationServices/ApplicationServices.h> -#endif - -#ifdef SK_BUILD_FOR_IOS -#include <CoreText/CoreText.h> -#include <CoreText/CTFontManager.h> -#include <CoreGraphics/CoreGraphics.h> -#include <CoreFoundation/CoreFoundation.h> -#endif - -#include "include/core/SkFontMetrics.h" -#include "include/core/SkFontMgr.h" -#include "include/core/SkPaint.h" -#include "include/core/SkPath.h" -#include "include/core/SkStream.h" -#include "include/core/SkString.h" -#include "include/ports/SkTypeface_mac.h" -#include "include/private/SkColorData.h" -#include "include/private/SkFloatingPoint.h" -#include "include/private/SkMutex.h" -#include "include/private/SkOnce.h" -#include "include/private/SkTemplates.h" -#include "include/private/SkTo.h" -#include "include/utils/mac/SkCGUtils.h" -#include "src/core/SkAdvancedTypefaceMetrics.h" -#include "src/core/SkAutoMalloc.h" -#include "src/core/SkDescriptor.h" -#include "src/core/SkEndian.h" -#include "src/core/SkFontDescriptor.h" -#include "src/core/SkGlyph.h" -#include "src/core/SkMaskGamma.h" -#include "src/core/SkMathPriv.h" -#include "src/core/SkTypefaceCache.h" -#include "src/core/SkUtils.h" -#include "src/sfnt/SkOTTable_OS_2.h" -#include "src/sfnt/SkOTUtils.h" -#include "src/sfnt/SkSFNTHeader.h" -#include "src/utils/SkUTF.h" -#include "src/utils/mac/SkUniqueCFRef.h" - -#include <dlfcn.h> - -#include <utility> - -// Set to make glyph bounding boxes visible. -#define SK_SHOW_TEXT_BLIT_COVERAGE 0 - -CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) { - return face ? (CTFontRef)face->internal_private_getCTFontRef() : nullptr; -} - -class SkScalerContext_Mac; - -static SkUniqueCFRef<CFStringRef> make_CFString(const char s[]) { - return SkUniqueCFRef<CFStringRef>(CFStringCreateWithCString(nullptr, s, kCFStringEncodingUTF8)); -} - -// inline versions of these rect helpers - -static bool CGRectIsEmpty_inline(const CGRect& rect) { - return rect.size.width <= 0 || rect.size.height <= 0; -} - -static CGFloat CGRectGetMinX_inline(const CGRect& rect) { - return rect.origin.x; -} - -static CGFloat CGRectGetMaxX_inline(const CGRect& rect) { - return rect.origin.x + rect.size.width; -} - -static CGFloat CGRectGetMinY_inline(const CGRect& rect) { - return rect.origin.y; -} - -static CGFloat CGRectGetMaxY_inline(const CGRect& rect) { - return rect.origin.y + rect.size.height; -} - -static CGFloat CGRectGetWidth_inline(const CGRect& rect) { - return rect.size.width; -} - -/////////////////////////////////////////////////////////////////////////////// - -static void sk_memset_rect32(uint32_t* ptr, uint32_t value, - int width, int height, size_t rowBytes) { - SkASSERT(width); - SkASSERT(width * sizeof(uint32_t) <= rowBytes); - - if (width >= 32) { - while (height) { - sk_memset32(ptr, value, width); - ptr = (uint32_t*)((char*)ptr + rowBytes); - height -= 1; - } - return; - } - - rowBytes -= width * sizeof(uint32_t); - - if (width >= 8) { - while (height) { - int w = width; - do { - *ptr++ = value; *ptr++ = value; - *ptr++ = value; *ptr++ = value; - *ptr++ = value; *ptr++ = value; - *ptr++ = value; *ptr++ = value; - w -= 8; - } while (w >= 8); - while (--w >= 0) { - *ptr++ = value; - } - ptr = (uint32_t*)((char*)ptr + rowBytes); - height -= 1; - } - } else { - while (height) { - int w = width; - do { - *ptr++ = value; - } while (--w > 0); - ptr = (uint32_t*)((char*)ptr + rowBytes); - height -= 1; - } - } -} - -typedef uint32_t CGRGBPixel; - -static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) { - return pixel & 0xFF; -} - -static CGFloat ScalarToCG(SkScalar scalar) { - if (sizeof(CGFloat) == sizeof(float)) { - return SkScalarToFloat(scalar); - } else { - SkASSERT(sizeof(CGFloat) == sizeof(double)); - return (CGFloat) SkScalarToDouble(scalar); - } -} - -static SkScalar CGToScalar(CGFloat cgFloat) { - if (sizeof(CGFloat) == sizeof(float)) { - return SkFloatToScalar(cgFloat); - } else { - SkASSERT(sizeof(CGFloat) == sizeof(double)); - return SkDoubleToScalar(cgFloat); - } -} - -static float CGToFloat(CGFloat cgFloat) { - if (sizeof(CGFloat) == sizeof(float)) { - return cgFloat; - } else { - SkASSERT(sizeof(CGFloat) == sizeof(double)); - return static_cast<float>(cgFloat); - } -} - -static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix) { - return CGAffineTransformMake( ScalarToCG(matrix[SkMatrix::kMScaleX]), - -ScalarToCG(matrix[SkMatrix::kMSkewY] ), - -ScalarToCG(matrix[SkMatrix::kMSkewX] ), - ScalarToCG(matrix[SkMatrix::kMScaleY]), - ScalarToCG(matrix[SkMatrix::kMTransX]), - ScalarToCG(matrix[SkMatrix::kMTransY])); -} - -/////////////////////////////////////////////////////////////////////////////// - -#define BITMAP_INFO_RGB (kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host) - -/** Drawn in FontForge, reduced with fonttools ttx, converted by xxd -i, - * this TrueType font contains a glyph of the spider. - * - * To re-forge the original bytes of the TrueType font file, - * remove all ',|( +0x)' from this definition, - * copy the data to the clipboard, - * run 'pbpaste | xxd -p -r - spider.ttf'. - */ -static constexpr const uint8_t kSpiderSymbol_ttf[] = { - 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x80, 0x00, 0x03, 0x00, 0x40, - 0x47, 0x44, 0x45, 0x46, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x07, 0xa8, - 0x00, 0x00, 0x00, 0x18, 0x4f, 0x53, 0x2f, 0x32, 0x8a, 0xf4, 0xfb, 0xdb, - 0x00, 0x00, 0x01, 0x48, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6d, 0x61, 0x70, - 0xe0, 0x7f, 0x10, 0x7e, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x54, - 0x67, 0x61, 0x73, 0x70, 0xff, 0xff, 0x00, 0x03, 0x00, 0x00, 0x07, 0xa0, - 0x00, 0x00, 0x00, 0x08, 0x67, 0x6c, 0x79, 0x66, 0x97, 0x0b, 0x6a, 0xf6, - 0x00, 0x00, 0x02, 0x18, 0x00, 0x00, 0x03, 0x40, 0x68, 0x65, 0x61, 0x64, - 0x0f, 0xa2, 0x24, 0x1a, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x36, - 0x68, 0x68, 0x65, 0x61, 0x0e, 0xd3, 0x07, 0x3f, 0x00, 0x00, 0x01, 0x04, - 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78, 0x10, 0x03, 0x00, 0x44, - 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x0e, 0x6c, 0x6f, 0x63, 0x61, - 0x01, 0xb4, 0x00, 0x28, 0x00, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x0a, - 0x6d, 0x61, 0x78, 0x70, 0x00, 0x4a, 0x01, 0x4d, 0x00, 0x00, 0x01, 0x28, - 0x00, 0x00, 0x00, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0xc3, 0xe5, 0x39, 0xd4, - 0x00, 0x00, 0x05, 0x58, 0x00, 0x00, 0x02, 0x28, 0x70, 0x6f, 0x73, 0x74, - 0xff, 0x03, 0x00, 0x67, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x20, - 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0f, 0x08, 0x1d, - 0x5f, 0x0f, 0x3c, 0xf5, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xd1, 0x97, 0xa8, 0x5a, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xe8, 0x32, 0x33, - 0x00, 0x03, 0xff, 0x3b, 0x08, 0x00, 0x05, 0x55, 0x00, 0x00, 0x00, 0x08, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x05, 0x55, 0xff, 0x3b, 0x01, 0x79, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x04, 0x01, 0x1c, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x2e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x01, 0x90, 0x00, 0x05, - 0x00, 0x00, 0x05, 0x33, 0x05, 0x99, 0x00, 0x00, 0x01, 0x1e, 0x05, 0x33, - 0x05, 0x99, 0x00, 0x00, 0x03, 0xd7, 0x00, 0x66, 0x02, 0x12, 0x00, 0x00, - 0x05, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x73, 0x6b, 0x69, 0x61, 0x00, 0xc0, 0x00, 0x00, 0xf0, 0x21, - 0x06, 0x66, 0xfe, 0x66, 0x01, 0x79, 0x05, 0x55, 0x00, 0xc5, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x20, 0x00, 0x01, 0x08, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x48, - 0x00, 0x00, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, - 0x00, 0x09, 0x00, 0x0d, 0x00, 0x1d, 0x00, 0x21, 0xf0, 0x21, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x1d, 0x00, 0x21, - 0xf0, 0x21, 0xff, 0xff, 0x00, 0x01, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xe4, - 0xff, 0xe2, 0x0f, 0xe2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, - 0x00, 0x14, 0x00, 0x14, 0x01, 0xa0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x44, - 0x00, 0x00, 0x02, 0x64, 0x05, 0x55, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, - 0x33, 0x11, 0x21, 0x11, 0x25, 0x21, 0x11, 0x21, 0x44, 0x02, 0x20, 0xfe, - 0x24, 0x01, 0x98, 0xfe, 0x68, 0x05, 0x55, 0xfa, 0xab, 0x44, 0x04, 0xcd, - 0x00, 0x04, 0x00, 0x03, 0xff, 0x3b, 0x08, 0x00, 0x05, 0x4c, 0x00, 0x15, - 0x00, 0x1d, 0x00, 0x25, 0x01, 0x1b, 0x00, 0x00, 0x01, 0x36, 0x37, 0x36, - 0x27, 0x26, 0x07, 0x06, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x26, 0x07, - 0x06, 0x17, 0x16, 0x17, 0x16, 0x32, 0x37, 0x32, 0x35, 0x34, 0x23, 0x22, - 0x15, 0x14, 0x27, 0x32, 0x35, 0x34, 0x23, 0x22, 0x15, 0x14, 0x03, 0x32, - 0x17, 0x30, 0x17, 0x31, 0x36, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x33, - 0x32, 0x33, 0x16, 0x33, 0x32, 0x17, 0x16, 0x07, 0x06, 0x23, 0x22, 0x27, - 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, - 0x1f, 0x02, 0x37, 0x36, 0x37, 0x36, 0x33, 0x32, 0x17, 0x17, 0x16, 0x33, - 0x16, 0x17, 0x16, 0x07, 0x06, 0x23, 0x22, 0x27, 0x27, 0x26, 0x23, 0x22, - 0x07, 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x33, 0x32, 0x33, 0x32, - 0x37, 0x36, 0x37, 0x36, 0x17, 0x16, 0x1f, 0x02, 0x16, 0x17, 0x16, 0x15, - 0x14, 0x23, 0x22, 0x27, 0x27, 0x26, 0x27, 0x27, 0x26, 0x27, 0x26, 0x07, - 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x07, - 0x06, 0x23, 0x22, 0x27, 0x26, 0x07, 0x06, 0x07, 0x06, 0x15, 0x14, 0x17, - 0x16, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, - 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x37, 0x34, 0x27, 0x26, 0x07, - 0x06, 0x07, 0x06, 0x0f, 0x02, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x34, - 0x37, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, - 0x26, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x07, 0x06, 0x23, 0x22, - 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x37, 0x36, 0x37, 0x37, 0x36, - 0x37, 0x36, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, - 0x23, 0x22, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x27, 0x26, 0x27, 0x26, - 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x33, 0x32, - 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, - 0x33, 0x04, 0xf5, 0x23, 0x13, 0x11, 0x14, 0x16, 0x1d, 0x1b, 0x4c, 0x1f, - 0x0e, 0x2d, 0x23, 0x14, 0x2c, 0x13, 0x18, 0x25, 0x2c, 0x10, 0x3c, 0x71, - 0x1d, 0x5c, 0x5c, 0x3f, 0xae, 0x5c, 0x5c, 0x3f, 0x6a, 0x27, 0x31, 0x5b, - 0x09, 0x27, 0x36, 0x03, 0x0a, 0x26, 0x35, 0x2e, 0x09, 0x08, 0xc6, 0x13, - 0x81, 0x17, 0x20, 0x18, 0x21, 0x1e, 0x04, 0x04, 0x15, 0x5c, 0x22, 0x26, - 0x48, 0x56, 0x3b, 0x10, 0x21, 0x01, 0x0c, 0x06, 0x06, 0x0f, 0x31, 0x44, - 0x3c, 0x52, 0x4a, 0x1d, 0x11, 0x3f, 0xb4, 0x71, 0x01, 0x26, 0x06, 0x0d, - 0x15, 0x1a, 0x2a, 0x13, 0x53, 0xaa, 0x42, 0x1d, 0x0a, 0x33, 0x20, 0x21, - 0x2b, 0x01, 0x02, 0x3e, 0x21, 0x09, 0x02, 0x02, 0x0f, 0x2d, 0x4b, 0x0a, - 0x22, 0x15, 0x20, 0x1f, 0x72, 0x8b, 0x2d, 0x2f, 0x1d, 0x1f, 0x0e, 0x25, - 0x3f, 0x4d, 0x1b, 0x63, 0x2a, 0x2c, 0x14, 0x22, 0x18, 0x1c, 0x0f, 0x08, - 0x2a, 0x08, 0x08, 0x0d, 0x3b, 0x4c, 0x52, 0x74, 0x27, 0x71, 0x2e, 0x01, - 0x0c, 0x10, 0x15, 0x0d, 0x06, 0x0d, 0x05, 0x01, 0x06, 0x2c, 0x28, 0x14, - 0x1b, 0x05, 0x04, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x16, 0x27, 0x03, 0x0d, - 0x30, 0x4c, 0x4c, 0x4b, 0x1f, 0x0b, 0x22, 0x26, 0x0d, 0x15, 0x0d, 0x2d, - 0x68, 0x34, 0x14, 0x3c, 0x25, 0x12, 0x04, 0x10, 0x18, 0x0b, 0x09, 0x30, - 0x2b, 0x44, 0x66, 0x14, 0x47, 0x47, 0x59, 0x73, 0x25, 0x05, 0x03, 0x1f, - 0x01, 0x08, 0x3f, 0x48, 0x4b, 0x4b, 0x76, 0x2f, 0x49, 0x2d, 0x22, 0x24, - 0x0c, 0x15, 0x08, 0x0e, 0x33, 0x03, 0x44, 0x4c, 0x10, 0x46, 0x13, 0x1f, - 0x27, 0x1b, 0x1d, 0x13, 0x02, 0x24, 0x08, 0x02, 0x42, 0x0e, 0x4d, 0x3c, - 0x19, 0x1b, 0x40, 0x2b, 0x2b, 0x1e, 0x16, 0x11, 0x04, 0x1f, 0x11, 0x04, - 0x18, 0x11, 0x35, 0x01, 0xa3, 0x13, 0x24, 0x1f, 0x0b, 0x0c, 0x19, 0x19, - 0x18, 0x13, 0x0f, 0x0c, 0x1a, 0x18, 0x1f, 0x19, 0x1e, 0x07, 0x1a, 0xc3, - 0x54, 0x51, 0x54, 0x51, 0x04, 0x53, 0x51, 0x54, 0x50, 0x02, 0x48, 0x1a, - 0x31, 0x18, 0x55, 0x74, 0x04, 0x0e, 0x09, 0x0d, 0x06, 0x10, 0x16, 0x1b, - 0x24, 0x01, 0x04, 0x0b, 0x04, 0x10, 0x3f, 0x0a, 0x41, 0x02, 0x41, 0x20, - 0x06, 0x12, 0x16, 0x21, 0x17, 0x2a, 0x1e, 0x15, 0x40, 0x27, 0x11, 0x0e, - 0x1e, 0x11, 0x15, 0x1f, 0x43, 0x13, 0x1a, 0x10, 0x15, 0x1b, 0x04, 0x09, - 0x4d, 0x2a, 0x0f, 0x19, 0x0a, 0x0a, 0x03, 0x05, 0x15, 0x3c, 0x64, 0x21, - 0x4b, 0x2e, 0x21, 0x28, 0x13, 0x47, 0x44, 0x19, 0x3f, 0x11, 0x18, 0x0b, - 0x0a, 0x07, 0x18, 0x0d, 0x07, 0x24, 0x2c, 0x2b, 0x21, 0x32, 0x10, 0x48, - 0x2a, 0x2d, 0x1e, 0x1a, 0x01, 0x0c, 0x43, 0x59, 0x28, 0x4e, 0x1c, 0x0d, - 0x5d, 0x24, 0x14, 0x0a, 0x05, 0x1f, 0x24, 0x32, 0x46, 0x3e, 0x5f, 0x3e, - 0x44, 0x1a, 0x30, 0x15, 0x0d, 0x07, 0x18, 0x2b, 0x03, 0x0d, 0x1a, 0x28, - 0x28, 0x57, 0xb2, 0x29, 0x27, 0x40, 0x2c, 0x23, 0x16, 0x63, 0x58, 0x1a, - 0x0a, 0x18, 0x11, 0x23, 0x08, 0x1b, 0x29, 0x05, 0x04, 0x0b, 0x15, 0x0d, - 0x14, 0x0b, 0x2a, 0x29, 0x5a, 0x62, 0x01, 0x19, 0x1e, 0x05, 0x05, 0x26, - 0x42, 0x42, 0x2a, 0x2a, 0x3f, 0x0d, 0x0f, 0x09, 0x05, 0x07, 0x01, 0x0b, - 0x25, 0x3e, 0x0d, 0x17, 0x11, 0x01, 0x03, 0x0d, 0x13, 0x20, 0x19, 0x11, - 0x03, 0x02, 0x01, 0x04, 0x11, 0x04, 0x05, 0x1b, 0x3d, 0x10, 0x29, 0x20, - 0x04, 0x04, 0x0a, 0x07, 0x04, 0x1f, 0x15, 0x20, 0x3e, 0x0f, 0x2a, 0x1e, - 0x00, 0x00, 0x00, 0x1b, 0x01, 0x4a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x07, 0x00, 0x27, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x03, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x05, 0x00, 0x02, 0x00, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x06, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x30, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, - 0x00, 0x00, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, - 0x00, 0x01, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, - 0x00, 0x02, 0x00, 0x0e, 0x00, 0x98, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, - 0x00, 0x03, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, - 0x00, 0x04, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, - 0x00, 0x05, 0x00, 0x04, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, - 0x00, 0x06, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, - 0x00, 0x0d, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, - 0x00, 0x0e, 0x00, 0x34, 0x00, 0xaa, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, - 0x00, 0x00, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, - 0x00, 0x01, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, - 0x00, 0x02, 0x00, 0x0e, 0x00, 0x98, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, - 0x00, 0x03, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, - 0x00, 0x04, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, - 0x00, 0x05, 0x00, 0x04, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, - 0x00, 0x06, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, - 0x00, 0x0d, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, - 0x00, 0x0e, 0x00, 0x34, 0x00, 0xaa, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, - 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x35, - 0x2c, 0x20, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x53, 0x70, 0x69, - 0x64, 0x65, 0x72, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x52, 0x65, 0x67, - 0x75, 0x6c, 0x61, 0x72, 0x56, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, - 0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x2e, 0x73, 0x69, 0x6c, - 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x4f, 0x46, 0x4c, 0x00, 0x43, 0x00, 0x6f, - 0x00, 0x70, 0x00, 0x79, 0x00, 0x72, 0x00, 0x69, 0x00, 0x67, 0x00, 0x68, - 0x00, 0x74, 0x00, 0x20, 0x00, 0x28, 0x00, 0x63, 0x00, 0x29, 0x00, 0x20, - 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x20, - 0x00, 0x47, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, - 0x00, 0x2e, 0x00, 0x53, 0x00, 0x70, 0x00, 0x69, 0x00, 0x64, 0x00, 0x65, - 0x00, 0x72, 0x00, 0x53, 0x00, 0x79, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x6f, - 0x00, 0x6c, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00, 0x6c, - 0x00, 0x61, 0x00, 0x72, 0x00, 0x56, 0x00, 0x31, 0x00, 0x68, 0x00, 0x74, - 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x73, - 0x00, 0x63, 0x00, 0x72, 0x00, 0x69, 0x00, 0x70, 0x00, 0x74, 0x00, 0x73, - 0x00, 0x2e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x2e, 0x00, 0x6f, - 0x00, 0x72, 0x00, 0x67, 0x00, 0x2f, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x4c, - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x66, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0xff, 0xff, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00 -}; - -enum class SmoothBehavior { - none, // SmoothFonts produces no effect. - some, // SmoothFonts produces some effect, but not subpixel coverage. - subpixel, // SmoothFonts produces some effect and provides subpixel coverage. -}; - -/** - * There does not appear to be a publicly accessable API for determining if lcd - * font smoothing will be applied if we request it. The main issue is that if - * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0. - */ -static SmoothBehavior smooth_behavior() { - static SmoothBehavior gSmoothBehavior = []{ - uint32_t noSmoothBitmap[16][16] = {}; - uint32_t smoothBitmap[16][16] = {}; - - SkUniqueCFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB()); - SkUniqueCFRef<CGContextRef> noSmoothContext( - CGBitmapContextCreate(&noSmoothBitmap, 16, 16, 8, 16*4, - colorspace.get(), BITMAP_INFO_RGB)); - SkUniqueCFRef<CGContextRef> smoothContext( - CGBitmapContextCreate(&smoothBitmap, 16, 16, 8, 16*4, - colorspace.get(), BITMAP_INFO_RGB)); - - SkUniqueCFRef<CFDataRef> data(CFDataCreateWithBytesNoCopy( - kCFAllocatorDefault, kSpiderSymbol_ttf, SK_ARRAY_COUNT(kSpiderSymbol_ttf), - kCFAllocatorNull)); - SkUniqueCFRef<CTFontDescriptorRef> desc( - CTFontManagerCreateFontDescriptorFromData(data.get())); - SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc.get(), 16, nullptr)); - SkASSERT(ctFont); - - CGContextSetShouldSmoothFonts(noSmoothContext.get(), false); - CGContextSetShouldAntialias(noSmoothContext.get(), true); - CGContextSetTextDrawingMode(noSmoothContext.get(), kCGTextFill); - CGContextSetGrayFillColor(noSmoothContext.get(), 1, 1); - - CGContextSetShouldSmoothFonts(smoothContext.get(), true); - CGContextSetShouldAntialias(smoothContext.get(), true); - CGContextSetTextDrawingMode(smoothContext.get(), kCGTextFill); - CGContextSetGrayFillColor(smoothContext.get(), 1, 1); - - CGPoint point = CGPointMake(0, 3); - CGGlyph spiderGlyph = 3; - CTFontDrawGlyphs(ctFont.get(), &spiderGlyph, &point, 1, noSmoothContext.get()); - CTFontDrawGlyphs(ctFont.get(), &spiderGlyph, &point, 1, smoothContext.get()); - - // For debugging. - //SkUniqueCFRef<CGImageRef> image(CGBitmapContextCreateImage(noSmoothContext())); - //SkUniqueCFRef<CGImageRef> image(CGBitmapContextCreateImage(smoothContext())); - - SmoothBehavior smoothBehavior = SmoothBehavior::none; - for (int x = 0; x < 16; ++x) { - for (int y = 0; y < 16; ++y) { - uint32_t smoothPixel = smoothBitmap[x][y]; - uint32_t r = (smoothPixel >> 16) & 0xFF; - uint32_t g = (smoothPixel >> 8) & 0xFF; - uint32_t b = (smoothPixel >> 0) & 0xFF; - if (r != g || r != b) { - return SmoothBehavior::subpixel; - } - if (noSmoothBitmap[x][y] != smoothPixel) { - smoothBehavior = SmoothBehavior::some; - } - } - } - return smoothBehavior; - }(); - return gSmoothBehavior; -} - -class Offscreen { -public: - Offscreen() - : fRGBSpace(nullptr) - , fCG(nullptr) - , fDoAA(false) - , fDoLCD(false) - { - fSize.set(0, 0); - } - - CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, - CGGlyph glyphID, size_t* rowBytesPtr, bool generateA8FromLCD); - -private: - enum { - kSize = 32 * 32 * sizeof(CGRGBPixel) - }; - SkAutoSMalloc<kSize> fImageStorage; - SkUniqueCFRef<CGColorSpaceRef> fRGBSpace; - - // cached state - SkUniqueCFRef<CGContextRef> fCG; - SkISize fSize; - bool fDoAA; - bool fDoLCD; - - static int RoundSize(int dimension) { - return SkNextPow2(dimension); - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -static bool find_dict_CGFloat(CFDictionaryRef dict, CFStringRef name, CGFloat* value) { - CFNumberRef num; - return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num) - && CFNumberIsFloatType(num) - && CFNumberGetValue(num, kCFNumberCGFloatType, value); -} - -template <typename S, typename D, typename C> struct LinearInterpolater { - struct Mapping { - S src_val; - D dst_val; - }; - constexpr LinearInterpolater(Mapping const mapping[], int mappingCount) - : fMapping(mapping), fMappingCount(mappingCount) {} - - static D map(S value, S src_min, S src_max, D dst_min, D dst_max) { - SkASSERT(src_min < src_max); - SkASSERT(dst_min <= dst_max); - return C()(dst_min + (((value - src_min) * (dst_max - dst_min)) / (src_max - src_min))); - } - - D map(S val) const { - // -Inf to [0] - if (val < fMapping[0].src_val) { - return fMapping[0].dst_val; - } - - // Linear from [i] to [i+1] - for (int i = 0; i < fMappingCount - 1; ++i) { - if (val < fMapping[i+1].src_val) { - return map(val, fMapping[i].src_val, fMapping[i+1].src_val, - fMapping[i].dst_val, fMapping[i+1].dst_val); - } - } - - // From [n] to +Inf - // if (fcweight < Inf) - return fMapping[fMappingCount - 1].dst_val; - } - - Mapping const * fMapping; - int fMappingCount; -}; - -struct RoundCGFloatToInt { - int operator()(CGFloat s) { return s + 0.5; } -}; -struct CGFloatIdentity { - CGFloat operator()(CGFloat s) { return s; } -}; - -/** Returns the [-1, 1] CTFontDescriptor weights for the - * <0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000> CSS weights. - * - * It is assumed that the values will be interpolated linearly between these points. - * NSFontWeightXXX were added in 10.11, appear in 10.10, but do not appear in 10.9. - * The actual values appear to be stable, but they may change in the future without notice. - */ -static CGFloat(&get_NSFontWeight_mapping())[11] { - - // Declarations in <AppKit/AppKit.h> on macOS, <UIKit/UIKit.h> on iOS -#ifdef SK_BUILD_FOR_MAC -# define SK_KIT_FONT_WEIGHT_PREFIX "NS" -#endif -#ifdef SK_BUILD_FOR_IOS -# define SK_KIT_FONT_WEIGHT_PREFIX "UI" -#endif - static constexpr struct { - CGFloat defaultValue; - const char* name; - } nsFontWeightLoaderInfos[] = { - { -0.80f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightUltraLight" }, - { -0.60f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightThin" }, - { -0.40f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightLight" }, - { 0.00f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightRegular" }, - { 0.23f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightMedium" }, - { 0.30f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightSemibold" }, - { 0.40f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightBold" }, - { 0.56f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightHeavy" }, - { 0.62f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightBlack" }, - }; - - static_assert(SK_ARRAY_COUNT(nsFontWeightLoaderInfos) == 9, ""); - static CGFloat nsFontWeights[11]; - static SkOnce once; - once([&] { - size_t i = 0; - nsFontWeights[i++] = -1.00; - for (const auto& nsFontWeightLoaderInfo : nsFontWeightLoaderInfos) { - void* nsFontWeightValuePtr = dlsym(RTLD_DEFAULT, nsFontWeightLoaderInfo.name); - if (nsFontWeightValuePtr) { - nsFontWeights[i++] = *(static_cast<CGFloat*>(nsFontWeightValuePtr)); - } else { - nsFontWeights[i++] = nsFontWeightLoaderInfo.defaultValue; - } - } - nsFontWeights[i++] = 1.00; - }); - return nsFontWeights; -} - -/** Convert the [0, 1000] CSS weight to [-1, 1] CTFontDescriptor weight (for system fonts). - * - * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the - * CTFont is native or created from a CGDataProvider. - */ -static CGFloat fontstyle_to_ct_weight(int fontstyleWeight) { - using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>; - - // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100. - // However, on this end we can't tell, so this is ignored. - - static Interpolator::Mapping nativeWeightMappings[11]; - static SkOnce once; - once([&] { - CGFloat(&nsFontWeights)[11] = get_NSFontWeight_mapping(); - for (int i = 0; i < 11; ++i) { - nativeWeightMappings[i].src_val = i * 100; - nativeWeightMappings[i].dst_val = nsFontWeights[i]; - } - }); - static constexpr Interpolator nativeInterpolator( - nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings)); - - return nativeInterpolator.map(fontstyleWeight); -} - - -/** Convert the [-1, 1] CTFontDescriptor weight to [0, 1000] CSS weight. - * - * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the - * CTFont is native or created from a CGDataProvider. - */ -static int ct_weight_to_fontstyle(CGFloat cgWeight, bool fromDataProvider) { - using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>; - - // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100. - // However, on this end we can't tell, so this is ignored. - - /** This mapping for CGDataProvider created fonts is determined by creating font data with every - * weight, creating a CTFont, and asking the CTFont for its weight. See the TypefaceStyle test - * in tests/TypefaceTest.cpp for the code used to determine these values. - */ - static constexpr Interpolator::Mapping dataProviderWeightMappings[] = { - { -1.00, 0 }, - { -0.70, 100 }, - { -0.50, 200 }, - { -0.23, 300 }, - { 0.00, 400 }, - { 0.20, 500 }, - { 0.30, 600 }, - { 0.40, 700 }, - { 0.60, 800 }, - { 0.80, 900 }, - { 1.00, 1000 }, - }; - static constexpr Interpolator dataProviderInterpolator( - dataProviderWeightMappings, SK_ARRAY_COUNT(dataProviderWeightMappings)); - - static Interpolator::Mapping nativeWeightMappings[11]; - static SkOnce once; - once([&] { - CGFloat(&nsFontWeights)[11] = get_NSFontWeight_mapping(); - for (int i = 0; i < 11; ++i) { - nativeWeightMappings[i].src_val = nsFontWeights[i]; - nativeWeightMappings[i].dst_val = i * 100; - } - }); - static constexpr Interpolator nativeInterpolator( - nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings)); - - return fromDataProvider ? dataProviderInterpolator.map(cgWeight) - : nativeInterpolator.map(cgWeight); -} - -/** Convert the [0, 10] CSS weight to [-1, 1] CTFontDescriptor width. */ -static int fontstyle_to_ct_width(int fontstyleWidth) { - using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>; - - // Values determined by creating font data with every width, creating a CTFont, - // and asking the CTFont for its width. See TypefaceStyle test for basics. - static constexpr Interpolator::Mapping widthMappings[] = { - { 0, -0.5 }, - { 10, 0.5 }, - }; - static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings)); - return interpolator.map(fontstyleWidth); -} - -/** Convert the [-1, 1] CTFontDescriptor width to [0, 10] CSS weight. */ -static int ct_width_to_fontstyle(CGFloat cgWidth) { - using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>; - - // Values determined by creating font data with every width, creating a CTFont, - // and asking the CTFont for its width. See TypefaceStyle test for basics. - static constexpr Interpolator::Mapping widthMappings[] = { - { -0.5, 0 }, - { 0.5, 10 }, - }; - static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings)); - return interpolator.map(cgWidth); -} - -static SkFontStyle fontstyle_from_descriptor(CTFontDescriptorRef desc, bool fromDataProvider) { - SkUniqueCFRef<CFTypeRef> traits(CTFontDescriptorCopyAttribute(desc, kCTFontTraitsAttribute)); - if (!traits || CFDictionaryGetTypeID() != CFGetTypeID(traits.get())) { - return SkFontStyle(); - } - SkUniqueCFRef<CFDictionaryRef> fontTraitsDict(static_cast<CFDictionaryRef>(traits.release())); - - CGFloat weight, width, slant; - if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWeightTrait, &weight)) { - weight = 0; - } - if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWidthTrait, &width)) { - width = 0; - } - if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontSlantTrait, &slant)) { - slant = 0; - } - - return SkFontStyle(ct_weight_to_fontstyle(weight, fromDataProvider), - ct_width_to_fontstyle(width), - slant ? SkFontStyle::kItalic_Slant - : SkFontStyle::kUpright_Slant); -} - -struct OpszVariation { - bool isSet = false; - double value = 0; -}; - -class SkTypeface_Mac : public SkTypeface { -public: - SkTypeface_Mac(SkUniqueCFRef<CTFontRef> fontRef, const SkFontStyle& fs, bool isFixedPitch, - OpszVariation opszVariation, std::unique_ptr<SkStreamAsset> providedData) - : SkTypeface(fs, isFixedPitch) - , fFontRef(std::move(fontRef)) - , fOpszVariation(opszVariation) - , fHasColorGlyphs( - SkToBool(CTFontGetSymbolicTraits(fFontRef.get()) & kCTFontColorGlyphsTrait)) - , fStream(std::move(providedData)) - , fIsFromStream(fStream) - { - SkASSERT(fFontRef); - } - - SkUniqueCFRef<CTFontRef> fFontRef; - const OpszVariation fOpszVariation; - const bool fHasColorGlyphs; - -protected: - int onGetUPEM() const override; - std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override; - std::unique_ptr<SkFontData> onMakeFontData() const override; - int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], - int coordinateCount) const override; - void onGetFamilyName(SkString* familyName) const override; - SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; - int onGetTableTags(SkFontTableTag tags[]) const override; - size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override; - sk_sp<SkData> onCopyTableData(SkFontTableTag) const override; - SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&, - const SkDescriptor*) const override; - void onFilterRec(SkScalerContextRec*) const override; - void onGetFontDescriptor(SkFontDescriptor*, bool*) const override; - void getGlyphToUnicodeMap(SkUnichar*) const override; - std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override; - void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override; - int onCountGlyphs() const override; - void getPostScriptGlyphNames(SkString*) const override {} - int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], - int parameterCount) const override; - sk_sp<SkTypeface> onMakeClone(const SkFontArguments&) const override; - - void* onGetCTFontRef() const override { return (void*)fFontRef.get(); } - -private: - mutable std::unique_ptr<SkStreamAsset> fStream; - bool fIsFromStream; - mutable SkOnce fInitStream; - - typedef SkTypeface INHERITED; -}; - -static bool find_by_CTFontRef(SkTypeface* cached, void* context) { - CTFontRef self = (CTFontRef)context; - CTFontRef other = (CTFontRef)cached->internal_private_getCTFontRef(); - - return CFEqual(self, other); -} - -/** Creates a typeface, searching the cache if isLocalStream is false. */ -static sk_sp<SkTypeface> create_from_CTFontRef(SkUniqueCFRef<CTFontRef> font, - OpszVariation opszVariation, - std::unique_ptr<SkStreamAsset> providedData) { - SkASSERT(font); - const bool isFromStream(providedData); - - if (!isFromStream) { - sk_sp<SkTypeface> face = SkTypefaceCache::FindByProcAndRef(find_by_CTFontRef, - (void*)font.get()); - if (face) { - return face; - } - } - - SkUniqueCFRef<CTFontDescriptorRef> desc(CTFontCopyFontDescriptor(font.get())); - SkFontStyle style = fontstyle_from_descriptor(desc.get(), isFromStream); - CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font.get()); - bool isFixedPitch = SkToBool(traits & kCTFontMonoSpaceTrait); - - sk_sp<SkTypeface> face(new SkTypeface_Mac(std::move(font), style, - isFixedPitch, opszVariation, - std::move(providedData))); - if (!isFromStream) { - SkTypefaceCache::Add(face); - } - return face; -} - -/** Creates a typeface from a descriptor, searching the cache. */ -static sk_sp<SkTypeface> create_from_desc(CTFontDescriptorRef desc) { - SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr)); - if (!ctFont) { - return nullptr; - } - - return create_from_CTFontRef(std::move(ctFont), OpszVariation(), nullptr); -} - -static SkUniqueCFRef<CTFontDescriptorRef> create_descriptor(const char familyName[], - const SkFontStyle& style) { - SkUniqueCFRef<CFMutableDictionaryRef> cfAttributes( - CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - SkUniqueCFRef<CFMutableDictionaryRef> cfTraits( - CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - if (!cfAttributes || !cfTraits) { - return nullptr; - } - - // TODO(crbug.com/1018581) Some CoreText versions have errant behavior when - // certain traits set. Temporary workaround to omit specifying trait for - // those versions. - // Long term solution will involve serializing typefaces instead of relying - // upon this to match between processes. - // - // Compare CoreText.h in an up to date SDK for where these values come from. - static const uint32_t kSkiaLocalCTVersionNumber10_14 = 0x000B0000; - static const uint32_t kSkiaLocalCTVersionNumber10_15 = 0x000C0000; - - // CTFontTraits (symbolic) - // macOS 14 and iOS 12 seem to behave badly when kCTFontSymbolicTrait is set. - // macOS 15 yields LastResort font instead of a good default font when - // kCTFontSymbolicTrait is set. - if (!(&CTGetCoreTextVersion && CTGetCoreTextVersion() >= kSkiaLocalCTVersionNumber10_14)) { - CTFontSymbolicTraits ctFontTraits = 0; - if (style.weight() >= SkFontStyle::kBold_Weight) { - ctFontTraits |= kCTFontBoldTrait; - } - if (style.slant() != SkFontStyle::kUpright_Slant) { - ctFontTraits |= kCTFontItalicTrait; - } - SkUniqueCFRef<CFNumberRef> cfFontTraits( - CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits)); - if (cfFontTraits) { - CFDictionaryAddValue(cfTraits.get(), kCTFontSymbolicTrait, cfFontTraits.get()); - } - } - - // CTFontTraits (weight) - CGFloat ctWeight = fontstyle_to_ct_weight(style.weight()); - SkUniqueCFRef<CFNumberRef> cfFontWeight( - CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWeight)); - if (cfFontWeight) { - CFDictionaryAddValue(cfTraits.get(), kCTFontWeightTrait, cfFontWeight.get()); - } - // CTFontTraits (width) - CGFloat ctWidth = fontstyle_to_ct_width(style.width()); - SkUniqueCFRef<CFNumberRef> cfFontWidth( - CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWidth)); - if (cfFontWidth) { - CFDictionaryAddValue(cfTraits.get(), kCTFontWidthTrait, cfFontWidth.get()); - } - // CTFontTraits (slant) - // macOS 15 behaves badly when kCTFontSlantTrait is set. - if (!(&CTGetCoreTextVersion && CTGetCoreTextVersion() == kSkiaLocalCTVersionNumber10_15)) { - CGFloat ctSlant = style.slant() == SkFontStyle::kUpright_Slant ? 0 : 1; - SkUniqueCFRef<CFNumberRef> cfFontSlant( - CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctSlant)); - if (cfFontSlant) { - CFDictionaryAddValue(cfTraits.get(), kCTFontSlantTrait, cfFontSlant.get()); - } - } - // CTFontTraits - CFDictionaryAddValue(cfAttributes.get(), kCTFontTraitsAttribute, cfTraits.get()); - - // CTFontFamilyName - if (familyName) { - SkUniqueCFRef<CFStringRef> cfFontName = make_CFString(familyName); - if (cfFontName) { - CFDictionaryAddValue(cfAttributes.get(), kCTFontFamilyNameAttribute, cfFontName.get()); - } - } - - return SkUniqueCFRef<CTFontDescriptorRef>( - CTFontDescriptorCreateWithAttributes(cfAttributes.get())); -} - -// Same as the above function except style is included so we can -// compare whether the created font conforms to the style. If not, we need -// to recreate the font with symbolic traits. This is needed due to MacOS 10.11 -// font creation problem https://bugs.chromium.org/p/skia/issues/detail?id=8447. -static sk_sp<SkTypeface> create_from_desc_and_style(CTFontDescriptorRef desc, - const SkFontStyle& style) { - SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr)); - if (!ctFont) { - return nullptr; - } - - const CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctFont.get()); - CTFontSymbolicTraits expected_traits = traits; - if (style.slant() != SkFontStyle::kUpright_Slant) { - expected_traits |= kCTFontItalicTrait; - } - if (style.weight() >= SkFontStyle::kBold_Weight) { - expected_traits |= kCTFontBoldTrait; - } - - if (expected_traits != traits) { - SkUniqueCFRef<CTFontRef> ctNewFont(CTFontCreateCopyWithSymbolicTraits( - ctFont.get(), 0, nullptr, expected_traits, expected_traits)); - if (ctNewFont) { - ctFont = std::move(ctNewFont); - } - } - - return create_from_CTFontRef(std::move(ctFont), OpszVariation(), nullptr); -} - -/** Creates a typeface from a name, searching the cache. */ -static sk_sp<SkTypeface> create_from_name(const char familyName[], const SkFontStyle& style) { - SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style); - if (!desc) { - return nullptr; - } - return create_from_desc_and_style(desc.get(), style); -} - -/////////////////////////////////////////////////////////////////////////////// - -/* This function is visible on the outside. It first searches the cache, and if - * not found, returns a new entry (after adding it to the cache). - */ -sk_sp<SkTypeface> SkMakeTypefaceFromCTFont(CTFontRef font) { - CFRetain(font); - return create_from_CTFontRef(SkUniqueCFRef<CTFontRef>(font), - OpszVariation(), - nullptr); -} - -static const char* map_css_names(const char* name) { - static const struct { - const char* fFrom; // name the caller specified - const char* fTo; // "canonical" name we map to - } gPairs[] = { - { "sans-serif", "Helvetica" }, - { "serif", "Times" }, - { "monospace", "Courier" } - }; - - for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { - if (strcmp(name, gPairs[i].fFrom) == 0) { - return gPairs[i].fTo; - } - } - return name; // no change -} - -/////////////////////////////////////////////////////////////////////////////// - -class SkScalerContext_Mac : public SkScalerContext { -public: - SkScalerContext_Mac(sk_sp<SkTypeface_Mac>, const SkScalerContextEffects&, const SkDescriptor*); - -protected: - unsigned generateGlyphCount(void) override; - bool generateAdvance(SkGlyph* glyph) override; - void generateMetrics(SkGlyph* glyph) override; - void generateImage(const SkGlyph& glyph) override; - bool generatePath(SkGlyphID glyph, SkPath* path) override; - void generateFontMetrics(SkFontMetrics*) override; - -private: - template<bool APPLY_PREBLEND> - static void RGBToA8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, - const SkGlyph& glyph, const uint8_t* table8); - template<bool APPLY_PREBLEND> - static uint16_t RGBToLcd16(CGRGBPixel rgb, const uint8_t* tableR, - const uint8_t* tableG, - const uint8_t* tableB); - template<bool APPLY_PREBLEND> - static void RGBToLcd16(const CGRGBPixel* SK_RESTRICT cgPixels, - size_t cgRowBytes, - const SkGlyph& glyph, - const uint8_t* tableR, - const uint8_t* tableG, - const uint8_t* tableB); - - Offscreen fOffscreen; - - /** Unrotated variant of fCTFont. - * - * In 10.10.1 CTFontGetAdvancesForGlyphs applies the font transform to the width of the - * advances, but always sets the height to 0. This font is used to get the advances of the - * unrotated glyph, and then the rotation is applied separately. - * - * CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise. - * This makes kCTFontOrientationDefault dangerous, because the metrics from - * kCTFontOrientationHorizontal are in a different space from kCTFontOrientationVertical. - * With kCTFontOrientationVertical the advances must be unrotated. - * - * Sometimes, creating a copy of a CTFont with the same size but different trasform will select - * different underlying font data. As a result, avoid ever creating more than one CTFont per - * SkScalerContext to ensure that only one CTFont is used. - * - * As a result of the above (and other constraints) this font contains the size, but not the - * transform. The transform must always be applied separately. - */ - SkUniqueCFRef<CTFontRef> fCTFont; - - /** The transform without the font size. */ - CGAffineTransform fTransform; - CGAffineTransform fInvTransform; - - SkUniqueCFRef<CGFontRef> fCGFont; - uint16_t fGlyphCount; - const bool fDoSubPosition; - - friend class Offscreen; - - typedef SkScalerContext INHERITED; -}; - -// In macOS 10.12 and later any variation on the CGFont which has default axis value will be -// dropped when creating the CTFont. Unfortunately, in macOS 10.15 the priority of setting -// the optical size (and opsz variation) is -// 1. the value of kCTFontOpticalSizeAttribute in the CTFontDescriptor (undocumented) -// 2. the opsz axis default value if kCTFontOpticalSizeAttribute is 'none' (undocumented) -// 3. the opsz variation on the nascent CTFont from the CGFont (was dropped if default) -// 4. the opsz variation in kCTFontVariationAttribute in CTFontDescriptor (crashes 10.10) -// 5. the size requested (can fudge in SkTypeface but not SkScalerContext) -// The first one which is found will be used to set the opsz variation (after clamping). -static void add_opsz_attr(CFMutableDictionaryRef attr, double opsz) { - SkUniqueCFRef<CFNumberRef> opszValueNumber( - CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &opsz)); - // Avoid using kCTFontOpticalSizeAttribute directly - CFStringRef SkCTFontOpticalSizeAttribute = CFSTR("NSCTFontOpticalSizeAttribute"); - CFDictionarySetValue(attr, SkCTFontOpticalSizeAttribute, opszValueNumber.get()); -} - -// This turns off application of the 'trak' table to advances, but also all other tracking. -static void add_notrak_attr(CFMutableDictionaryRef attr) { - int zero = 0; - SkUniqueCFRef<CFNumberRef> unscaledTrackingNumber( - CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &zero)); - CFStringRef SkCTFontUnscaledTrackingAttribute = CFSTR("NSCTFontUnscaledTrackingAttribute"); - CFDictionarySetValue(attr, SkCTFontUnscaledTrackingAttribute, unscaledTrackingNumber.get()); -} - -static SkUniqueCFRef<CTFontRef> ctfont_create_exact_copy(CTFontRef baseFont, CGFloat textSize, - OpszVariation opsz) -{ - SkUniqueCFRef<CFMutableDictionaryRef> attr( - CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - if (opsz.isSet) { - add_opsz_attr(attr.get(), opsz.value); -#if !defined(SK_IGNORE_MAC_OPSZ_FORCE) - } else { - // On (at least) 10.10 though 10.14 the default system font was SFNSText/SFNSDisplay. - // The CTFont is backed by both; optical size < 20 means SFNSText else SFNSDisplay. - // On at least 10.11 the glyph ids in these fonts became non-interchangable. - // To keep glyph ids stable over size changes, preserve the optical size. - // In 10.15 this was replaced with use of variable fonts with an opsz axis. - // A CTFont backed by multiple fonts picked by opsz where the multiple backing fonts are - // variable fonts with opsz axis and non-interchangeable glyph ids would break the - // opsz.isSet branch above, but hopefully that never happens. - // See https://crbug.com/524646 . - CFStringRef SkCTFontOpticalSizeAttribute = CFSTR("NSCTFontOpticalSizeAttribute"); - SkUniqueCFRef<CFTypeRef> opsz(CTFontCopyAttribute(baseFont, SkCTFontOpticalSizeAttribute)); - double opsz_val; - if (!opsz || - CFGetTypeID(opsz.get()) != CFNumberGetTypeID() || - !CFNumberGetValue(static_cast<CFNumberRef>(opsz.get()),kCFNumberDoubleType,&opsz_val) || - opsz_val <= 0) - { - opsz_val = CTFontGetSize(baseFont); - } - add_opsz_attr(attr.get(), opsz_val); -#endif - } - add_notrak_attr(attr.get()); - - SkUniqueCFRef<CTFontDescriptorRef> desc(CTFontDescriptorCreateWithAttributes(attr.get())); - -#if !defined(SK_IGNORE_MAC_OPSZ_FORCE) - return SkUniqueCFRef<CTFontRef>( - CTFontCreateCopyWithAttributes(baseFont, textSize, nullptr, desc.get())); -#else - SkUniqueCFRef<CGFontRef> baseCGFont(CTFontCopyGraphicsFont(baseFont, nullptr)); - return SkUniqueCFRef<CTFontRef>( - CTFontCreateWithGraphicsFont(baseCGFont.get(), textSize, nullptr, desc.get())); - -#endif -} - -SkScalerContext_Mac::SkScalerContext_Mac(sk_sp<SkTypeface_Mac> typeface, - const SkScalerContextEffects& effects, - const SkDescriptor* desc) - : INHERITED(std::move(typeface), effects, desc) - , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag)) - -{ - CTFontRef ctFont = (CTFontRef)this->getTypeface()->internal_private_getCTFontRef(); - CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); - SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); - fGlyphCount = SkToU16(numGlyphs); - - // CT on (at least) 10.9 will size color glyphs down from the requested size, but not up. - // As a result, it is necessary to know the actual device size and request that. - SkVector scale; - SkMatrix skTransform; - bool invertible = fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale, - &scale, &skTransform, nullptr, nullptr, nullptr); - fTransform = MatrixToCGAffineTransform(skTransform); - // CGAffineTransformInvert documents that if the transform is non-invertible it will return the - // passed transform unchanged. It does so, but then also prints a message to stdout. Avoid this. - if (invertible) { - fInvTransform = CGAffineTransformInvert(fTransform); - } else { - fInvTransform = fTransform; - } - - // The transform contains everything except the requested text size. - // Some properties, like 'trak', are based on the optical text size. - CGFloat textSize = ScalarToCG(scale.y()); - fCTFont = ctfont_create_exact_copy(ctFont, textSize, - ((SkTypeface_Mac*)this->getTypeface())->fOpszVariation); - fCGFont.reset(CTFontCopyGraphicsFont(fCTFont.get(), nullptr)); -} - -CGRGBPixel* Offscreen::getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, - CGGlyph glyphID, size_t* rowBytesPtr, - bool generateA8FromLCD) { - if (!fRGBSpace) { - //It doesn't appear to matter what color space is specified. - //Regular blends and antialiased text are always (s*a + d*(1-a)) - //and subpixel antialiased text is always g=2.0. - fRGBSpace.reset(CGColorSpaceCreateDeviceRGB()); - } - - // default to kBW_Format - bool doAA = false; - bool doLCD = false; - - if (SkMask::kBW_Format != glyph.maskFormat()) { - doLCD = true; - doAA = true; - } - - // FIXME: lcd smoothed un-hinted rasterization unsupported. - if (!generateA8FromLCD && SkMask::kA8_Format == glyph.maskFormat()) { - doLCD = false; - doAA = true; - } - - // If this font might have color glyphs, disable LCD as there's no way to support it. - // CoreText doesn't tell us which format it ended up using, so we can't detect it. - // A8 will end up black on transparent, but TODO: we can detect gray and set to A8. - if (SkMask::kARGB32_Format == glyph.maskFormat()) { - doLCD = false; - } - - size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel); - if (!fCG || fSize.fWidth < glyph.width() || fSize.fHeight < glyph.height()) { - if (fSize.fWidth < glyph.width()) { - fSize.fWidth = RoundSize(glyph.width()); - } - if (fSize.fHeight < glyph.height()) { - fSize.fHeight = RoundSize(glyph.height()); - } - - rowBytes = fSize.fWidth * sizeof(CGRGBPixel); - void* image = fImageStorage.reset(rowBytes * fSize.fHeight); - const CGImageAlphaInfo alpha = (glyph.isColor()) - ? kCGImageAlphaPremultipliedFirst - : kCGImageAlphaNoneSkipFirst; - const CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | alpha; - fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, - rowBytes, fRGBSpace.get(), bitmapInfo)); - - // Skia handles quantization and subpixel positioning, - // so disable quantization and enabe subpixel positioning in CG. - CGContextSetAllowsFontSubpixelQuantization(fCG.get(), false); - CGContextSetShouldSubpixelQuantizeFonts(fCG.get(), false); - - // Because CG always draws from the horizontal baseline, - // if there is a non-integral translation from the horizontal origin to the vertical origin, - // then CG cannot draw the glyph in the correct location without subpixel positioning. - CGContextSetAllowsFontSubpixelPositioning(fCG.get(), true); - CGContextSetShouldSubpixelPositionFonts(fCG.get(), true); - - CGContextSetTextDrawingMode(fCG.get(), kCGTextFill); - - // Draw black on white to create mask. (Special path exists to speed this up in CG.) - CGContextSetGrayFillColor(fCG.get(), 0.0f, 1.0f); - - // force our checks below to happen - fDoAA = !doAA; - fDoLCD = !doLCD; - - CGContextSetTextMatrix(fCG.get(), context.fTransform); - } - - if (fDoAA != doAA) { - CGContextSetShouldAntialias(fCG.get(), doAA); - fDoAA = doAA; - } - if (fDoLCD != doLCD) { - CGContextSetShouldSmoothFonts(fCG.get(), doLCD); - fDoLCD = doLCD; - } - - CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get(); - // skip rows based on the glyph's height - image += (fSize.fHeight - glyph.height()) * fSize.fWidth; - - // Erase to white (or transparent black if it's a color glyph, to not composite against white). - uint32_t bgColor = (!glyph.isColor()) ? 0xFFFFFFFF : 0x00000000; - sk_memset_rect32(image, bgColor, glyph.width(), glyph.height(), rowBytes); - - float subX = 0; - float subY = 0; - if (context.fDoSubPosition) { - subX = SkFixedToFloat(glyph.getSubXFixed()); - subY = SkFixedToFloat(glyph.getSubYFixed()); - } - - CGPoint point = CGPointMake(-glyph.left() + subX, glyph.top() + glyph.height() - subY); - // Prior to 10.10, CTFontDrawGlyphs acted like CGContextShowGlyphsAtPositions and took - // 'positions' which are in text space. The glyph location (in device space) must be - // mapped into text space, so that CG can convert it back into device space. - // In 10.10.1, this is handled directly in CTFontDrawGlyphs. - // - // However, in 10.10.2 color glyphs no longer rotate based on the font transform. - // So always make the font transform identity and place the transform on the context. - point = CGPointApplyAffineTransform(point, context.fInvTransform); - - CTFontDrawGlyphs(context.fCTFont.get(), &glyphID, &point, 1, fCG.get()); - - SkASSERT(rowBytesPtr); - *rowBytesPtr = rowBytes; - return image; -} - -unsigned SkScalerContext_Mac::generateGlyphCount(void) { - return fGlyphCount; -} - -bool SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { - return false; -} - -void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { - glyph->fMaskFormat = fRec.fMaskFormat; - - const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(); - glyph->zeroMetrics(); - - // The following block produces cgAdvance in CG units (pixels, y up). - CGSize cgAdvance; - CTFontGetAdvancesForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal, - &cgGlyph, &cgAdvance, 1); - cgAdvance = CGSizeApplyAffineTransform(cgAdvance, fTransform); - glyph->fAdvanceX = CGToFloat(cgAdvance.width); - glyph->fAdvanceY = -CGToFloat(cgAdvance.height); - - // The following produces skBounds in SkGlyph units (pixels, y down), - // or returns early if skBounds would be empty. - SkRect skBounds; - - // Glyphs are always drawn from the horizontal origin. The caller must manually use the result - // of CTFontGetVerticalTranslationsForGlyphs to calculate where to draw the glyph for vertical - // glyphs. As a result, always get the horizontal bounds of a glyph and translate it if the - // glyph is vertical. This avoids any diagreement between the various means of retrieving - // vertical metrics. - { - // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up). - CGRect cgBounds; - CTFontGetBoundingRectsForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal, - &cgGlyph, &cgBounds, 1); - cgBounds = CGRectApplyAffineTransform(cgBounds, fTransform); - - // BUG? - // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when - // it should be empty. So, if we see a zero-advance, we check if it has an - // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance - // is rare, so we won't incur a big performance cost for this extra check. - if (0 == cgAdvance.width && 0 == cgAdvance.height) { - SkUniqueCFRef<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph,nullptr)); - if (!path || CGPathIsEmpty(path.get())) { - return; - } - } - - if (CGRectIsEmpty_inline(cgBounds)) { - return; - } - - // Convert cgBounds to SkGlyph units (pixels, y down). - skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height, - cgBounds.size.width, cgBounds.size.height); - } - - // Currently the bounds are based on being rendered at (0,0). - // The top left must not move, since that is the base from which subpixel positioning is offset. - if (fDoSubPosition) { - skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed()); - skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed()); - } - - // We're trying to pack left and top into int16_t, - // and width and height into uint16_t, after outsetting by 1. - if (!SkRect::MakeXYWH(-32767, -32767, 65535, 65535).contains(skBounds)) { - return; - } - - SkIRect skIBounds; - skBounds.roundOut(&skIBounds); - // Expand the bounds by 1 pixel, to give CG room for anti-aliasing. - // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset - // is not currently known, as CG dilates the outlines by some percentage. - // Note that if this context is A8 and not back-forming from LCD, there is no need to outset. - skIBounds.outset(1, 1); - glyph->fLeft = SkToS16(skIBounds.fLeft); - glyph->fTop = SkToS16(skIBounds.fTop); - glyph->fWidth = SkToU16(skIBounds.width()); - glyph->fHeight = SkToU16(skIBounds.height()); -} - -static constexpr uint8_t sk_pow2_table(size_t i) { - return SkToU8(((i * i + 128) / 255)); -} - -/** - * This will invert the gamma applied by CoreGraphics, so we can get linear - * values. - * - * CoreGraphics obscurely defaults to 2.0 as the subpixel coverage gamma value. - * The color space used does not appear to affect this choice. - */ -static constexpr auto gLinearCoverageFromCGLCDValue = SkMakeArray<256>(sk_pow2_table); - -static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) { - while (count > 0) { - uint8_t mask = 0; - for (int i = 7; i >= 0; --i) { - mask |= ((CGRGBPixel_getAlpha(*src++) >> 7) ^ 0x1) << i; - if (0 == --count) { - break; - } - } - *dst++ = mask; - } -} - -template<bool APPLY_PREBLEND> -static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) { - U8CPU r = 0xFF - ((rgb >> 16) & 0xFF); - U8CPU g = 0xFF - ((rgb >> 8) & 0xFF); - U8CPU b = 0xFF - ((rgb >> 0) & 0xFF); - U8CPU lum = sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8); -#if SK_SHOW_TEXT_BLIT_COVERAGE - lum = std::max(lum, (U8CPU)0x30); -#endif - return lum; -} - -template<bool APPLY_PREBLEND> -void SkScalerContext_Mac::RGBToA8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, - const SkGlyph& glyph, const uint8_t* table8) { - const int width = glyph.fWidth; - size_t dstRB = glyph.rowBytes(); - uint8_t* SK_RESTRICT dst = (uint8_t*)glyph.fImage; - - for (int y = 0; y < glyph.fHeight; y++) { - for (int i = 0; i < width; ++i) { - dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8); - } - cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes); - dst = SkTAddOffset<uint8_t>(dst, dstRB); - } -} - -template<bool APPLY_PREBLEND> -uint16_t SkScalerContext_Mac::RGBToLcd16(CGRGBPixel rgb, const uint8_t* tableR, - const uint8_t* tableG, - const uint8_t* tableB) { - U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 16) & 0xFF), tableR); - U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 8) & 0xFF), tableG); - U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 0) & 0xFF), tableB); -#if SK_SHOW_TEXT_BLIT_COVERAGE - r = std::max(r, (U8CPU)0x30); - g = std::max(g, (U8CPU)0x30); - b = std::max(b, (U8CPU)0x30); -#endif - return SkPack888ToRGB16(r, g, b); -} - -template<bool APPLY_PREBLEND> -void SkScalerContext_Mac::RGBToLcd16(const CGRGBPixel* SK_RESTRICT cgPixels, - size_t cgRowBytes, - const SkGlyph& glyph, - const uint8_t* tableR, - const uint8_t* tableG, - const uint8_t* tableB) { - const int width = glyph.fWidth; - size_t dstRB = glyph.rowBytes(); - uint16_t* SK_RESTRICT dst = (uint16_t*)glyph.fImage; - - for (int y = 0; y < glyph.fHeight; y++) { - for (int i = 0; i < width; i++) { - dst[i] = RGBToLcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB); - } - cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes); - dst = SkTAddOffset<uint16_t>(dst, dstRB); - } -} - -static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb) { - U8CPU a = (rgb >> 24) & 0xFF; - U8CPU r = (rgb >> 16) & 0xFF; - U8CPU g = (rgb >> 8) & 0xFF; - U8CPU b = (rgb >> 0) & 0xFF; -#if SK_SHOW_TEXT_BLIT_COVERAGE - a = std::max(a, (U8CPU)0x30); -#endif - return SkPackARGB32(a, r, g, b); -} - -void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { - CGGlyph cgGlyph = SkTo<CGGlyph>(glyph.getGlyphID()); - - // FIXME: lcd smoothed un-hinted rasterization unsupported. - bool requestSmooth = fRec.getHinting() != SkFontHinting::kNone; - - // Draw the glyph - size_t cgRowBytes; - CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, requestSmooth); - if (cgPixels == nullptr) { - return; - } - - // Fix the glyph - if ((glyph.fMaskFormat == SkMask::kLCD16_Format) || - (glyph.fMaskFormat == SkMask::kA8_Format - && requestSmooth - && smooth_behavior() != SmoothBehavior::none)) - { - const uint8_t* linear = gLinearCoverageFromCGLCDValue.data(); - - //Note that the following cannot really be integrated into the - //pre-blend, since we may not be applying the pre-blend; when we aren't - //applying the pre-blend it means that a filter wants linear anyway. - //Other code may also be applying the pre-blend, so we'd need another - //one with this and one without. - CGRGBPixel* addr = cgPixels; - for (int y = 0; y < glyph.fHeight; ++y) { - for (int x = 0; x < glyph.fWidth; ++x) { - int r = (addr[x] >> 16) & 0xFF; - int g = (addr[x] >> 8) & 0xFF; - int b = (addr[x] >> 0) & 0xFF; - addr[x] = (linear[r] << 16) | (linear[g] << 8) | linear[b]; - } - addr = SkTAddOffset<CGRGBPixel>(addr, cgRowBytes); - } - } - - // Convert glyph to mask - switch (glyph.fMaskFormat) { - case SkMask::kLCD16_Format: { - if (fPreBlend.isApplicable()) { - RGBToLcd16<true>(cgPixels, cgRowBytes, glyph, - fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); - } else { - RGBToLcd16<false>(cgPixels, cgRowBytes, glyph, - fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); - } - } break; - case SkMask::kA8_Format: { - if (fPreBlend.isApplicable()) { - RGBToA8<true>(cgPixels, cgRowBytes, glyph, fPreBlend.fG); - } else { - RGBToA8<false>(cgPixels, cgRowBytes, glyph, fPreBlend.fG); - } - } break; - case SkMask::kBW_Format: { - const int width = glyph.fWidth; - size_t dstRB = glyph.rowBytes(); - uint8_t* dst = (uint8_t*)glyph.fImage; - for (int y = 0; y < glyph.fHeight; y++) { - cgpixels_to_bits(dst, cgPixels, width); - cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes); - dst = SkTAddOffset<uint8_t>(dst, dstRB); - } - } break; - case SkMask::kARGB32_Format: { - const int width = glyph.fWidth; - size_t dstRB = glyph.rowBytes(); - SkPMColor* dst = (SkPMColor*)glyph.fImage; - for (int y = 0; y < glyph.fHeight; y++) { - for (int x = 0; x < width; ++x) { - dst[x] = cgpixels_to_pmcolor(cgPixels[x]); - } - cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes); - dst = SkTAddOffset<SkPMColor>(dst, dstRB); - } - } break; - default: - SkDEBUGFAIL("unexpected mask format"); - break; - } -} - -namespace { -class SkCTPathGeometrySink { - SkPath* fPath; - bool fStarted; - CGPoint fCurrent; - - void goingTo(const CGPoint pt) { - if (!fStarted) { - fStarted = true; - fPath->moveTo(fCurrent.x, -fCurrent.y); - } - fCurrent = pt; - } - - bool currentIsNot(const CGPoint pt) { - return fCurrent.x != pt.x || fCurrent.y != pt.y; - } - -public: - SkCTPathGeometrySink(SkPath* path) : fPath{path}, fStarted{false}, fCurrent{0,0} {} - static void ApplyElement(void *ctx, const CGPathElement *element) { - SkCTPathGeometrySink& self = *(SkCTPathGeometrySink*)ctx; - CGPoint* points = element->points; - - switch (element->type) { - case kCGPathElementMoveToPoint: - self.fStarted = false; - self.fCurrent = points[0]; - break; - - case kCGPathElementAddLineToPoint: - if (self.currentIsNot(points[0])) { - self.goingTo(points[0]); - self.fPath->lineTo(points[0].x, -points[0].y); - } - break; - - case kCGPathElementAddQuadCurveToPoint: - if (self.currentIsNot(points[0]) || self.currentIsNot(points[1])) { - self.goingTo(points[1]); - self.fPath->quadTo(points[0].x, -points[0].y, - points[1].x, -points[1].y); - } - break; - - case kCGPathElementAddCurveToPoint: - if (self.currentIsNot(points[0]) || - self.currentIsNot(points[1]) || - self.currentIsNot(points[2])) - { - self.goingTo(points[2]); - self.fPath->cubicTo(points[0].x, -points[0].y, - points[1].x, -points[1].y, - points[2].x, -points[2].y); - } - break; - - case kCGPathElementCloseSubpath: - if (self.fStarted) { - self.fPath->close(); - } - break; - - default: - SkDEBUGFAIL("Unknown path element!"); - break; - } - } -}; -} // namespace - -/* - * Our subpixel resolution is only 2 bits in each direction, so a scale of 4 - * seems sufficient, and possibly even correct, to allow the hinted outline - * to be subpixel positioned. - */ -#define kScaleForSubPixelPositionHinting (4.0f) - -bool SkScalerContext_Mac::generatePath(SkGlyphID glyph, SkPath* path) { - SkScalar scaleX = SK_Scalar1; - SkScalar scaleY = SK_Scalar1; - - CGAffineTransform xform = fTransform; - /* - * For subpixel positioning, we want to return an unhinted outline, so it - * can be positioned nicely at fractional offsets. However, we special-case - * if the baseline of the (horizontal) text is axis-aligned. In those cases - * we want to retain hinting in the direction orthogonal to the baseline. - * e.g. for horizontal baseline, we want to retain hinting in Y. - * The way we remove hinting is to scale the font by some value (4) in that - * direction, ask for the path, and then scale the path back down. - */ - if (fDoSubPosition) { - // start out by assuming that we want no hining in X and Y - scaleX = scaleY = kScaleForSubPixelPositionHinting; - // now see if we need to restore hinting for axis-aligned baselines - switch (this->computeAxisAlignmentForHText()) { - case kX_SkAxisAlignment: - scaleY = SK_Scalar1; // want hinting in the Y direction - break; - case kY_SkAxisAlignment: - scaleX = SK_Scalar1; // want hinting in the X direction - break; - default: - break; - } - - CGAffineTransform scale(CGAffineTransformMakeScale(ScalarToCG(scaleX), ScalarToCG(scaleY))); - xform = CGAffineTransformConcat(fTransform, scale); - } - - CGGlyph cgGlyph = SkTo<CGGlyph>(glyph); - SkUniqueCFRef<CGPathRef> cgPath(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph, &xform)); - - path->reset(); - if (!cgPath) { - return false; - } - - SkCTPathGeometrySink sink(path); - CGPathApply(cgPath.get(), &sink, SkCTPathGeometrySink::ApplyElement); - if (fDoSubPosition) { - SkMatrix m; - m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY)); - path->transform(m); - } - return true; -} - -void SkScalerContext_Mac::generateFontMetrics(SkFontMetrics* metrics) { - if (nullptr == metrics) { - return; - } - - CGRect theBounds = CTFontGetBoundingBox(fCTFont.get()); - - metrics->fTop = CGToScalar(-CGRectGetMaxY_inline(theBounds)); - metrics->fAscent = CGToScalar(-CTFontGetAscent(fCTFont.get())); - metrics->fDescent = CGToScalar( CTFontGetDescent(fCTFont.get())); - metrics->fBottom = CGToScalar(-CGRectGetMinY_inline(theBounds)); - metrics->fLeading = CGToScalar( CTFontGetLeading(fCTFont.get())); - metrics->fAvgCharWidth = CGToScalar( CGRectGetWidth_inline(theBounds)); - metrics->fXMin = CGToScalar( CGRectGetMinX_inline(theBounds)); - metrics->fXMax = CGToScalar( CGRectGetMaxX_inline(theBounds)); - metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; - metrics->fXHeight = CGToScalar( CTFontGetXHeight(fCTFont.get())); - metrics->fCapHeight = CGToScalar( CTFontGetCapHeight(fCTFont.get())); - metrics->fUnderlineThickness = CGToScalar( CTFontGetUnderlineThickness(fCTFont.get())); - metrics->fUnderlinePosition = -CGToScalar( CTFontGetUnderlinePosition(fCTFont.get())); - - metrics->fFlags = 0; - metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag; - metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag; - - // See https://bugs.chromium.org/p/skia/issues/detail?id=6203 - // At least on 10.12.3 with memory based fonts the x-height is always 0.6666 of the ascent and - // the cap-height is always 0.8888 of the ascent. It appears that the values from the 'OS/2' - // table are read, but then overwritten if the font is not a system font. As a result, if there - // is a valid 'OS/2' table available use the values from the table if they aren't too strange. - struct OS2HeightMetrics { - SK_OT_SHORT sxHeight; - SK_OT_SHORT sCapHeight; - } heights; - size_t bytesRead = this->getTypeface()->getTableData( - SkTEndian_SwapBE32(SkOTTableOS2::TAG), offsetof(SkOTTableOS2, version.v2.sxHeight), - sizeof(heights), &heights); - if (bytesRead == sizeof(heights)) { - // 'fontSize' is correct because the entire resolved size is set by the constructor. - CGFloat fontSize = CTFontGetSize(this->fCTFont.get()); - unsigned upem = CTFontGetUnitsPerEm(this->fCTFont.get()); - unsigned maxSaneHeight = upem * 2; - uint16_t xHeight = SkEndian_SwapBE16(heights.sxHeight); - if (xHeight && xHeight < maxSaneHeight) { - metrics->fXHeight = CGToScalar(xHeight * fontSize / upem); - } - uint16_t capHeight = SkEndian_SwapBE16(heights.sCapHeight); - if (capHeight && capHeight < maxSaneHeight) { - metrics->fCapHeight = CGToScalar(capHeight * fontSize / upem); - } - } -} - -/////////////////////////////////////////////////////////////////////////////// - -// Web fonts added to the CTFont registry do not return their character set. -// Iterate through the font in this case. The existing caller caches the result, -// so the performance impact isn't too bad. -static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount, - SkUnichar* out) { - sk_bzero(out, glyphCount * sizeof(SkUnichar)); - UniChar unichar = 0; - while (glyphCount > 0) { - CGGlyph glyph; - if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) { - if (out[glyph] == 0) { - out[glyph] = unichar; - --glyphCount; - } - } - if (++unichar == 0) { - break; - } - } -} - -static constexpr uint16_t kPlaneSize = 1 << 13; - -static void get_plane_glyph_map(const uint8_t* bits, - CTFontRef ctFont, - CFIndex glyphCount, - SkUnichar* glyphToUnicode, - uint8_t planeIndex) { - SkUnichar planeOrigin = (SkUnichar)planeIndex << 16; // top half of codepoint. - for (uint16_t i = 0; i < kPlaneSize; i++) { - uint8_t mask = bits[i]; - if (!mask) { - continue; - } - for (uint8_t j = 0; j < 8; j++) { - if (0 == (mask & ((uint8_t)1 << j))) { - continue; - } - uint16_t planeOffset = (i << 3) | j; - SkUnichar codepoint = planeOrigin | (SkUnichar)planeOffset; - uint16_t utf16[2] = {planeOffset, 0}; - size_t count = 1; - if (planeOrigin != 0) { - count = SkUTF::ToUTF16(codepoint, utf16); - } - CGGlyph glyphs[2] = {0, 0}; - if (CTFontGetGlyphsForCharacters(ctFont, utf16, glyphs, count)) { - SkASSERT(glyphs[1] == 0); - SkASSERT(glyphs[0] < glyphCount); - // CTFontCopyCharacterSet and CTFontGetGlyphsForCharacters seem to add 'support' - // for characters 0x9, 0xA, and 0xD mapping them to the glyph for character 0x20? - // Prefer mappings to codepoints at or above 0x20. - if (glyphToUnicode[glyphs[0]] < 0x20) { - glyphToUnicode[glyphs[0]] = codepoint; - } - } - } - } -} -// Construct Glyph to Unicode table. -static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount, - SkUnichar* glyphToUnicode) { - sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount); - SkUniqueCFRef<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont)); - if (!charSet) { - populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode); - return; - } - - SkUniqueCFRef<CFDataRef> bitmap( - CFCharacterSetCreateBitmapRepresentation(nullptr, charSet.get())); - if (!bitmap) { - return; - } - CFIndex dataLength = CFDataGetLength(bitmap.get()); - if (!dataLength) { - return; - } - SkASSERT(dataLength >= kPlaneSize); - const UInt8* bits = CFDataGetBytePtr(bitmap.get()); - - get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, 0); - /* - A CFData object that specifies the bitmap representation of the Unicode - character points the for the new character set. The bitmap representation could - contain all the Unicode character range starting from BMP to Plane 16. The - first 8KiB (8192 bytes) of the data represent the BMP range. The BMP range 8KiB - can be followed by zero to sixteen 8KiB bitmaps, each prepended with the plane - index byte. For example, the bitmap representing the BMP and Plane 2 has the - size of 16385 bytes (8KiB for BMP, 1 byte index, and a 8KiB bitmap for Plane - 2). The plane index byte, in this case, contains the integer value two. - */ - - if (dataLength <= kPlaneSize) { - return; - } - int extraPlaneCount = (dataLength - kPlaneSize) / (1 + kPlaneSize); - SkASSERT(dataLength == kPlaneSize + extraPlaneCount * (1 + kPlaneSize)); - while (extraPlaneCount-- > 0) { - bits += kPlaneSize; - uint8_t planeIndex = *bits++; - SkASSERT(planeIndex >= 1); - SkASSERT(planeIndex <= 16); - get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, planeIndex); - } -} - -/** Assumes src and dst are not nullptr. */ -static void CFStringToSkString(CFStringRef src, SkString* dst) { - // Reserve enough room for the worst-case string, - // plus 1 byte for the trailing null. - CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src), - kCFStringEncodingUTF8) + 1; - dst->resize(length); - CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8); - // Resize to the actual UTF-8 length used, stripping the null character. - dst->resize(strlen(dst->c_str())); -} - -void SkTypeface_Mac::getGlyphToUnicodeMap(SkUnichar* dstArray) const { - SkUniqueCFRef<CTFontRef> ctFont = - ctfont_create_exact_copy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()), - fOpszVariation); - CFIndex glyphCount = CTFontGetGlyphCount(ctFont.get()); - populate_glyph_to_unicode(ctFont.get(), glyphCount, dstArray); -} - -std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_Mac::onGetAdvancedMetrics() const { - - SkUniqueCFRef<CTFontRef> ctFont = - ctfont_create_exact_copy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()), - fOpszVariation); - - std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics); - - { - SkUniqueCFRef<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont.get())); - if (fontName.get()) { - CFStringToSkString(fontName.get(), &info->fPostScriptName); - info->fFontName = info->fPostScriptName; - } - } - - // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when - // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always - // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and - // CGFontCopyVariations here until support for 10.10 and earlier is removed. - SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont.get(), nullptr)); - if (cgFont) { - SkUniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get())); - if (cgAxes && CFArrayGetCount(cgAxes.get()) > 0) { - info->fFlags |= SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag; - } - } - - SkOTTableOS2_V4::Type fsType; - if (sizeof(fsType) == this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG), - offsetof(SkOTTableOS2_V4, fsType), - sizeof(fsType), - &fsType)) { - SkOTUtils::SetAdvancedTypefaceFlags(fsType, info.get()); - } - - // If it's not a truetype font, mark it as 'other'. Assume that TrueType - // fonts always have both glyf and loca tables. At the least, this is what - // sfntly needs to subset the font. CTFontCopyAttribute() does not always - // succeed in determining this directly. - if (!this->getTableSize('glyf') || !this->getTableSize('loca')) { - return info; - } - - info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; - CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get()); - if (symbolicTraits & kCTFontMonoSpaceTrait) { - info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; - } - if (symbolicTraits & kCTFontItalicTrait) { - info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style; - } - CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait; - if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) { - info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style; - } else if (stylisticClass & kCTFontScriptsClass) { - info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; - } - info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont.get()); - info->fAscent = (int16_t) CTFontGetAscent(ctFont.get()); - info->fDescent = (int16_t) CTFontGetDescent(ctFont.get()); - info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont.get()); - CGRect bbox = CTFontGetBoundingBox(ctFont.get()); - - SkRect r; - r.setLTRB(CGToScalar(CGRectGetMinX_inline(bbox)), // Left - CGToScalar(CGRectGetMaxY_inline(bbox)), // Top - CGToScalar(CGRectGetMaxX_inline(bbox)), // Right - CGToScalar(CGRectGetMinY_inline(bbox))); // Bottom - - r.roundOut(&(info->fBBox)); - - // Figure out a good guess for StemV - Min width of i, I, !, 1. - // This probably isn't very good with an italic font. - int16_t min_width = SHRT_MAX; - info->fStemV = 0; - static const UniChar stem_chars[] = {'i', 'I', '!', '1'}; - const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]); - CGGlyph glyphs[count]; - CGRect boundingRects[count]; - if (CTFontGetGlyphsForCharacters(ctFont.get(), stem_chars, glyphs, count)) { - CTFontGetBoundingRectsForGlyphs(ctFont.get(), kCTFontOrientationHorizontal, - glyphs, boundingRects, count); - for (size_t i = 0; i < count; i++) { - int16_t width = (int16_t) boundingRects[i].size.width; - if (width > 0 && width < min_width) { - min_width = width; - info->fStemV = min_width; - } - } - } - return info; -} - -/////////////////////////////////////////////////////////////////////////////// - -static SK_SFNT_ULONG get_font_type_tag(CTFontRef ctFont) { - SkUniqueCFRef<CFNumberRef> fontFormatRef( - static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute))); - if (!fontFormatRef) { - return 0; - } - - SInt32 fontFormatValue; - if (!CFNumberGetValue(fontFormatRef.get(), kCFNumberSInt32Type, &fontFormatValue)) { - return 0; - } - - switch (fontFormatValue) { - case kCTFontFormatOpenTypePostScript: - return SkSFNTHeader::fontType_OpenTypeCFF::TAG; - case kCTFontFormatOpenTypeTrueType: - return SkSFNTHeader::fontType_WindowsTrueType::TAG; - case kCTFontFormatTrueType: - return SkSFNTHeader::fontType_MacTrueType::TAG; - case kCTFontFormatPostScript: - return SkSFNTHeader::fontType_PostScript::TAG; - case kCTFontFormatBitmap: - return SkSFNTHeader::fontType_MacTrueType::TAG; - case kCTFontFormatUnrecognized: - default: - return 0; - } -} - -std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenStream(int* ttcIndex) const { - *ttcIndex = 0; - - fInitStream([this]{ - if (fStream) { - return; - } - - SK_SFNT_ULONG fontType = get_font_type_tag(fFontRef.get()); - - // get table tags - int numTables = this->countTables(); - SkTDArray<SkFontTableTag> tableTags; - tableTags.setCount(numTables); - this->getTableTags(tableTags.begin()); - - // CT seems to be unreliable in being able to obtain the type, - // even if all we want is the first four bytes of the font resource. - // Just the presence of the FontForge 'FFTM' table seems to throw it off. - if (fontType == 0) { - fontType = SkSFNTHeader::fontType_WindowsTrueType::TAG; - - // see https://skbug.com/7630#c7 - bool couldBeCFF = false; - constexpr SkFontTableTag CFFTag = SkSetFourByteTag('C', 'F', 'F', ' '); - constexpr SkFontTableTag CFF2Tag = SkSetFourByteTag('C', 'F', 'F', '2'); - for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { - if (CFFTag == tableTags[tableIndex] || CFF2Tag == tableTags[tableIndex]) { - couldBeCFF = true; - } - } - if (couldBeCFF) { - fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG; - } - } - - // Sometimes CoreGraphics incorrectly thinks a font is kCTFontFormatPostScript. - // It is exceedingly unlikely that this is the case, so double check - // (see https://crbug.com/809763 ). - if (fontType == SkSFNTHeader::fontType_PostScript::TAG) { - // see if there are any required 'typ1' tables (see Adobe Technical Note #5180) - bool couldBeTyp1 = false; - constexpr SkFontTableTag TYPE1Tag = SkSetFourByteTag('T', 'Y', 'P', '1'); - constexpr SkFontTableTag CIDTag = SkSetFourByteTag('C', 'I', 'D', ' '); - for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { - if (TYPE1Tag == tableTags[tableIndex] || CIDTag == tableTags[tableIndex]) { - couldBeTyp1 = true; - } - } - if (!couldBeTyp1) { - fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG; - } - } - - // get the table sizes and accumulate the total size of the font - SkTDArray<size_t> tableSizes; - size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables; - for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { - size_t tableSize = this->getTableSize(tableTags[tableIndex]); - totalSize += (tableSize + 3) & ~3; - *tableSizes.append() = tableSize; - } - - // reserve memory for stream, and zero it (tables must be zero padded) - fStream.reset(new SkMemoryStream(totalSize)); - char* dataStart = (char*)fStream->getMemoryBase(); - sk_bzero(dataStart, totalSize); - char* dataPtr = dataStart; - - // compute font header entries - uint16_t entrySelector = 0; - uint16_t searchRange = 1; - while (searchRange < numTables >> 1) { - entrySelector++; - searchRange <<= 1; - } - searchRange <<= 4; - uint16_t rangeShift = (numTables << 4) - searchRange; - - // write font header - SkSFNTHeader* header = (SkSFNTHeader*)dataPtr; - header->fontType = fontType; - header->numTables = SkEndian_SwapBE16(numTables); - header->searchRange = SkEndian_SwapBE16(searchRange); - header->entrySelector = SkEndian_SwapBE16(entrySelector); - header->rangeShift = SkEndian_SwapBE16(rangeShift); - dataPtr += sizeof(SkSFNTHeader); - - // write tables - SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr; - dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables; - for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { - size_t tableSize = tableSizes[tableIndex]; - this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr); - entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]); - entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr, - tableSize)); - entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart)); - entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize)); - - dataPtr += (tableSize + 3) & ~3; - ++entry; - } - }); - return fStream->duplicate(); -} - -struct NonDefaultAxesContext { - SkFixed* axisValue; - CFArrayRef cgAxes; -}; -static void set_non_default_axes(CFTypeRef key, CFTypeRef value, void* context) { - NonDefaultAxesContext* self = static_cast<NonDefaultAxesContext*>(context); - - if (CFGetTypeID(key) != CFStringGetTypeID() || CFGetTypeID(value) != CFNumberGetTypeID()) { - return; - } - - // The key is a CFString which is a string from the 'name' table. - // Search the cgAxes for an axis with this name, and use its index to store the value. - CFIndex keyIndex = -1; - CFStringRef keyString = static_cast<CFStringRef>(key); - for (CFIndex i = 0; i < CFArrayGetCount(self->cgAxes); ++i) { - CFTypeRef cgAxis = CFArrayGetValueAtIndex(self->cgAxes, i); - if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) { - continue; - } - - CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis); - CFTypeRef cgAxisName = CFDictionaryGetValue(cgAxisDict, kCGFontVariationAxisName); - if (!cgAxisName || CFGetTypeID(cgAxisName) != CFStringGetTypeID()) { - continue; - } - CFStringRef cgAxisNameString = static_cast<CFStringRef>(cgAxisName); - if (CFStringCompare(keyString, cgAxisNameString, 0) == kCFCompareEqualTo) { - keyIndex = i; - break; - } - } - if (keyIndex == -1) { - return; - } - - CFNumberRef valueNumber = static_cast<CFNumberRef>(value); - double valueDouble; - if (!CFNumberGetValue(valueNumber, kCFNumberDoubleType, &valueDouble) || - valueDouble < SkFixedToDouble(SK_FixedMin) || SkFixedToDouble(SK_FixedMax) < valueDouble) - { - return; - } - self->axisValue[keyIndex] = SkDoubleToFixed(valueDouble); -} -static bool get_variations(CTFontRef ctFont, CFIndex* cgAxisCount, - SkAutoSTMalloc<4, SkFixed>* axisValues) -{ - // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when - // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always - // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and - // CGFontCopyVariations here until support for 10.10 and earlier is removed. - SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr)); - if (!cgFont) { - return false; - } - - SkUniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get())); - // If a font has no variations CGFontCopyVariations returns nullptr (instead of an empty dict). - if (!cgVariations) { - return false; - } - - SkUniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get())); - if (!cgAxes) { - return false; - } - *cgAxisCount = CFArrayGetCount(cgAxes.get()); - axisValues->reset(*cgAxisCount); - - // Set all of the axes to their default values. - // Fail if any default value cannot be determined. - for (CFIndex i = 0; i < *cgAxisCount; ++i) { - CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes.get(), i); - if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) { - return false; - } - - CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis); - CFTypeRef axisDefaultValue = CFDictionaryGetValue(cgAxisDict, - kCGFontVariationAxisDefaultValue); - if (!axisDefaultValue || CFGetTypeID(axisDefaultValue) != CFNumberGetTypeID()) { - return false; - } - CFNumberRef axisDefaultValueNumber = static_cast<CFNumberRef>(axisDefaultValue); - double axisDefaultValueDouble; - if (!CFNumberGetValue(axisDefaultValueNumber, kCFNumberDoubleType, &axisDefaultValueDouble)) - { - return false; - } - if (axisDefaultValueDouble < SkFixedToDouble(SK_FixedMin) || - SkFixedToDouble(SK_FixedMax) < axisDefaultValueDouble) - { - return false; - } - (*axisValues)[(int)i] = SkDoubleToFixed(axisDefaultValueDouble); - } - - // Override the default values with the given font's stated axis values. - NonDefaultAxesContext c = { axisValues->get(), cgAxes.get() }; - CFDictionaryApplyFunction(cgVariations.get(), set_non_default_axes, &c); - - return true; -} -std::unique_ptr<SkFontData> SkTypeface_Mac::onMakeFontData() const { - int index; - std::unique_ptr<SkStreamAsset> stream(this->onOpenStream(&index)); - - CFIndex cgAxisCount; - SkAutoSTMalloc<4, SkFixed> axisValues; - if (get_variations(fFontRef.get(), &cgAxisCount, &axisValues)) { - return std::make_unique<SkFontData>(std::move(stream), index, - axisValues.get(), cgAxisCount); - } - return std::make_unique<SkFontData>(std::move(stream), index, nullptr, 0); -} - -/** Creates a CT variation dictionary {tag, value} from a CG variation dictionary {name, value}. */ -static SkUniqueCFRef<CFDictionaryRef> ct_variation_from_cg_variation(CFDictionaryRef cgVariations, - CFArrayRef ctAxes) { - - SkUniqueCFRef<CFMutableDictionaryRef> ctVariation( - CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - CFIndex axisCount = CFArrayGetCount(ctAxes); - for (CFIndex i = 0; i < axisCount; ++i) { - CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes, i); - if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { - return nullptr; - } - CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); - - // The assumption is that values produced by kCTFontVariationAxisNameKey and - // kCGFontVariationAxisName will always be equal. - CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey); - if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) { - return nullptr; - } - - CFTypeRef axisValue = CFDictionaryGetValue(cgVariations, axisName); - if (!axisValue || CFGetTypeID(axisValue) != CFNumberGetTypeID()) { - return nullptr; - } - - CFTypeRef axisTag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); - if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) { - return nullptr; - } - - CFDictionaryAddValue(ctVariation.get(), axisTag, axisValue); - } - return std::move(ctVariation); -} - -int SkTypeface_Mac::onGetVariationDesignPosition( - SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const -{ - // The CGFont variation data does not contain the tag. - - // CTFontCopyVariationAxes returns nullptr for CGFontCreateWithDataProvider fonts with - // macOS 10.10 and iOS 9 or earlier. When this happens, there is no API to provide the tag. - SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get())); - if (!ctAxes) { - return -1; - } - CFIndex axisCount = CFArrayGetCount(ctAxes.get()); - if (!coordinates || coordinateCount < axisCount) { - return axisCount; - } - - // This call always returns nullptr on 10.11 and under for CGFontCreateWithDataProvider fonts. - // When this happens, try converting the CG variation to a CT variation. - // On 10.12 and later, this only returns non-default variations. - SkUniqueCFRef<CFDictionaryRef> ctVariation(CTFontCopyVariation(fFontRef.get())); - if (!ctVariation) { - // When 10.11 and earlier are no longer supported, the following code can be replaced with - // return -1 and ct_variation_from_cg_variation can be removed. - SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr)); - if (!cgFont) { - return -1; - } - SkUniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get())); - if (!cgVariations) { - return -1; - } - ctVariation = ct_variation_from_cg_variation(cgVariations.get(), ctAxes.get()); - if (!ctVariation) { - return -1; - } - } - - for (int i = 0; i < axisCount; ++i) { - CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); - if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { - return -1; - } - CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); - - CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); - if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { - return -1; - } - CFNumberRef tagNumber = static_cast<CFNumberRef>(tag); - int64_t tagLong; - if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { - return -1; - } - coordinates[i].axis = tagLong; - - CGFloat variationCGFloat; - CFTypeRef variationValue = CFDictionaryGetValue(ctVariation.get(), tagNumber); - if (variationValue) { - if (CFGetTypeID(variationValue) != CFNumberGetTypeID()) { - return -1; - } - CFNumberRef variationNumber = static_cast<CFNumberRef>(variationValue); - if (!CFNumberGetValue(variationNumber, kCFNumberCGFloatType, &variationCGFloat)) { - return -1; - } - } else { - CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey); - if (!def || CFGetTypeID(def) != CFNumberGetTypeID()) { - return -1; - } - CFNumberRef defNumber = static_cast<CFNumberRef>(def); - if (!CFNumberGetValue(defNumber, kCFNumberCGFloatType, &variationCGFloat)) { - return -1; - } - } - coordinates[i].value = CGToScalar(variationCGFloat); - - } - return axisCount; -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -int SkTypeface_Mac::onGetUPEM() const { - SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr)); - return CGFontGetUnitsPerEm(cgFont.get()); -} - -SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const { - sk_sp<SkTypeface::LocalizedStrings> nameIter = - SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this); - if (!nameIter) { - CFStringRef cfLanguageRaw; - SkUniqueCFRef<CFStringRef> cfFamilyName( - CTFontCopyLocalizedName(fFontRef.get(), kCTFontFamilyNameKey, &cfLanguageRaw)); - SkUniqueCFRef<CFStringRef> cfLanguage(cfLanguageRaw); - - SkString skLanguage; - SkString skFamilyName; - if (cfLanguage) { - CFStringToSkString(cfLanguage.get(), &skLanguage); - } else { - skLanguage = "und"; //undetermined - } - if (cfFamilyName) { - CFStringToSkString(cfFamilyName.get(), &skFamilyName); - } - - nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(skFamilyName, skLanguage); - } - return nameIter.release(); -} - -int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const { - SkUniqueCFRef<CFArrayRef> cfArray( - CTFontCopyAvailableTables(fFontRef.get(), kCTFontTableOptionNoOptions)); - if (!cfArray) { - return 0; - } - int count = SkToInt(CFArrayGetCount(cfArray.get())); - if (tags) { - for (int i = 0; i < count; ++i) { - uintptr_t fontTag = reinterpret_cast<uintptr_t>( - CFArrayGetValueAtIndex(cfArray.get(), i)); - tags[i] = static_cast<SkFontTableTag>(fontTag); - } - } - return count; -} - -// If, as is the case with web fonts, the CTFont data isn't available, -// the CGFont data may work. While the CGFont may always provide the -// right result, leave the CTFont code path to minimize disruption. -static SkUniqueCFRef<CFDataRef> copy_table_from_font(CTFontRef ctFont, SkFontTableTag tag) { - SkUniqueCFRef<CFDataRef> data(CTFontCopyTable(ctFont, (CTFontTableTag) tag, - kCTFontTableOptionNoOptions)); - if (!data) { - SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr)); - data.reset(CGFontCopyTableForTag(cgFont.get(), tag)); - } - return data; -} - -size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset, - size_t length, void* dstData) const { - SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag); - if (!srcData) { - return 0; - } - - size_t srcSize = CFDataGetLength(srcData.get()); - if (offset >= srcSize) { - return 0; - } - if (length > srcSize - offset) { - length = srcSize - offset; - } - if (dstData) { - memcpy(dstData, CFDataGetBytePtr(srcData.get()) + offset, length); - } - return length; -} - -sk_sp<SkData> SkTypeface_Mac::onCopyTableData(SkFontTableTag tag) const { - SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag); - if (!srcData) { - return nullptr; - } - const UInt8* data = CFDataGetBytePtr(srcData.get()); - CFIndex length = CFDataGetLength(srcData.get()); - return SkData::MakeWithProc(data, length, - [](const void*, void* ctx) { - CFRelease((CFDataRef)ctx); - }, (void*)srcData.release()); -} - -SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkScalerContextEffects& effects, - const SkDescriptor* desc) const { - return new SkScalerContext_Mac(sk_ref_sp(const_cast<SkTypeface_Mac*>(this)), effects, desc); -} - -void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const { - if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag || - rec->fFlags & SkScalerContext::kLCD_Vertical_Flag) - { - rec->fMaskFormat = SkMask::kA8_Format; - // Render the glyphs as close as possible to what was requested. - // The above turns off subpixel rendering, but the user requested it. - // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks. - // See comments below for more details. - rec->setHinting(SkFontHinting::kNormal); - } - - unsigned flagsWeDontSupport = SkScalerContext::kForceAutohinting_Flag | - SkScalerContext::kLCD_BGROrder_Flag | - SkScalerContext::kLCD_Vertical_Flag; - - rec->fFlags &= ~flagsWeDontSupport; - - const SmoothBehavior smoothBehavior = smooth_behavior(); - - // Only two levels of hinting are supported. - // kNo_Hinting means avoid CoreGraphics outline dilation (smoothing). - // kNormal_Hinting means CoreGraphics outline dilation (smoothing) is allowed. - if (rec->getHinting() != SkFontHinting::kNone) { - rec->setHinting(SkFontHinting::kNormal); - } - // If smoothing has no effect, don't request it. - if (smoothBehavior == SmoothBehavior::none) { - rec->setHinting(SkFontHinting::kNone); - } - - // FIXME: lcd smoothed un-hinted rasterization unsupported. - // Tracked by http://code.google.com/p/skia/issues/detail?id=915 . - // There is no current means to honor a request for unhinted lcd, - // so arbitrarilly ignore the hinting request and honor lcd. - - // Hinting and smoothing should be orthogonal, but currently they are not. - // CoreGraphics has no API to influence hinting. However, its lcd smoothed - // output is drawn from auto-dilated outlines (the amount of which is - // determined by AppleFontSmoothing). Its regular anti-aliased output is - // drawn from un-dilated outlines. - - // The behavior of Skia is as follows: - // [AA][no-hint]: generate AA using CoreGraphic's AA output. - // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single - // channel. This matches [LCD][yes-hint] in weight. - // [LCD][no-hint]: curently unable to honor, and must pick which to respect. - // Currenly side with LCD, effectively ignoring the hinting setting. - // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output. - if (rec->fMaskFormat == SkMask::kLCD16_Format) { - if (smoothBehavior == SmoothBehavior::subpixel) { - //CoreGraphics creates 555 masks for smoothed text anyway. - rec->fMaskFormat = SkMask::kLCD16_Format; - rec->setHinting(SkFontHinting::kNormal); - } else { - rec->fMaskFormat = SkMask::kA8_Format; - if (smoothBehavior != SmoothBehavior::none) { - rec->setHinting(SkFontHinting::kNormal); - } - } - } - - // CoreText provides no information as to whether a glyph will be color or not. - // Fonts may mix outlines and bitmaps, so information is needed on a glyph by glyph basis. - // If a font contains an 'sbix' table, consider it to be a color font, and disable lcd. - if (fHasColorGlyphs) { - rec->fMaskFormat = SkMask::kARGB32_Format; - } - - // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8. - // All other masks can use regular gamma. - if (SkMask::kA8_Format == rec->fMaskFormat && SkFontHinting::kNone == rec->getHinting()) { -#ifndef SK_GAMMA_APPLY_TO_A8 - // SRGBTODO: Is this correct? Do we want contrast boost? - rec->ignorePreBlend(); -#endif - } else { - SkColor color = rec->getLuminanceColor(); - if (smoothBehavior == SmoothBehavior::some) { - // CoreGraphics smoothed text without subpixel coverage blitting goes from a gamma of - // 2.0 for black foreground to a gamma of 1.0 for white foreground. Emulate this - // through the mask gamma by reducing the color values to 1/2. - color = SkColorSetRGB(SkColorGetR(color) * 1/2, - SkColorGetG(color) * 1/2, - SkColorGetB(color) * 1/2); - } else if (smoothBehavior == SmoothBehavior::subpixel) { - // CoreGraphics smoothed text with subpixel coverage blitting goes from a gamma of - // 2.0 for black foreground to a gamma of ~1.4? for white foreground. Emulate this - // through the mask gamma by reducing the color values to 3/4. - color = SkColorSetRGB(SkColorGetR(color) * 3/4, - SkColorGetG(color) * 3/4, - SkColorGetB(color) * 3/4); - } - rec->setLuminanceColor(color); - - // CoreGraphics dialates smoothed text to provide contrast. - rec->setContrast(0); - } -} - -/** Takes ownership of the CFStringRef. */ -static const char* get_str(CFStringRef ref, SkString* str) { - if (nullptr == ref) { - return nullptr; - } - CFStringToSkString(ref, str); - CFRelease(ref); - return str->c_str(); -} - -void SkTypeface_Mac::onGetFamilyName(SkString* familyName) const { - get_str(CTFontCopyFamilyName(fFontRef.get()), familyName); -} - -void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc, - bool* isLocalStream) const { - SkString tmpStr; - - desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef.get()), &tmpStr)); - desc->setFullName(get_str(CTFontCopyFullName(fFontRef.get()), &tmpStr)); - desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef.get()), &tmpStr)); - desc->setStyle(this->fontStyle()); - *isLocalStream = fIsFromStream; -} - -void SkTypeface_Mac::onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const { - // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points: - // When a surrogate pair is detected, the glyph index used is the index of the high surrogate. - // It is documented that if a mapping is unavailable, the glyph will be set to 0. - - SkAutoSTMalloc<1024, UniChar> charStorage; - const UniChar* src; // UniChar is a UTF-16 16-bit code unit. - int srcCount; - const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(uni); - UniChar* utf16 = charStorage.reset(2 * count); - src = utf16; - for (int i = 0; i < count; ++i) { - utf16 += SkUTF::ToUTF16(utf32[i], utf16); - } - srcCount = SkToInt(utf16 - src); - - // If there are any non-bmp code points, the provided 'glyphs' storage will be inadequate. - SkAutoSTMalloc<1024, uint16_t> glyphStorage; - uint16_t* macGlyphs = glyphs; - if (srcCount > count) { - macGlyphs = glyphStorage.reset(srcCount); - } - - CTFontGetGlyphsForCharacters(fFontRef.get(), src, macGlyphs, srcCount); - - // If there were any non-bmp, then copy and compact. - // If all are bmp, 'glyphs' already contains the compact glyphs. - // If some are non-bmp, copy and compact into 'glyphs'. - if (srcCount > count) { - SkASSERT(glyphs != macGlyphs); - int extra = 0; - for (int i = 0; i < count; ++i) { - glyphs[i] = macGlyphs[i + extra]; - if (SkUTF16_IsLeadingSurrogate(src[i + extra])) { - ++extra; - } - } - } else { - SkASSERT(glyphs == macGlyphs); - } -} - -int SkTypeface_Mac::onCountGlyphs() const { - return SkToInt(CTFontGetGlyphCount(fFontRef.get())); -} - -/////////////////////////////////////////////////////////////////////////////// -/////////////////////////////////////////////////////////////////////////////// - -namespace { - -struct CTFontVariation { - SkUniqueCFRef<CFDictionaryRef> dict; - OpszVariation opsz; -}; - -/** Creates a dictionary suitable for setting the axes on a CTFont. */ -static CTFontVariation ctvariation_from_skfontarguments(CTFontRef ct, - const SkFontArguments& args) -{ - OpszVariation opsz; - constexpr const SkFourByteTag opszTag = SkSetFourByteTag('o','p','s','z'); - - SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct)); - if (!ctAxes) { - return CTFontVariation(); - } - CFIndex axisCount = CFArrayGetCount(ctAxes.get()); - - const SkFontArguments::VariationPosition position = args.getVariationDesignPosition(); - - SkUniqueCFRef<CFMutableDictionaryRef> dict( - CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - for (int i = 0; i < axisCount; ++i) { - CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); - if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { - return CTFontVariation(); - } - CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); - - CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); - if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { - return CTFontVariation(); - } - CFNumberRef tagNumber = static_cast<CFNumberRef>(tag); - int64_t tagLong; - if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { - return CTFontVariation(); - } - - // The variation axes can be set to any value, but cg will effectively pin them. - // Pin them here to normalize. - CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey); - CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey); - CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey); - if (!min || CFGetTypeID(min) != CFNumberGetTypeID() || - !max || CFGetTypeID(max) != CFNumberGetTypeID() || - !def || CFGetTypeID(def) != CFNumberGetTypeID()) - { - return CTFontVariation(); - } - CFNumberRef minNumber = static_cast<CFNumberRef>(min); - CFNumberRef maxNumber = static_cast<CFNumberRef>(max); - CFNumberRef defNumber = static_cast<CFNumberRef>(def); - double minDouble; - double maxDouble; - double defDouble; - if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) || - !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble) || - !CFNumberGetValue(defNumber, kCFNumberDoubleType, &defDouble)) - { - return CTFontVariation(); - } - - double value = defDouble; - // The position may be over specified. If there are multiple values for a given axis, - // use the last one since that's what css-fonts-4 requires. - for (int j = position.coordinateCount; j --> 0;) { - if (position.coordinates[j].axis == tagLong) { - value = SkTPin(SkScalarToDouble(position.coordinates[j].value), - minDouble, maxDouble); - if (tagLong == opszTag) { - opsz.isSet = true; - } - break; - } - } - if (tagLong == opszTag) { - opsz.value = value; - } - SkUniqueCFRef<CFNumberRef> valueNumber( - CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value)); - CFDictionaryAddValue(dict.get(), tagNumber, valueNumber.get()); - } - return { SkUniqueCFRef<CFDictionaryRef>(std::move(dict)), opsz }; -} - -/** Creates a dictionary suitable for setting the axes on a CTFont. */ -static CTFontVariation ctvariation_from_skfontdata(CTFontRef ct, SkFontData* fontData) { - // In macOS 10.15 CTFontCreate* overrides any 'opsz' variation with the 'size'. - // Track the 'opsz' and return it, since it is an out of band axis. - OpszVariation opsz; - constexpr const SkFourByteTag opszTag = SkSetFourByteTag('o','p','s','z'); - - SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct)); - if (!ctAxes) { - return CTFontVariation(); - } - - CFIndex axisCount = CFArrayGetCount(ctAxes.get()); - if (0 == axisCount || axisCount != fontData->getAxisCount()) { - return CTFontVariation(); - } - - SkUniqueCFRef<CFMutableDictionaryRef> dict( - CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - for (int i = 0; i < fontData->getAxisCount(); ++i) { - CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); - if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { - return CTFontVariation(); - } - CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); - - CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, - kCTFontVariationAxisIdentifierKey); - if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { - return CTFontVariation(); - } - CFNumberRef tagNumber = static_cast<CFNumberRef>(tag); - int64_t tagLong; - if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { - return CTFontVariation(); - } - - // The variation axes can be set to any value, but cg will effectively pin them. - // Pin them here to normalize. - CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey); - CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey); - if (!min || CFGetTypeID(min) != CFNumberGetTypeID() || - !max || CFGetTypeID(max) != CFNumberGetTypeID()) - { - return CTFontVariation(); - } - CFNumberRef minNumber = static_cast<CFNumberRef>(min); - CFNumberRef maxNumber = static_cast<CFNumberRef>(max); - double minDouble; - double maxDouble; - if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) || - !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble)) - { - return CTFontVariation(); - } - double value = SkTPin(SkFixedToDouble(fontData->getAxis()[i]), minDouble, maxDouble); - - if (tagLong == opszTag) { - opsz.isSet = true; - opsz.value = value; - } - - SkUniqueCFRef<CFNumberRef> valueNumber( - CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value)); - CFDictionaryAddValue(dict.get(), tagNumber, valueNumber.get()); - } - return { SkUniqueCFRef<CFDictionaryRef>(std::move(dict)), opsz }; -} - -static sk_sp<SkData> skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream) { - size_t size = stream->getLength(); - if (const void* base = stream->getMemoryBase()) { - return SkData::MakeWithProc(base, size, - [](const void*, void* ctx) -> void { - delete (SkStreamAsset*)ctx; - }, stream.release()); - } - return SkData::MakeFromStream(stream.get(), size); -} - -static SkUniqueCFRef<CFDataRef> cfdata_from_skdata(sk_sp<SkData> data) { - void const * const addr = data->data(); - size_t const size = data->size(); - - CFAllocatorContext ctx = { - 0, // CFIndex version - data.release(), // void* info - nullptr, // const void *(*retain)(const void *info); - nullptr, // void (*release)(const void *info); - nullptr, // CFStringRef (*copyDescription)(const void *info); - nullptr, // void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info); - nullptr, // void*(*reallocate)(void* ptr,CFIndex newsize,CFOptionFlags hint,void* info); - [](void*,void* info) -> void { // void (*deallocate)(void *ptr, void *info); - SkASSERT(info); - ((SkData*)info)->unref(); - }, - nullptr, // CFIndex (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info); - }; - SkUniqueCFRef<CFAllocatorRef> alloc(CFAllocatorCreate(kCFAllocatorDefault, &ctx)); - return SkUniqueCFRef<CFDataRef>(CFDataCreateWithBytesNoCopy( - kCFAllocatorDefault, (const UInt8 *)addr, size, alloc.get())); -} - -static SkUniqueCFRef<CTFontRef> ctfont_from_skdata(sk_sp<SkData> data, int ttcIndex) { - // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available. - if (ttcIndex != 0) { - return nullptr; - } - - SkUniqueCFRef<CFDataRef> cfData(cfdata_from_skdata(std::move(data))); - - SkUniqueCFRef<CTFontDescriptorRef> desc( - CTFontManagerCreateFontDescriptorFromData(cfData.get())); - if (!desc) { - return nullptr; - } - return SkUniqueCFRef<CTFontRef>(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr)); -} - -static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) { - SkUniqueCFRef<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name)); - if (!ref) { - return false; - } - CFStringToSkString(ref.get(), value); - return true; -} - -static inline int sqr(int value) { - SkASSERT(SkAbs32(value) < 0x7FFF); // check for overflow - return value * value; -} - -// We normalize each axis (weight, width, italic) to be base-900 -static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) { - return sqr(a.weight() - b.weight()) + - sqr((a.width() - b.width()) * 100) + - sqr((a.slant() != b.slant()) * 900); -} - -class SkFontStyleSet_Mac : public SkFontStyleSet { -public: - SkFontStyleSet_Mac(CTFontDescriptorRef desc) - : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, nullptr)) - , fCount(0) - { - if (!fArray) { - fArray.reset(CFArrayCreate(nullptr, nullptr, 0, nullptr)); - } - fCount = SkToInt(CFArrayGetCount(fArray.get())); - } - - int count() override { - return fCount; - } - - void getStyle(int index, SkFontStyle* style, SkString* name) override { - SkASSERT((unsigned)index < (unsigned)fCount); - CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index); - if (style) { - *style = fontstyle_from_descriptor(desc, false); - } - if (name) { - if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) { - name->reset(); - } - } - } - - SkTypeface* createTypeface(int index) override { - SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray.get())); - CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index); - - return create_from_desc(desc).release(); - } - - SkTypeface* matchStyle(const SkFontStyle& pattern) override { - if (0 == fCount) { - return nullptr; - } - return create_from_desc(findMatchingDesc(pattern)).release(); - } - -private: - SkUniqueCFRef<CFArrayRef> fArray; - int fCount; - - CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const { - int bestMetric = SK_MaxS32; - CTFontDescriptorRef bestDesc = nullptr; - - for (int i = 0; i < fCount; ++i) { - CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), i); - int metric = compute_metric(pattern, fontstyle_from_descriptor(desc, false)); - if (0 == metric) { - return desc; - } - if (metric < bestMetric) { - bestMetric = metric; - bestDesc = desc; - } - } - SkASSERT(bestDesc); - return bestDesc; - } -}; - -} // namespace - -sk_sp<SkTypeface> SkTypeface_Mac::onMakeClone(const SkFontArguments& args) const { - CTFontVariation ctVariation = ctvariation_from_skfontarguments(fFontRef.get(), args); - - SkUniqueCFRef<CTFontRef> ctVariant; - if (ctVariation.dict) { - SkUniqueCFRef<CFMutableDictionaryRef> attributes( - CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - CFDictionaryAddValue(attributes.get(), - kCTFontVariationAttribute, ctVariation.dict.get()); - SkUniqueCFRef<CTFontDescriptorRef> varDesc( - CTFontDescriptorCreateWithAttributes(attributes.get())); - ctVariant.reset(CTFontCreateCopyWithAttributes(fFontRef.get(), 0, nullptr, varDesc.get())); - } else { - ctVariant.reset((CTFontRef)CFRetain(fFontRef.get())); - } - if (!ctVariant) { - return nullptr; - } - - return create_from_CTFontRef(std::move(ctVariant), ctVariation.opsz, - fStream ? fStream->duplicate() : nullptr); -} - -int SkTypeface_Mac::onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], - int parameterCount) const -{ - SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get())); - if (!ctAxes) { - return -1; - } - CFIndex axisCount = CFArrayGetCount(ctAxes.get()); - - if (!parameters || parameterCount < axisCount) { - return axisCount; - } - - // Added in 10.13 - CFStringRef* kCTFontVariationAxisHiddenKeyPtr = - static_cast<CFStringRef*>(dlsym(RTLD_DEFAULT, "kCTFontVariationAxisHiddenKey")); - - for (int i = 0; i < axisCount; ++i) { - CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); - if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { - return -1; - } - CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); - - CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); - if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { - return -1; - } - CFNumberRef tagNumber = static_cast<CFNumberRef>(tag); - int64_t tagLong; - if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { - return -1; - } - - CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey); - CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey); - CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey); - if (!min || CFGetTypeID(min) != CFNumberGetTypeID() || - !max || CFGetTypeID(max) != CFNumberGetTypeID() || - !def || CFGetTypeID(def) != CFNumberGetTypeID()) - { - return -1; - } - CFNumberRef minNumber = static_cast<CFNumberRef>(min); - CFNumberRef maxNumber = static_cast<CFNumberRef>(max); - CFNumberRef defNumber = static_cast<CFNumberRef>(def); - double minDouble; - double maxDouble; - double defDouble; - if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) || - !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble) || - !CFNumberGetValue(defNumber, kCFNumberDoubleType, &defDouble)) - { - return -1; - } - - SkFontParameters::Variation::Axis& skAxis = parameters[i]; - skAxis.tag = tagLong; - skAxis.min = minDouble; - skAxis.max = maxDouble; - skAxis.def = defDouble; - skAxis.setHidden(false); - if (kCTFontVariationAxisHiddenKeyPtr) { - CFTypeRef hidden = CFDictionaryGetValue(axisInfoDict,*kCTFontVariationAxisHiddenKeyPtr); - if (hidden) { - if (CFGetTypeID(hidden) != CFBooleanGetTypeID()) { - return -1; - } - CFBooleanRef hiddenBoolean = static_cast<CFBooleanRef>(hidden); - skAxis.setHidden(CFBooleanGetValue(hiddenBoolean)); - } - } - } - return axisCount; -} - -class SkFontMgr_Mac : public SkFontMgr { - SkUniqueCFRef<CFArrayRef> fNames; - int fCount; - - CFStringRef getFamilyNameAt(int index) const { - SkASSERT((unsigned)index < (unsigned)fCount); - return (CFStringRef)CFArrayGetValueAtIndex(fNames.get(), index); - } - - static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) { - SkUniqueCFRef<CFMutableDictionaryRef> cfAttr( - CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - CFDictionaryAddValue(cfAttr.get(), kCTFontFamilyNameAttribute, cfFamilyName); - - SkUniqueCFRef<CTFontDescriptorRef> desc( - CTFontDescriptorCreateWithAttributes(cfAttr.get())); - return new SkFontStyleSet_Mac(desc.get()); - } - - /** CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we - * provide a wrapper here that will return an empty array if need be. - */ - static SkUniqueCFRef<CFArrayRef> CopyAvailableFontFamilyNames() { -#ifdef SK_BUILD_FOR_IOS - return SkUniqueCFRef<CFArrayRef>(CFArrayCreate(nullptr, nullptr, 0, nullptr)); -#else - return SkUniqueCFRef<CFArrayRef>(CTFontManagerCopyAvailableFontFamilyNames()); -#endif - } - -public: - SkFontMgr_Mac() - : fNames(CopyAvailableFontFamilyNames()) - , fCount(fNames ? SkToInt(CFArrayGetCount(fNames.get())) : 0) {} - -protected: - int onCountFamilies() const override { - return fCount; - } - - void onGetFamilyName(int index, SkString* familyName) const override { - if ((unsigned)index < (unsigned)fCount) { - CFStringToSkString(this->getFamilyNameAt(index), familyName); - } else { - familyName->reset(); - } - } - - SkFontStyleSet* onCreateStyleSet(int index) const override { - if ((unsigned)index >= (unsigned)fCount) { - return nullptr; - } - return CreateSet(this->getFamilyNameAt(index)); - } - - SkFontStyleSet* onMatchFamily(const char familyName[]) const override { - if (!familyName) { - return nullptr; - } - SkUniqueCFRef<CFStringRef> cfName = make_CFString(familyName); - return CreateSet(cfName.get()); - } - - SkTypeface* onMatchFamilyStyle(const char familyName[], - const SkFontStyle& style) const override { - SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style); - return create_from_desc(desc.get()).release(); - } - - SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], - const SkFontStyle& style, - const char* bcp47[], int bcp47Count, - SkUnichar character) const override { - SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style); - SkUniqueCFRef<CTFontRef> familyFont(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr)); - - // kCFStringEncodingUTF32 is BE unless there is a BOM. - // Since there is no machine endian option, explicitly state machine endian. -#ifdef SK_CPU_LENDIAN - constexpr CFStringEncoding encoding = kCFStringEncodingUTF32LE; -#else - constexpr CFStringEncoding encoding = kCFStringEncodingUTF32BE; -#endif - SkUniqueCFRef<CFStringRef> string(CFStringCreateWithBytes( - kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(&character), sizeof(character), - encoding, false)); - // If 0xD800 <= codepoint <= 0xDFFF || 0x10FFFF < codepoint 'string' may be nullptr. - // No font should be covering such codepoints (even the magic fallback font). - if (!string) { - return nullptr; - } - CFRange range = CFRangeMake(0, CFStringGetLength(string.get())); // in UniChar units. - SkUniqueCFRef<CTFontRef> fallbackFont( - CTFontCreateForString(familyFont.get(), string.get(), range)); - return create_from_CTFontRef(std::move(fallbackFont), OpszVariation(), nullptr).release(); - } - - SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, - const SkFontStyle&) const override { - return nullptr; - } - - sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override { - if (ttcIndex != 0) { - return nullptr; - } - - SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(data, ttcIndex); - if (!ct) { - return nullptr; - } - - return create_from_CTFontRef(std::move(ct), OpszVariation(), - SkMemoryStream::Make(std::move(data))); - } - - sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream, - int ttcIndex) const override { - if (ttcIndex != 0) { - return nullptr; - } - - sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate()); - if (!data) { - return nullptr; - } - SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex); - if (!ct) { - return nullptr; - } - - return create_from_CTFontRef(std::move(ct), OpszVariation(), std::move(stream)); - } - - sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream, - const SkFontArguments& args) const override - { - // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available. - int ttcIndex = args.getCollectionIndex(); - if (ttcIndex != 0) { - return nullptr; - } - - sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate()); - if (!data) { - return nullptr; - } - SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex); - if (!ct) { - return nullptr; - } - - CTFontVariation ctVariation = ctvariation_from_skfontarguments(ct.get(), args); - - SkUniqueCFRef<CTFontRef> ctVariant; - if (ctVariation.dict) { - SkUniqueCFRef<CFMutableDictionaryRef> attributes( - CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - CFDictionaryAddValue(attributes.get(), - kCTFontVariationAttribute, ctVariation.dict.get()); - SkUniqueCFRef<CTFontDescriptorRef> varDesc( - CTFontDescriptorCreateWithAttributes(attributes.get())); - ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get())); - } else { - ctVariant.reset(ct.release()); - } - if (!ctVariant) { - return nullptr; - } - - return create_from_CTFontRef(std::move(ctVariant), ctVariation.opsz, - std::move(stream)); - } - - sk_sp<SkTypeface> onMakeFromFontData(std::unique_ptr<SkFontData> fontData) const override { - // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available. - if (fontData->getIndex() != 0) { - return nullptr; - } - - sk_sp<SkData> data = skdata_from_skstreamasset(fontData->getStream()->duplicate()); - if (!data) { - return nullptr; - } - SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), fontData->getIndex()); - if (!ct) { - return nullptr; - } - - CTFontVariation ctVariation = ctvariation_from_skfontdata(ct.get(), fontData.get()); - - SkUniqueCFRef<CTFontRef> ctVariant; - if (ctVariation.dict) { - SkUniqueCFRef<CFMutableDictionaryRef> attributes( - CFDictionaryCreateMutable(kCFAllocatorDefault, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - CFDictionaryAddValue(attributes.get(), - kCTFontVariationAttribute, ctVariation.dict.get()); - SkUniqueCFRef<CTFontDescriptorRef> varDesc( - CTFontDescriptorCreateWithAttributes(attributes.get())); - ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get())); - } else { - ctVariant.reset(ct.release()); - } - if (!ctVariant) { - return nullptr; - } - - return create_from_CTFontRef(std::move(ctVariant), ctVariation.opsz, - fontData->detachStream()); - } - - sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override { - if (ttcIndex != 0) { - return nullptr; - } - - sk_sp<SkData> data = SkData::MakeFromFileName(path); - if (!data) { - return nullptr; - } - - return this->onMakeFromData(std::move(data), ttcIndex); - } - - sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override { - if (familyName) { - familyName = map_css_names(familyName); - } - - sk_sp<SkTypeface> face = create_from_name(familyName, style); - if (face) { - return face; - } - - static SkTypeface* gDefaultFace; - static SkOnce lookupDefault; - static const char FONT_DEFAULT_NAME[] = "Lucida Sans"; - lookupDefault([]{ - gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle()).release(); - }); - return sk_ref_sp(gDefaultFace); - } -}; - -/////////////////////////////////////////////////////////////////////////////// - -sk_sp<SkFontMgr> SkFontMgr::Factory() { return sk_make_sp<SkFontMgr_Mac>(); } - -#endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) diff --git a/chromium/third_party/skia/src/ports/SkFontMgr_custom_directory_factory.cpp b/chromium/third_party/skia/src/ports/SkFontMgr_custom_directory_factory.cpp index 3bb52eb3393..f20b1b5bc47 100644 --- a/chromium/third_party/skia/src/ports/SkFontMgr_custom_directory_factory.cpp +++ b/chromium/third_party/skia/src/ports/SkFontMgr_custom_directory_factory.cpp @@ -9,7 +9,11 @@ #include "include/ports/SkFontMgr_directory.h" #ifndef SK_FONT_FILE_PREFIX +# if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) +# define SK_FONT_FILE_PREFIX "/System/Library/Fonts/" +# else # define SK_FONT_FILE_PREFIX "/usr/share/fonts/" +# endif #endif sk_sp<SkFontMgr> SkFontMgr::Factory() { diff --git a/chromium/third_party/skia/src/ports/SkFontMgr_custom_embedded.cpp b/chromium/third_party/skia/src/ports/SkFontMgr_custom_embedded.cpp index 924dc5a5628..a9b0f810d31 100644 --- a/chromium/third_party/skia/src/ports/SkFontMgr_custom_embedded.cpp +++ b/chromium/third_party/skia/src/ports/SkFontMgr_custom_embedded.cpp @@ -100,7 +100,7 @@ static void load_font_from_data(const SkTypeface_FreeType::Scanner& scanner, addTo = new SkFontStyleSet_Custom(realname); families->push_back().reset(addTo); } - auto data = std::make_unique<SkFontData>(std::move(stream), faceIndex, nullptr, 0); + auto data = std::make_unique<SkFontData>(stream->duplicate(), faceIndex, nullptr, 0); addTo->appendTypeface(sk_make_sp<SkTypeface_Stream>(std::move(data), style, isFixedPitch, true, realname)); diff --git a/chromium/third_party/skia/src/ports/SkFontMgr_mac_ct.cpp b/chromium/third_party/skia/src/ports/SkFontMgr_mac_ct.cpp new file mode 100644 index 00000000000..c362b160e50 --- /dev/null +++ b/chromium/third_party/skia/src/ports/SkFontMgr_mac_ct.cpp @@ -0,0 +1,669 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#ifdef SK_BUILD_FOR_MAC +#import <ApplicationServices/ApplicationServices.h> +#endif + +#ifdef SK_BUILD_FOR_IOS +#include <CoreText/CoreText.h> +#include <CoreText/CTFontManager.h> +#include <CoreGraphics/CoreGraphics.h> +#include <CoreFoundation/CoreFoundation.h> +#endif + +#include "include/core/SkData.h" +#include "include/core/SkFontArguments.h" +#include "include/core/SkFontMgr.h" +#include "include/core/SkFontStyle.h" +#include "include/core/SkStream.h" +#include "include/core/SkString.h" +#include "include/core/SkTypeface.h" +#include "include/ports/SkFontMgr_mac_ct.h" +#include "include/private/SkFixed.h" +#include "include/private/SkOnce.h" +#include "include/private/SkTemplates.h" +#include "include/private/SkTo.h" +#include "src/core/SkFontDescriptor.h" +#include "src/ports/SkTypeface_mac_ct.h" +#include "src/utils/SkUTF.h" + +#include <string.h> +#include <memory> + +static SkUniqueCFRef<CFStringRef> make_CFString(const char s[]) { + return SkUniqueCFRef<CFStringRef>(CFStringCreateWithCString(nullptr, s, kCFStringEncodingUTF8)); +} + +/** Creates a typeface from a descriptor, searching the cache. */ +static sk_sp<SkTypeface> create_from_desc(CTFontDescriptorRef desc) { + SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr)); + if (!ctFont) { + return nullptr; + } + + return SkTypeface_Mac::Make(std::move(ctFont), OpszVariation(), nullptr); +} + +static SkUniqueCFRef<CTFontDescriptorRef> create_descriptor(const char familyName[], + const SkFontStyle& style) { + SkUniqueCFRef<CFMutableDictionaryRef> cfAttributes( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + SkUniqueCFRef<CFMutableDictionaryRef> cfTraits( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + if (!cfAttributes || !cfTraits) { + return nullptr; + } + + // TODO(crbug.com/1018581) Some CoreText versions have errant behavior when + // certain traits set. Temporary workaround to omit specifying trait for + // those versions. + // Long term solution will involve serializing typefaces instead of relying + // upon this to match between processes. + // + // Compare CoreText.h in an up to date SDK for where these values come from. + static const uint32_t kSkiaLocalCTVersionNumber10_14 = 0x000B0000; + static const uint32_t kSkiaLocalCTVersionNumber10_15 = 0x000C0000; + + // CTFontTraits (symbolic) + // macOS 14 and iOS 12 seem to behave badly when kCTFontSymbolicTrait is set. + // macOS 15 yields LastResort font instead of a good default font when + // kCTFontSymbolicTrait is set. + if (!(&CTGetCoreTextVersion && CTGetCoreTextVersion() >= kSkiaLocalCTVersionNumber10_14)) { + CTFontSymbolicTraits ctFontTraits = 0; + if (style.weight() >= SkFontStyle::kBold_Weight) { + ctFontTraits |= kCTFontBoldTrait; + } + if (style.slant() != SkFontStyle::kUpright_Slant) { + ctFontTraits |= kCTFontItalicTrait; + } + SkUniqueCFRef<CFNumberRef> cfFontTraits( + CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &ctFontTraits)); + if (cfFontTraits) { + CFDictionaryAddValue(cfTraits.get(), kCTFontSymbolicTrait, cfFontTraits.get()); + } + } + + // CTFontTraits (weight) + CGFloat ctWeight = SkCTFontCTWeightForCSSWeight(style.weight()); + SkUniqueCFRef<CFNumberRef> cfFontWeight( + CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWeight)); + if (cfFontWeight) { + CFDictionaryAddValue(cfTraits.get(), kCTFontWeightTrait, cfFontWeight.get()); + } + // CTFontTraits (width) + CGFloat ctWidth = SkCTFontCTWidthForCSSWidth(style.width()); + SkUniqueCFRef<CFNumberRef> cfFontWidth( + CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctWidth)); + if (cfFontWidth) { + CFDictionaryAddValue(cfTraits.get(), kCTFontWidthTrait, cfFontWidth.get()); + } + // CTFontTraits (slant) + // macOS 15 behaves badly when kCTFontSlantTrait is set. + if (!(&CTGetCoreTextVersion && CTGetCoreTextVersion() == kSkiaLocalCTVersionNumber10_15)) { + CGFloat ctSlant = style.slant() == SkFontStyle::kUpright_Slant ? 0 : 1; + SkUniqueCFRef<CFNumberRef> cfFontSlant( + CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &ctSlant)); + if (cfFontSlant) { + CFDictionaryAddValue(cfTraits.get(), kCTFontSlantTrait, cfFontSlant.get()); + } + } + // CTFontTraits + CFDictionaryAddValue(cfAttributes.get(), kCTFontTraitsAttribute, cfTraits.get()); + + // CTFontFamilyName + if (familyName) { + SkUniqueCFRef<CFStringRef> cfFontName = make_CFString(familyName); + if (cfFontName) { + CFDictionaryAddValue(cfAttributes.get(), kCTFontFamilyNameAttribute, cfFontName.get()); + } + } + + return SkUniqueCFRef<CTFontDescriptorRef>( + CTFontDescriptorCreateWithAttributes(cfAttributes.get())); +} + +// Same as the above function except style is included so we can +// compare whether the created font conforms to the style. If not, we need +// to recreate the font with symbolic traits. This is needed due to MacOS 10.11 +// font creation problem https://bugs.chromium.org/p/skia/issues/detail?id=8447. +static sk_sp<SkTypeface> create_from_desc_and_style(CTFontDescriptorRef desc, + const SkFontStyle& style) { + SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc, 0, nullptr)); + if (!ctFont) { + return nullptr; + } + + const CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctFont.get()); + CTFontSymbolicTraits expected_traits = traits; + if (style.slant() != SkFontStyle::kUpright_Slant) { + expected_traits |= kCTFontItalicTrait; + } + if (style.weight() >= SkFontStyle::kBold_Weight) { + expected_traits |= kCTFontBoldTrait; + } + + if (expected_traits != traits) { + SkUniqueCFRef<CTFontRef> ctNewFont(CTFontCreateCopyWithSymbolicTraits( + ctFont.get(), 0, nullptr, expected_traits, expected_traits)); + if (ctNewFont) { + ctFont = std::move(ctNewFont); + } + } + + return SkTypeface_Mac::Make(std::move(ctFont), OpszVariation(), nullptr); +} + +/** Creates a typeface from a name, searching the cache. */ +static sk_sp<SkTypeface> create_from_name(const char familyName[], const SkFontStyle& style) { + SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style); + if (!desc) { + return nullptr; + } + return create_from_desc_and_style(desc.get(), style); +} + +static const char* map_css_names(const char* name) { + static const struct { + const char* fFrom; // name the caller specified + const char* fTo; // "canonical" name we map to + } gPairs[] = { + { "sans-serif", "Helvetica" }, + { "serif", "Times" }, + { "monospace", "Courier" } + }; + + for (size_t i = 0; i < SK_ARRAY_COUNT(gPairs); i++) { + if (strcmp(name, gPairs[i].fFrom) == 0) { + return gPairs[i].fTo; + } + } + return name; // no change +} + +namespace { + +/** Creates a dictionary suitable for setting the axes on a CTFont. */ +static CTFontVariation ctvariation_from_skfontdata(CTFontRef ct, SkFontData* fontData) { + // In macOS 10.15 CTFontCreate* overrides any 'opsz' variation with the 'size'. + // Track the 'opsz' and return it, since it is an out of band axis. + OpszVariation opsz; + constexpr const SkFourByteTag opszTag = SkSetFourByteTag('o','p','s','z'); + + SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct)); + if (!ctAxes) { + return CTFontVariation(); + } + + CFIndex axisCount = CFArrayGetCount(ctAxes.get()); + if (0 == axisCount || axisCount != fontData->getAxisCount()) { + return CTFontVariation(); + } + + SkUniqueCFRef<CFMutableDictionaryRef> dict( + CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + for (int i = 0; i < fontData->getAxisCount(); ++i) { + CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); + if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { + return CTFontVariation(); + } + CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); + + CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, + kCTFontVariationAxisIdentifierKey); + if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { + return CTFontVariation(); + } + CFNumberRef tagNumber = static_cast<CFNumberRef>(tag); + int64_t tagLong; + if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { + return CTFontVariation(); + } + + // The variation axes can be set to any value, but cg will effectively pin them. + // Pin them here to normalize. + CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey); + CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey); + if (!min || CFGetTypeID(min) != CFNumberGetTypeID() || + !max || CFGetTypeID(max) != CFNumberGetTypeID()) + { + return CTFontVariation(); + } + CFNumberRef minNumber = static_cast<CFNumberRef>(min); + CFNumberRef maxNumber = static_cast<CFNumberRef>(max); + double minDouble; + double maxDouble; + if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) || + !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble)) + { + return CTFontVariation(); + } + double value = SkTPin(SkFixedToDouble(fontData->getAxis()[i]), minDouble, maxDouble); + + if (tagLong == opszTag) { + opsz.isSet = true; + opsz.value = value; + } + + SkUniqueCFRef<CFNumberRef> valueNumber( + CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value)); + CFDictionaryAddValue(dict.get(), tagNumber, valueNumber.get()); + } + return { SkUniqueCFRef<CFDictionaryRef>(std::move(dict)), opsz }; +} + +static sk_sp<SkData> skdata_from_skstreamasset(std::unique_ptr<SkStreamAsset> stream) { + size_t size = stream->getLength(); + if (const void* base = stream->getMemoryBase()) { + return SkData::MakeWithProc(base, size, + [](const void*, void* ctx) -> void { + delete (SkStreamAsset*)ctx; + }, stream.release()); + } + return SkData::MakeFromStream(stream.get(), size); +} + +static SkUniqueCFRef<CFDataRef> cfdata_from_skdata(sk_sp<SkData> data) { + void const * const addr = data->data(); + size_t const size = data->size(); + + CFAllocatorContext ctx = { + 0, // CFIndex version + data.release(), // void* info + nullptr, // const void *(*retain)(const void *info); + nullptr, // void (*release)(const void *info); + nullptr, // CFStringRef (*copyDescription)(const void *info); + nullptr, // void * (*allocate)(CFIndex size, CFOptionFlags hint, void *info); + nullptr, // void*(*reallocate)(void* ptr,CFIndex newsize,CFOptionFlags hint,void* info); + [](void*,void* info) -> void { // void (*deallocate)(void *ptr, void *info); + SkASSERT(info); + ((SkData*)info)->unref(); + }, + nullptr, // CFIndex (*preferredSize)(CFIndex size, CFOptionFlags hint, void *info); + }; + SkUniqueCFRef<CFAllocatorRef> alloc(CFAllocatorCreate(kCFAllocatorDefault, &ctx)); + return SkUniqueCFRef<CFDataRef>(CFDataCreateWithBytesNoCopy( + kCFAllocatorDefault, (const UInt8 *)addr, size, alloc.get())); +} + +static SkUniqueCFRef<CTFontRef> ctfont_from_skdata(sk_sp<SkData> data, int ttcIndex) { + // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available. + if (ttcIndex != 0) { + return nullptr; + } + + SkUniqueCFRef<CFDataRef> cfData(cfdata_from_skdata(std::move(data))); + + SkUniqueCFRef<CTFontDescriptorRef> desc( + CTFontManagerCreateFontDescriptorFromData(cfData.get())); + if (!desc) { + return nullptr; + } + return SkUniqueCFRef<CTFontRef>(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr)); +} + +static bool find_desc_str(CTFontDescriptorRef desc, CFStringRef name, SkString* value) { + SkUniqueCFRef<CFStringRef> ref((CFStringRef)CTFontDescriptorCopyAttribute(desc, name)); + if (!ref) { + return false; + } + SkStringFromCFString(ref.get(), value); + return true; +} + +static inline int sqr(int value) { + SkASSERT(SkAbs32(value) < 0x7FFF); // check for overflow + return value * value; +} + +// We normalize each axis (weight, width, italic) to be base-900 +static int compute_metric(const SkFontStyle& a, const SkFontStyle& b) { + return sqr(a.weight() - b.weight()) + + sqr((a.width() - b.width()) * 100) + + sqr((a.slant() != b.slant()) * 900); +} + +class SkFontStyleSet_Mac : public SkFontStyleSet { +public: + SkFontStyleSet_Mac(CTFontDescriptorRef desc) + : fArray(CTFontDescriptorCreateMatchingFontDescriptors(desc, nullptr)) + , fCount(0) + { + if (!fArray) { + fArray.reset(CFArrayCreate(nullptr, nullptr, 0, nullptr)); + } + fCount = SkToInt(CFArrayGetCount(fArray.get())); + } + + int count() override { + return fCount; + } + + void getStyle(int index, SkFontStyle* style, SkString* name) override { + SkASSERT((unsigned)index < (unsigned)fCount); + CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index); + if (style) { + *style = SkCTFontDescriptorGetSkFontStyle(desc, false); + } + if (name) { + if (!find_desc_str(desc, kCTFontStyleNameAttribute, name)) { + name->reset(); + } + } + } + + SkTypeface* createTypeface(int index) override { + SkASSERT((unsigned)index < (unsigned)CFArrayGetCount(fArray.get())); + CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), index); + + return create_from_desc(desc).release(); + } + + SkTypeface* matchStyle(const SkFontStyle& pattern) override { + if (0 == fCount) { + return nullptr; + } + return create_from_desc(findMatchingDesc(pattern)).release(); + } + +private: + SkUniqueCFRef<CFArrayRef> fArray; + int fCount; + + CTFontDescriptorRef findMatchingDesc(const SkFontStyle& pattern) const { + int bestMetric = SK_MaxS32; + CTFontDescriptorRef bestDesc = nullptr; + + for (int i = 0; i < fCount; ++i) { + CTFontDescriptorRef desc = (CTFontDescriptorRef)CFArrayGetValueAtIndex(fArray.get(), i); + int metric = compute_metric(pattern, SkCTFontDescriptorGetSkFontStyle(desc, false)); + if (0 == metric) { + return desc; + } + if (metric < bestMetric) { + bestMetric = metric; + bestDesc = desc; + } + } + SkASSERT(bestDesc); + return bestDesc; + } +}; + +} // namespace + +class SkFontMgr_Mac : public SkFontMgr { + SkUniqueCFRef<CFArrayRef> fNames; + int fCount; + + CFStringRef getFamilyNameAt(int index) const { + SkASSERT((unsigned)index < (unsigned)fCount); + return (CFStringRef)CFArrayGetValueAtIndex(fNames.get(), index); + } + + static SkFontStyleSet* CreateSet(CFStringRef cfFamilyName) { + SkUniqueCFRef<CFMutableDictionaryRef> cfAttr( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + CFDictionaryAddValue(cfAttr.get(), kCTFontFamilyNameAttribute, cfFamilyName); + + SkUniqueCFRef<CTFontDescriptorRef> desc( + CTFontDescriptorCreateWithAttributes(cfAttr.get())); + return new SkFontStyleSet_Mac(desc.get()); + } + + /** CTFontManagerCopyAvailableFontFamilyNames() is not always available, so we + * provide a wrapper here that will return an empty array if need be. + */ + static SkUniqueCFRef<CFArrayRef> CopyAvailableFontFamilyNames() { +#ifdef SK_BUILD_FOR_IOS + return SkUniqueCFRef<CFArrayRef>(CFArrayCreate(nullptr, nullptr, 0, nullptr)); +#else + return SkUniqueCFRef<CFArrayRef>(CTFontManagerCopyAvailableFontFamilyNames()); +#endif + } + +public: + SkUniqueCFRef<CTFontCollectionRef> fFontCollection; + SkFontMgr_Mac(CTFontCollectionRef fontCollection) + : fNames(CopyAvailableFontFamilyNames()) + , fCount(fNames ? SkToInt(CFArrayGetCount(fNames.get())) : 0) + , fFontCollection(fontCollection ? (CTFontCollectionRef)CFRetain(fontCollection) + : CTFontCollectionCreateFromAvailableFonts(nullptr)) + {} + +protected: + int onCountFamilies() const override { + return fCount; + } + + void onGetFamilyName(int index, SkString* familyName) const override { + if ((unsigned)index < (unsigned)fCount) { + SkStringFromCFString(this->getFamilyNameAt(index), familyName); + } else { + familyName->reset(); + } + } + + SkFontStyleSet* onCreateStyleSet(int index) const override { + if ((unsigned)index >= (unsigned)fCount) { + return nullptr; + } + return CreateSet(this->getFamilyNameAt(index)); + } + + SkFontStyleSet* onMatchFamily(const char familyName[]) const override { + if (!familyName) { + return nullptr; + } + SkUniqueCFRef<CFStringRef> cfName = make_CFString(familyName); + return CreateSet(cfName.get()); + } + + SkTypeface* onMatchFamilyStyle(const char familyName[], + const SkFontStyle& style) const override { + SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style); + return create_from_desc(desc.get()).release(); + } + + SkTypeface* onMatchFamilyStyleCharacter(const char familyName[], + const SkFontStyle& style, + const char* bcp47[], int bcp47Count, + SkUnichar character) const override { + SkUniqueCFRef<CTFontDescriptorRef> desc = create_descriptor(familyName, style); + SkUniqueCFRef<CTFontRef> familyFont(CTFontCreateWithFontDescriptor(desc.get(), 0, nullptr)); + + // kCFStringEncodingUTF32 is BE unless there is a BOM. + // Since there is no machine endian option, explicitly state machine endian. +#ifdef SK_CPU_LENDIAN + constexpr CFStringEncoding encoding = kCFStringEncodingUTF32LE; +#else + constexpr CFStringEncoding encoding = kCFStringEncodingUTF32BE; +#endif + SkUniqueCFRef<CFStringRef> string(CFStringCreateWithBytes( + kCFAllocatorDefault, reinterpret_cast<const UInt8 *>(&character), sizeof(character), + encoding, false)); + // If 0xD800 <= codepoint <= 0xDFFF || 0x10FFFF < codepoint 'string' may be nullptr. + // No font should be covering such codepoints (even the magic fallback font). + if (!string) { + return nullptr; + } + CFRange range = CFRangeMake(0, CFStringGetLength(string.get())); // in UniChar units. + SkUniqueCFRef<CTFontRef> fallbackFont( + CTFontCreateForString(familyFont.get(), string.get(), range)); + return SkTypeface_Mac::Make(std::move(fallbackFont), OpszVariation(), nullptr).release(); + } + + SkTypeface* onMatchFaceStyle(const SkTypeface* familyMember, + const SkFontStyle&) const override { + return nullptr; + } + + sk_sp<SkTypeface> onMakeFromData(sk_sp<SkData> data, int ttcIndex) const override { + if (ttcIndex != 0) { + return nullptr; + } + + SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(data, ttcIndex); + if (!ct) { + return nullptr; + } + + return SkTypeface_Mac::Make(std::move(ct), OpszVariation(), + SkMemoryStream::Make(std::move(data))); + } + + sk_sp<SkTypeface> onMakeFromStreamIndex(std::unique_ptr<SkStreamAsset> stream, + int ttcIndex) const override { + if (ttcIndex != 0) { + return nullptr; + } + + sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate()); + if (!data) { + return nullptr; + } + SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex); + if (!ct) { + return nullptr; + } + + return SkTypeface_Mac::Make(std::move(ct), OpszVariation(), std::move(stream)); + } + + sk_sp<SkTypeface> onMakeFromStreamArgs(std::unique_ptr<SkStreamAsset> stream, + const SkFontArguments& args) const override + { + // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available. + int ttcIndex = args.getCollectionIndex(); + if (ttcIndex != 0) { + return nullptr; + } + + sk_sp<SkData> data = skdata_from_skstreamasset(stream->duplicate()); + if (!data) { + return nullptr; + } + SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), ttcIndex); + if (!ct) { + return nullptr; + } + + CTFontVariation ctVariation = SkCTVariationFromSkFontArguments(ct.get(), args); + + SkUniqueCFRef<CTFontRef> ctVariant; + if (ctVariation.dict) { + SkUniqueCFRef<CFMutableDictionaryRef> attributes( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + CFDictionaryAddValue(attributes.get(), + kCTFontVariationAttribute, ctVariation.dict.get()); + SkUniqueCFRef<CTFontDescriptorRef> varDesc( + CTFontDescriptorCreateWithAttributes(attributes.get())); + ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get())); + } else { + ctVariant.reset(ct.release()); + } + if (!ctVariant) { + return nullptr; + } + + return SkTypeface_Mac::Make(std::move(ctVariant), ctVariation.opsz, std::move(stream)); + } + + sk_sp<SkTypeface> onMakeFromFontData(std::unique_ptr<SkFontData> fontData) const override { + // TODO: Use CTFontManagerCreateFontDescriptorsFromData when available. + if (fontData->getIndex() != 0) { + return nullptr; + } + + sk_sp<SkData> data = skdata_from_skstreamasset(fontData->getStream()->duplicate()); + if (!data) { + return nullptr; + } + SkUniqueCFRef<CTFontRef> ct = ctfont_from_skdata(std::move(data), fontData->getIndex()); + if (!ct) { + return nullptr; + } + + CTFontVariation ctVariation = ctvariation_from_skfontdata(ct.get(), fontData.get()); + + SkUniqueCFRef<CTFontRef> ctVariant; + if (ctVariation.dict) { + SkUniqueCFRef<CFMutableDictionaryRef> attributes( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + CFDictionaryAddValue(attributes.get(), + kCTFontVariationAttribute, ctVariation.dict.get()); + SkUniqueCFRef<CTFontDescriptorRef> varDesc( + CTFontDescriptorCreateWithAttributes(attributes.get())); + ctVariant.reset(CTFontCreateCopyWithAttributes(ct.get(), 0, nullptr, varDesc.get())); + } else { + ctVariant.reset(ct.release()); + } + if (!ctVariant) { + return nullptr; + } + + return SkTypeface_Mac::Make(std::move(ctVariant), ctVariation.opsz, + fontData->detachStream()); + } + + sk_sp<SkTypeface> onMakeFromFile(const char path[], int ttcIndex) const override { + if (ttcIndex != 0) { + return nullptr; + } + + sk_sp<SkData> data = SkData::MakeFromFileName(path); + if (!data) { + return nullptr; + } + + return this->onMakeFromData(std::move(data), ttcIndex); + } + + sk_sp<SkTypeface> onLegacyMakeTypeface(const char familyName[], SkFontStyle style) const override { + if (familyName) { + familyName = map_css_names(familyName); + } + + sk_sp<SkTypeface> face = create_from_name(familyName, style); + if (face) { + return face; + } + + static SkTypeface* gDefaultFace; + static SkOnce lookupDefault; + static const char FONT_DEFAULT_NAME[] = "Lucida Sans"; + lookupDefault([]{ + gDefaultFace = create_from_name(FONT_DEFAULT_NAME, SkFontStyle()).release(); + }); + return sk_ref_sp(gDefaultFace); + } +}; + +sk_sp<SkFontMgr> SkFontMgr_New_CoreText(CTFontCollectionRef fontCollection) { + return sk_make_sp<SkFontMgr_Mac>(fontCollection); +} + +#endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) diff --git a/chromium/third_party/skia/src/ports/SkFontMgr_mac_ct_factory.cpp b/chromium/third_party/skia/src/ports/SkFontMgr_mac_ct_factory.cpp new file mode 100644 index 00000000000..ef834e4af28 --- /dev/null +++ b/chromium/third_party/skia/src/ports/SkFontMgr_mac_ct_factory.cpp @@ -0,0 +1,18 @@ +/* + * Copyright 2017 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#include "include/core/SkFontMgr.h" +#include "include/ports/SkFontMgr_mac_ct.h" + +sk_sp<SkFontMgr> SkFontMgr::Factory() { + return SkFontMgr_New_CoreText(nullptr); +} + +#endif//defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) diff --git a/chromium/third_party/skia/src/ports/SkGlobalInitialization_default.cpp b/chromium/third_party/skia/src/ports/SkGlobalInitialization_default.cpp index e277b2c8457..167d94cca1e 100644 --- a/chromium/third_party/skia/src/ports/SkGlobalInitialization_default.cpp +++ b/chromium/third_party/skia/src/ports/SkGlobalInitialization_default.cpp @@ -73,8 +73,8 @@ // Color filters. SkColorFilter_Matrix::RegisterFlattenables(); - SK_REGISTER_FLATTENABLE(SkLumaColorFilter); - SkColorFilter::RegisterFlattenables(); + SkLumaColorFilter::RegisterFlattenable(); + SkColorFilterBase::RegisterFlattenables(); SkHighContrastFilter::RegisterFlattenables(); SkTableColorFilter::RegisterFlattenables(); @@ -96,6 +96,7 @@ SK_REGISTER_FLATTENABLE(SkPath1DPathEffect); SK_REGISTER_FLATTENABLE(SkPath2DPathEffect); SK_REGISTER_FLATTENABLE(SkStrokePE); + SK_REGISTER_FLATTENABLE(SkStrokeAndFillPE); SK_REGISTER_FLATTENABLE(SkTrimPE); SkPathEffect::RegisterFlattenables(); diff --git a/chromium/third_party/skia/src/ports/SkScalerContext_mac_ct.cpp b/chromium/third_party/skia/src/ports/SkScalerContext_mac_ct.cpp new file mode 100644 index 00000000000..f2f2298fb4d --- /dev/null +++ b/chromium/third_party/skia/src/ports/SkScalerContext_mac_ct.cpp @@ -0,0 +1,721 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#ifdef SK_BUILD_FOR_MAC +#import <ApplicationServices/ApplicationServices.h> +#endif + +#ifdef SK_BUILD_FOR_IOS +#include <CoreText/CoreText.h> +#include <CoreText/CTFontManager.h> +#include <CoreGraphics/CoreGraphics.h> +#include <CoreFoundation/CoreFoundation.h> +#endif + +#include "include/core/SkColor.h" +#include "include/core/SkColorPriv.h" +#include "include/core/SkFontMetrics.h" +#include "include/core/SkFontTypes.h" +#include "include/core/SkMatrix.h" +#include "include/core/SkPath.h" +#include "include/core/SkPoint.h" +#include "include/core/SkRect.h" +#include "include/core/SkScalar.h" +#include "include/core/SkTypeface.h" +#include "include/private/SkColorData.h" +#include "include/private/SkFixed.h" +#include "include/private/SkTemplates.h" +#include "include/private/SkTo.h" +#include "src/core/SkAutoMalloc.h" +#include "src/core/SkEndian.h" +#include "src/core/SkGlyph.h" +#include "src/core/SkMask.h" +#include "src/core/SkMaskGamma.h" +#include "src/core/SkMathPriv.h" +#include "src/core/SkUtils.h" +#include "src/ports/SkScalerContext_mac_ct.h" +#include "src/ports/SkTypeface_mac_ct.h" +#include "src/sfnt/SkOTTableTypes.h" +#include "src/sfnt/SkOTTable_OS_2.h" +#include "src/utils/mac/SkCGBase.h" +#include "src/utils/mac/SkCGGeometry.h" +#include "src/utils/mac/SkCTFontSmoothBehavior.h" +#include "src/utils/mac/SkUniqueCFRef.h" + +#include <algorithm> + +class SkDescriptor; + + +// Set to make glyph bounding boxes visible. +#define SK_SHOW_TEXT_BLIT_COVERAGE 0 + +static void sk_memset_rect32(uint32_t* ptr, uint32_t value, + int width, int height, size_t rowBytes) { + SkASSERT(width); + SkASSERT(width * sizeof(uint32_t) <= rowBytes); + + if (width >= 32) { + while (height) { + sk_memset32(ptr, value, width); + ptr = (uint32_t*)((char*)ptr + rowBytes); + height -= 1; + } + return; + } + + rowBytes -= width * sizeof(uint32_t); + + if (width >= 8) { + while (height) { + int w = width; + do { + *ptr++ = value; *ptr++ = value; + *ptr++ = value; *ptr++ = value; + *ptr++ = value; *ptr++ = value; + *ptr++ = value; *ptr++ = value; + w -= 8; + } while (w >= 8); + while (--w >= 0) { + *ptr++ = value; + } + ptr = (uint32_t*)((char*)ptr + rowBytes); + height -= 1; + } + } else { + while (height) { + int w = width; + do { + *ptr++ = value; + } while (--w > 0); + ptr = (uint32_t*)((char*)ptr + rowBytes); + height -= 1; + } + } +} + +static unsigned CGRGBPixel_getAlpha(CGRGBPixel pixel) { + return pixel & 0xFF; +} + +static CGAffineTransform MatrixToCGAffineTransform(const SkMatrix& matrix) { + return CGAffineTransformMake( SkScalarToCGFloat(matrix[SkMatrix::kMScaleX]), + -SkScalarToCGFloat(matrix[SkMatrix::kMSkewY] ), + -SkScalarToCGFloat(matrix[SkMatrix::kMSkewX] ), + SkScalarToCGFloat(matrix[SkMatrix::kMScaleY]), + SkScalarToCGFloat(matrix[SkMatrix::kMTransX]), + SkScalarToCGFloat(matrix[SkMatrix::kMTransY])); +} + +SkScalerContext_Mac::SkScalerContext_Mac(sk_sp<SkTypeface_Mac> typeface, + const SkScalerContextEffects& effects, + const SkDescriptor* desc) + : INHERITED(std::move(typeface), effects, desc) + , fDoSubPosition(SkToBool(fRec.fFlags & kSubpixelPositioning_Flag)) + +{ + CTFontRef ctFont = (CTFontRef)this->getTypeface()->internal_private_getCTFontRef(); + CFIndex numGlyphs = CTFontGetGlyphCount(ctFont); + SkASSERT(numGlyphs >= 1 && numGlyphs <= 0xFFFF); + fGlyphCount = SkToU16(numGlyphs); + + // CT on (at least) 10.9 will size color glyphs down from the requested size, but not up. + // As a result, it is necessary to know the actual device size and request that. + SkVector scale; + SkMatrix skTransform; + bool invertible = fRec.computeMatrices(SkScalerContextRec::kVertical_PreMatrixScale, + &scale, &skTransform, nullptr, nullptr, nullptr); + fTransform = MatrixToCGAffineTransform(skTransform); + // CGAffineTransformInvert documents that if the transform is non-invertible it will return the + // passed transform unchanged. It does so, but then also prints a message to stdout. Avoid this. + if (invertible) { + fInvTransform = CGAffineTransformInvert(fTransform); + } else { + fInvTransform = fTransform; + } + + // The transform contains everything except the requested text size. + // Some properties, like 'trak', are based on the optical text size. + CGFloat textSize = SkScalarToCGFloat(scale.y()); + fCTFont = SkCTFontCreateExactCopy(ctFont, textSize, + ((SkTypeface_Mac*)this->getTypeface())->fOpszVariation); + fCGFont.reset(CTFontCopyGraphicsFont(fCTFont.get(), nullptr)); +} + +static int RoundSize(int dimension) { + return SkNextPow2(dimension); +} + +CGRGBPixel* SkScalerContext_Mac::Offscreen::getCG(const SkScalerContext_Mac& context, + const SkGlyph& glyph, CGGlyph glyphID, + size_t* rowBytesPtr, + bool generateA8FromLCD) { + if (!fRGBSpace) { + //It doesn't appear to matter what color space is specified. + //Regular blends and antialiased text are always (s*a + d*(1-a)) + //and subpixel antialiased text is always g=2.0. + fRGBSpace.reset(CGColorSpaceCreateDeviceRGB()); + } + + // default to kBW_Format + bool doAA = false; + bool doLCD = false; + + if (SkMask::kBW_Format != glyph.maskFormat()) { + doLCD = true; + doAA = true; + } + + // FIXME: lcd smoothed un-hinted rasterization unsupported. + if (!generateA8FromLCD && SkMask::kA8_Format == glyph.maskFormat()) { + doLCD = false; + doAA = true; + } + + // If this font might have color glyphs, disable LCD as there's no way to support it. + // CoreText doesn't tell us which format it ended up using, so we can't detect it. + // A8 will end up black on transparent, but TODO: we can detect gray and set to A8. + if (SkMask::kARGB32_Format == glyph.maskFormat()) { + doLCD = false; + } + + size_t rowBytes = fSize.fWidth * sizeof(CGRGBPixel); + if (!fCG || fSize.fWidth < glyph.width() || fSize.fHeight < glyph.height()) { + if (fSize.fWidth < glyph.width()) { + fSize.fWidth = RoundSize(glyph.width()); + } + if (fSize.fHeight < glyph.height()) { + fSize.fHeight = RoundSize(glyph.height()); + } + + rowBytes = fSize.fWidth * sizeof(CGRGBPixel); + void* image = fImageStorage.reset(rowBytes * fSize.fHeight); + const CGImageAlphaInfo alpha = (glyph.isColor()) + ? kCGImageAlphaPremultipliedFirst + : kCGImageAlphaNoneSkipFirst; + const CGBitmapInfo bitmapInfo = kCGBitmapByteOrder32Host | (CGBitmapInfo)alpha; + fCG.reset(CGBitmapContextCreate(image, fSize.fWidth, fSize.fHeight, 8, + rowBytes, fRGBSpace.get(), bitmapInfo)); + + // Skia handles quantization and subpixel positioning, + // so disable quantization and enable subpixel positioning in CG. + CGContextSetAllowsFontSubpixelQuantization(fCG.get(), false); + CGContextSetShouldSubpixelQuantizeFonts(fCG.get(), false); + + // Because CG always draws from the horizontal baseline, + // if there is a non-integral translation from the horizontal origin to the vertical origin, + // then CG cannot draw the glyph in the correct location without subpixel positioning. + CGContextSetAllowsFontSubpixelPositioning(fCG.get(), true); + CGContextSetShouldSubpixelPositionFonts(fCG.get(), true); + + CGContextSetTextDrawingMode(fCG.get(), kCGTextFill); + + // Draw black on white to create mask. (Special path exists to speed this up in CG.) + CGContextSetGrayFillColor(fCG.get(), 0.0f, 1.0f); + + // force our checks below to happen + fDoAA = !doAA; + fDoLCD = !doLCD; + + CGContextSetTextMatrix(fCG.get(), context.fTransform); + } + + if (fDoAA != doAA) { + CGContextSetShouldAntialias(fCG.get(), doAA); + fDoAA = doAA; + } + if (fDoLCD != doLCD) { + CGContextSetShouldSmoothFonts(fCG.get(), doLCD); + fDoLCD = doLCD; + } + + CGRGBPixel* image = (CGRGBPixel*)fImageStorage.get(); + // skip rows based on the glyph's height + image += (fSize.fHeight - glyph.height()) * fSize.fWidth; + + // Erase to white (or transparent black if it's a color glyph, to not composite against white). + uint32_t bgColor = (!glyph.isColor()) ? 0xFFFFFFFF : 0x00000000; + sk_memset_rect32(image, bgColor, glyph.width(), glyph.height(), rowBytes); + + float subX = 0; + float subY = 0; + if (context.fDoSubPosition) { + subX = SkFixedToFloat(glyph.getSubXFixed()); + subY = SkFixedToFloat(glyph.getSubYFixed()); + } + + CGPoint point = CGPointMake(-glyph.left() + subX, glyph.top() + glyph.height() - subY); + // Prior to 10.10, CTFontDrawGlyphs acted like CGContextShowGlyphsAtPositions and took + // 'positions' which are in text space. The glyph location (in device space) must be + // mapped into text space, so that CG can convert it back into device space. + // In 10.10.1, this is handled directly in CTFontDrawGlyphs. + // + // However, in 10.10.2 color glyphs no longer rotate based on the font transform. + // So always make the font transform identity and place the transform on the context. + point = CGPointApplyAffineTransform(point, context.fInvTransform); + + CTFontDrawGlyphs(context.fCTFont.get(), &glyphID, &point, 1, fCG.get()); + + SkASSERT(rowBytesPtr); + *rowBytesPtr = rowBytes; + return image; +} + +unsigned SkScalerContext_Mac::generateGlyphCount(void) { + return fGlyphCount; +} + +bool SkScalerContext_Mac::generateAdvance(SkGlyph* glyph) { + return false; +} + +void SkScalerContext_Mac::generateMetrics(SkGlyph* glyph) { + glyph->fMaskFormat = fRec.fMaskFormat; + + const CGGlyph cgGlyph = (CGGlyph) glyph->getGlyphID(); + glyph->zeroMetrics(); + + // The following block produces cgAdvance in CG units (pixels, y up). + CGSize cgAdvance; + CTFontGetAdvancesForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal, + &cgGlyph, &cgAdvance, 1); + cgAdvance = CGSizeApplyAffineTransform(cgAdvance, fTransform); + glyph->fAdvanceX = SkFloatFromCGFloat(cgAdvance.width); + glyph->fAdvanceY = -SkFloatFromCGFloat(cgAdvance.height); + + // The following produces skBounds in SkGlyph units (pixels, y down), + // or returns early if skBounds would be empty. + SkRect skBounds; + + // Glyphs are always drawn from the horizontal origin. The caller must manually use the result + // of CTFontGetVerticalTranslationsForGlyphs to calculate where to draw the glyph for vertical + // glyphs. As a result, always get the horizontal bounds of a glyph and translate it if the + // glyph is vertical. This avoids any diagreement between the various means of retrieving + // vertical metrics. + { + // CTFontGetBoundingRectsForGlyphs produces cgBounds in CG units (pixels, y up). + CGRect cgBounds; + CTFontGetBoundingRectsForGlyphs(fCTFont.get(), kCTFontOrientationHorizontal, + &cgGlyph, &cgBounds, 1); + cgBounds = CGRectApplyAffineTransform(cgBounds, fTransform); + + // BUG? + // 0x200B (zero-advance space) seems to return a huge (garbage) bounds, when + // it should be empty. So, if we see a zero-advance, we check if it has an + // empty path or not, and if so, we jam the bounds to 0. Hopefully a zero-advance + // is rare, so we won't incur a big performance cost for this extra check. + if (0 == cgAdvance.width && 0 == cgAdvance.height) { + SkUniqueCFRef<CGPathRef> path(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph,nullptr)); + if (!path || CGPathIsEmpty(path.get())) { + return; + } + } + + if (SkCGRectIsEmpty(cgBounds)) { + return; + } + + // Convert cgBounds to SkGlyph units (pixels, y down). + skBounds = SkRect::MakeXYWH(cgBounds.origin.x, -cgBounds.origin.y - cgBounds.size.height, + cgBounds.size.width, cgBounds.size.height); + } + + // Currently the bounds are based on being rendered at (0,0). + // The top left must not move, since that is the base from which subpixel positioning is offset. + if (fDoSubPosition) { + skBounds.fRight += SkFixedToFloat(glyph->getSubXFixed()); + skBounds.fBottom += SkFixedToFloat(glyph->getSubYFixed()); + } + + // We're trying to pack left and top into int16_t, + // and width and height into uint16_t, after outsetting by 1. + if (!SkRect::MakeXYWH(-32767, -32767, 65535, 65535).contains(skBounds)) { + return; + } + + SkIRect skIBounds; + skBounds.roundOut(&skIBounds); + // Expand the bounds by 1 pixel, to give CG room for anti-aliasing. + // Note that this outset is to allow room for LCD smoothed glyphs. However, the correct outset + // is not currently known, as CG dilates the outlines by some percentage. + // Note that if this context is A8 and not back-forming from LCD, there is no need to outset. + skIBounds.outset(1, 1); + glyph->fLeft = SkToS16(skIBounds.fLeft); + glyph->fTop = SkToS16(skIBounds.fTop); + glyph->fWidth = SkToU16(skIBounds.width()); + glyph->fHeight = SkToU16(skIBounds.height()); +} + +static constexpr uint8_t sk_pow2_table(size_t i) { + return SkToU8(((i * i + 128) / 255)); +} + +/** + * This will invert the gamma applied by CoreGraphics, so we can get linear + * values. + * + * CoreGraphics obscurely defaults to 2.0 as the subpixel coverage gamma value. + * The color space used does not appear to affect this choice. + */ +static constexpr auto gLinearCoverageFromCGLCDValue = SkMakeArray<256>(sk_pow2_table); + +static void cgpixels_to_bits(uint8_t dst[], const CGRGBPixel src[], int count) { + while (count > 0) { + uint8_t mask = 0; + for (int i = 7; i >= 0; --i) { + mask |= ((CGRGBPixel_getAlpha(*src++) >> 7) ^ 0x1) << i; + if (0 == --count) { + break; + } + } + *dst++ = mask; + } +} + +template<bool APPLY_PREBLEND> +static inline uint8_t rgb_to_a8(CGRGBPixel rgb, const uint8_t* table8) { + U8CPU r = 0xFF - ((rgb >> 16) & 0xFF); + U8CPU g = 0xFF - ((rgb >> 8) & 0xFF); + U8CPU b = 0xFF - ((rgb >> 0) & 0xFF); + U8CPU lum = sk_apply_lut_if<APPLY_PREBLEND>(SkComputeLuminance(r, g, b), table8); +#if SK_SHOW_TEXT_BLIT_COVERAGE + lum = std::max(lum, (U8CPU)0x30); +#endif + return lum; +} + +template<bool APPLY_PREBLEND> +static void RGBToA8(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, + const SkGlyph& glyph, void* glyphImage, const uint8_t* table8) { + const int width = glyph.width(); + const int height = glyph.height(); + size_t dstRB = glyph.rowBytes(); + uint8_t* SK_RESTRICT dst = (uint8_t*)glyphImage; + + for (int y = 0; y < height; y++) { + for (int i = 0; i < width; ++i) { + dst[i] = rgb_to_a8<APPLY_PREBLEND>(cgPixels[i], table8); + } + cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes); + dst = SkTAddOffset<uint8_t>(dst, dstRB); + } +} + +template<bool APPLY_PREBLEND> +static uint16_t RGBToLcd16(CGRGBPixel rgb, + const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { + U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 16) & 0xFF), tableR); + U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 8) & 0xFF), tableG); + U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(0xFF - ((rgb >> 0) & 0xFF), tableB); +#if SK_SHOW_TEXT_BLIT_COVERAGE + r = std::max(r, (U8CPU)0x30); + g = std::max(g, (U8CPU)0x30); + b = std::max(b, (U8CPU)0x30); +#endif + return SkPack888ToRGB16(r, g, b); +} + +template<bool APPLY_PREBLEND> +static void RGBToLcd16(const CGRGBPixel* SK_RESTRICT cgPixels, size_t cgRowBytes, + const SkGlyph& glyph, void* glyphImage, + const uint8_t* tableR, const uint8_t* tableG, const uint8_t* tableB) { + const int width = glyph.width(); + const int height = glyph.height(); + size_t dstRB = glyph.rowBytes(); + uint16_t* SK_RESTRICT dst = (uint16_t*)glyphImage; + + for (int y = 0; y < height; y++) { + for (int i = 0; i < width; i++) { + dst[i] = RGBToLcd16<APPLY_PREBLEND>(cgPixels[i], tableR, tableG, tableB); + } + cgPixels = SkTAddOffset<const CGRGBPixel>(cgPixels, cgRowBytes); + dst = SkTAddOffset<uint16_t>(dst, dstRB); + } +} + +static SkPMColor cgpixels_to_pmcolor(CGRGBPixel rgb) { + U8CPU a = (rgb >> 24) & 0xFF; + U8CPU r = (rgb >> 16) & 0xFF; + U8CPU g = (rgb >> 8) & 0xFF; + U8CPU b = (rgb >> 0) & 0xFF; +#if SK_SHOW_TEXT_BLIT_COVERAGE + a = std::max(a, (U8CPU)0x30); +#endif + return SkPackARGB32(a, r, g, b); +} + +void SkScalerContext_Mac::generateImage(const SkGlyph& glyph) { + CGGlyph cgGlyph = SkTo<CGGlyph>(glyph.getGlyphID()); + + // FIXME: lcd smoothed un-hinted rasterization unsupported. + bool requestSmooth = fRec.getHinting() != SkFontHinting::kNone; + + // Draw the glyph + size_t cgRowBytes; + CGRGBPixel* cgPixels = fOffscreen.getCG(*this, glyph, cgGlyph, &cgRowBytes, requestSmooth); + if (cgPixels == nullptr) { + return; + } + + // Fix the glyph + if ((glyph.fMaskFormat == SkMask::kLCD16_Format) || + (glyph.fMaskFormat == SkMask::kA8_Format + && requestSmooth + && SkCTFontGetSmoothBehavior() != SkCTFontSmoothBehavior::none)) + { + const uint8_t* linear = gLinearCoverageFromCGLCDValue.data(); + + //Note that the following cannot really be integrated into the + //pre-blend, since we may not be applying the pre-blend; when we aren't + //applying the pre-blend it means that a filter wants linear anyway. + //Other code may also be applying the pre-blend, so we'd need another + //one with this and one without. + CGRGBPixel* addr = cgPixels; + for (int y = 0; y < glyph.fHeight; ++y) { + for (int x = 0; x < glyph.fWidth; ++x) { + int r = (addr[x] >> 16) & 0xFF; + int g = (addr[x] >> 8) & 0xFF; + int b = (addr[x] >> 0) & 0xFF; + addr[x] = (linear[r] << 16) | (linear[g] << 8) | linear[b]; + } + addr = SkTAddOffset<CGRGBPixel>(addr, cgRowBytes); + } + } + + // Convert glyph to mask + switch (glyph.fMaskFormat) { + case SkMask::kLCD16_Format: { + if (fPreBlend.isApplicable()) { + RGBToLcd16<true>(cgPixels, cgRowBytes, glyph, glyph.fImage, + fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); + } else { + RGBToLcd16<false>(cgPixels, cgRowBytes, glyph, glyph.fImage, + fPreBlend.fR, fPreBlend.fG, fPreBlend.fB); + } + } break; + case SkMask::kA8_Format: { + if (fPreBlend.isApplicable()) { + RGBToA8<true>(cgPixels, cgRowBytes, glyph, glyph.fImage, fPreBlend.fG); + } else { + RGBToA8<false>(cgPixels, cgRowBytes, glyph, glyph.fImage, fPreBlend.fG); + } + } break; + case SkMask::kBW_Format: { + const int width = glyph.fWidth; + size_t dstRB = glyph.rowBytes(); + uint8_t* dst = (uint8_t*)glyph.fImage; + for (int y = 0; y < glyph.fHeight; y++) { + cgpixels_to_bits(dst, cgPixels, width); + cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes); + dst = SkTAddOffset<uint8_t>(dst, dstRB); + } + } break; + case SkMask::kARGB32_Format: { + const int width = glyph.fWidth; + size_t dstRB = glyph.rowBytes(); + SkPMColor* dst = (SkPMColor*)glyph.fImage; + for (int y = 0; y < glyph.fHeight; y++) { + for (int x = 0; x < width; ++x) { + dst[x] = cgpixels_to_pmcolor(cgPixels[x]); + } + cgPixels = SkTAddOffset<CGRGBPixel>(cgPixels, cgRowBytes); + dst = SkTAddOffset<SkPMColor>(dst, dstRB); + } + } break; + default: + SkDEBUGFAIL("unexpected mask format"); + break; + } +} + +namespace { +class SkCTPathGeometrySink { + SkPath* fPath; + bool fStarted; + CGPoint fCurrent; + + void goingTo(const CGPoint pt) { + if (!fStarted) { + fStarted = true; + fPath->moveTo(fCurrent.x, -fCurrent.y); + } + fCurrent = pt; + } + + bool currentIsNot(const CGPoint pt) { + return fCurrent.x != pt.x || fCurrent.y != pt.y; + } + +public: + SkCTPathGeometrySink(SkPath* path) : fPath{path}, fStarted{false}, fCurrent{0,0} {} + static void ApplyElement(void *ctx, const CGPathElement *element) { + SkCTPathGeometrySink& self = *(SkCTPathGeometrySink*)ctx; + CGPoint* points = element->points; + + switch (element->type) { + case kCGPathElementMoveToPoint: + self.fStarted = false; + self.fCurrent = points[0]; + break; + + case kCGPathElementAddLineToPoint: + if (self.currentIsNot(points[0])) { + self.goingTo(points[0]); + self.fPath->lineTo(points[0].x, -points[0].y); + } + break; + + case kCGPathElementAddQuadCurveToPoint: + if (self.currentIsNot(points[0]) || self.currentIsNot(points[1])) { + self.goingTo(points[1]); + self.fPath->quadTo(points[0].x, -points[0].y, + points[1].x, -points[1].y); + } + break; + + case kCGPathElementAddCurveToPoint: + if (self.currentIsNot(points[0]) || + self.currentIsNot(points[1]) || + self.currentIsNot(points[2])) + { + self.goingTo(points[2]); + self.fPath->cubicTo(points[0].x, -points[0].y, + points[1].x, -points[1].y, + points[2].x, -points[2].y); + } + break; + + case kCGPathElementCloseSubpath: + if (self.fStarted) { + self.fPath->close(); + } + break; + + default: + SkDEBUGFAIL("Unknown path element!"); + break; + } + } +}; +} // namespace + +/* + * Our subpixel resolution is only 2 bits in each direction, so a scale of 4 + * seems sufficient, and possibly even correct, to allow the hinted outline + * to be subpixel positioned. + */ +#define kScaleForSubPixelPositionHinting (4.0f) + +bool SkScalerContext_Mac::generatePath(SkGlyphID glyph, SkPath* path) { + SkScalar scaleX = SK_Scalar1; + SkScalar scaleY = SK_Scalar1; + + CGAffineTransform xform = fTransform; + /* + * For subpixel positioning, we want to return an unhinted outline, so it + * can be positioned nicely at fractional offsets. However, we special-case + * if the baseline of the (horizontal) text is axis-aligned. In those cases + * we want to retain hinting in the direction orthogonal to the baseline. + * e.g. for horizontal baseline, we want to retain hinting in Y. + * The way we remove hinting is to scale the font by some value (4) in that + * direction, ask for the path, and then scale the path back down. + */ + if (fDoSubPosition) { + // start out by assuming that we want no hining in X and Y + scaleX = scaleY = kScaleForSubPixelPositionHinting; + // now see if we need to restore hinting for axis-aligned baselines + switch (this->computeAxisAlignmentForHText()) { + case kX_SkAxisAlignment: + scaleY = SK_Scalar1; // want hinting in the Y direction + break; + case kY_SkAxisAlignment: + scaleX = SK_Scalar1; // want hinting in the X direction + break; + default: + break; + } + + CGAffineTransform scale(CGAffineTransformMakeScale(SkScalarToCGFloat(scaleX), + SkScalarToCGFloat(scaleY))); + xform = CGAffineTransformConcat(fTransform, scale); + } + + CGGlyph cgGlyph = SkTo<CGGlyph>(glyph); + SkUniqueCFRef<CGPathRef> cgPath(CTFontCreatePathForGlyph(fCTFont.get(), cgGlyph, &xform)); + + path->reset(); + if (!cgPath) { + return false; + } + + SkCTPathGeometrySink sink(path); + CGPathApply(cgPath.get(), &sink, SkCTPathGeometrySink::ApplyElement); + if (fDoSubPosition) { + SkMatrix m; + m.setScale(SkScalarInvert(scaleX), SkScalarInvert(scaleY)); + path->transform(m); + } + return true; +} + +void SkScalerContext_Mac::generateFontMetrics(SkFontMetrics* metrics) { + if (nullptr == metrics) { + return; + } + + CGRect theBounds = CTFontGetBoundingBox(fCTFont.get()); + + metrics->fTop = SkScalarFromCGFloat(-SkCGRectGetMaxY(theBounds)); + metrics->fAscent = SkScalarFromCGFloat(-CTFontGetAscent(fCTFont.get())); + metrics->fDescent = SkScalarFromCGFloat( CTFontGetDescent(fCTFont.get())); + metrics->fBottom = SkScalarFromCGFloat(-SkCGRectGetMinY(theBounds)); + metrics->fLeading = SkScalarFromCGFloat( CTFontGetLeading(fCTFont.get())); + metrics->fAvgCharWidth = SkScalarFromCGFloat( SkCGRectGetWidth(theBounds)); + metrics->fXMin = SkScalarFromCGFloat( SkCGRectGetMinX(theBounds)); + metrics->fXMax = SkScalarFromCGFloat( SkCGRectGetMaxX(theBounds)); + metrics->fMaxCharWidth = metrics->fXMax - metrics->fXMin; + metrics->fXHeight = SkScalarFromCGFloat( CTFontGetXHeight(fCTFont.get())); + metrics->fCapHeight = SkScalarFromCGFloat( CTFontGetCapHeight(fCTFont.get())); + metrics->fUnderlineThickness = SkScalarFromCGFloat( CTFontGetUnderlineThickness(fCTFont.get())); + metrics->fUnderlinePosition = -SkScalarFromCGFloat( CTFontGetUnderlinePosition(fCTFont.get())); + + metrics->fFlags = 0; + metrics->fFlags |= SkFontMetrics::kUnderlineThicknessIsValid_Flag; + metrics->fFlags |= SkFontMetrics::kUnderlinePositionIsValid_Flag; + + // See https://bugs.chromium.org/p/skia/issues/detail?id=6203 + // At least on 10.12.3 with memory based fonts the x-height is always 0.6666 of the ascent and + // the cap-height is always 0.8888 of the ascent. It appears that the values from the 'OS/2' + // table are read, but then overwritten if the font is not a system font. As a result, if there + // is a valid 'OS/2' table available use the values from the table if they aren't too strange. + struct OS2HeightMetrics { + SK_OT_SHORT sxHeight; + SK_OT_SHORT sCapHeight; + } heights; + size_t bytesRead = this->getTypeface()->getTableData( + SkTEndian_SwapBE32(SkOTTableOS2::TAG), offsetof(SkOTTableOS2, version.v2.sxHeight), + sizeof(heights), &heights); + if (bytesRead == sizeof(heights)) { + // 'fontSize' is correct because the entire resolved size is set by the constructor. + CGFloat fontSize = CTFontGetSize(this->fCTFont.get()); + unsigned upem = CTFontGetUnitsPerEm(this->fCTFont.get()); + unsigned maxSaneHeight = upem * 2; + uint16_t xHeight = SkEndian_SwapBE16(heights.sxHeight); + if (xHeight && xHeight < maxSaneHeight) { + metrics->fXHeight = SkScalarFromCGFloat(xHeight * fontSize / upem); + } + uint16_t capHeight = SkEndian_SwapBE16(heights.sCapHeight); + if (capHeight && capHeight < maxSaneHeight) { + metrics->fCapHeight = SkScalarFromCGFloat(capHeight * fontSize / upem); + } + } +} + +#endif diff --git a/chromium/third_party/skia/src/ports/SkScalerContext_mac_ct.h b/chromium/third_party/skia/src/ports/SkScalerContext_mac_ct.h new file mode 100644 index 00000000000..4b7f548a1ca --- /dev/null +++ b/chromium/third_party/skia/src/ports/SkScalerContext_mac_ct.h @@ -0,0 +1,118 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkScalerContext_mac_ct_DEFINED +#define SkScalerContext_mac_ct_DEFINED + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#include "include/core/SkRefCnt.h" +#include "include/core/SkSize.h" +#include "src/core/SkAutoMalloc.h" +#include "src/core/SkScalerContext.h" +#include "src/utils/mac/SkUniqueCFRef.h" + +#ifdef SK_BUILD_FOR_MAC +#import <ApplicationServices/ApplicationServices.h> +#endif + +#ifdef SK_BUILD_FOR_IOS +#include <CoreText/CoreText.h> +#include <CoreText/CTFontManager.h> +#include <CoreGraphics/CoreGraphics.h> +#include <CoreFoundation/CoreFoundation.h> +#endif + +#include <memory> + +class SkDescriptor; +class SkGlyph; +class SkPath; +class SkTypeface_Mac; +struct SkFontMetrics; + + +typedef uint32_t CGRGBPixel; + +class SkScalerContext_Mac : public SkScalerContext { +public: + SkScalerContext_Mac(sk_sp<SkTypeface_Mac>, const SkScalerContextEffects&, const SkDescriptor*); + +protected: + unsigned generateGlyphCount(void) override; + bool generateAdvance(SkGlyph* glyph) override; + void generateMetrics(SkGlyph* glyph) override; + void generateImage(const SkGlyph& glyph) override; + bool generatePath(SkGlyphID glyph, SkPath* path) override; + void generateFontMetrics(SkFontMetrics*) override; + +private: + class Offscreen { + public: + Offscreen() + : fRGBSpace(nullptr) + , fCG(nullptr) + , fDoAA(false) + , fDoLCD(false) + { + fSize.set(0, 0); + } + + CGRGBPixel* getCG(const SkScalerContext_Mac& context, const SkGlyph& glyph, + CGGlyph glyphID, size_t* rowBytesPtr, bool generateA8FromLCD); + + private: + enum { + kSize = 32 * 32 * sizeof(CGRGBPixel) + }; + SkAutoSMalloc<kSize> fImageStorage; + SkUniqueCFRef<CGColorSpaceRef> fRGBSpace; + + // cached state + SkUniqueCFRef<CGContextRef> fCG; + SkISize fSize; + bool fDoAA; + bool fDoLCD; + }; + Offscreen fOffscreen; + + /** Unrotated variant of fCTFont. + * + * In 10.10.1 CTFontGetAdvancesForGlyphs applies the font transform to the width of the + * advances, but always sets the height to 0. This font is used to get the advances of the + * unrotated glyph, and then the rotation is applied separately. + * + * CT vertical metrics are pre-rotated (in em space, before transform) 90deg clock-wise. + * This makes kCTFontOrientationDefault dangerous, because the metrics from + * kCTFontOrientationHorizontal are in a different space from kCTFontOrientationVertical. + * With kCTFontOrientationVertical the advances must be unrotated. + * + * Sometimes, creating a copy of a CTFont with the same size but different trasform will select + * different underlying font data. As a result, avoid ever creating more than one CTFont per + * SkScalerContext to ensure that only one CTFont is used. + * + * As a result of the above (and other constraints) this font contains the size, but not the + * transform. The transform must always be applied separately. + */ + SkUniqueCFRef<CTFontRef> fCTFont; + + /** The transform without the font size. */ + CGAffineTransform fTransform; + CGAffineTransform fInvTransform; + + SkUniqueCFRef<CGFontRef> fCGFont; + uint16_t fGlyphCount; + const bool fDoSubPosition; + + friend class Offscreen; + + typedef SkScalerContext INHERITED; +}; + +#endif +#endif //SkScalerContext_mac_ct_DEFINED diff --git a/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.cpp b/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.cpp index b8208907088..f95f6c60ffa 100644 --- a/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.cpp +++ b/chromium/third_party/skia/src/ports/SkScalerContext_win_dw.cpp @@ -368,6 +368,15 @@ SkScalerContext_DW::SkScalerContext_DW(sk_sp<DWriteFontTypeface> typefaceRef, fTextSizeMeasure = realTextSize; fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; } + + // The GDI measuring modes don't seem to work well with CBDT fonts (DWrite.dll 10.0.18362.836). + if (fMeasuringMode != DWRITE_MEASURING_MODE_NATURAL) { + constexpr UINT32 CBDTTag = DWRITE_MAKE_OPENTYPE_TAG('C','B','D','T'); + AutoDWriteTable CBDT(typeface->fDWriteFontFace.get(), CBDTTag); + if (CBDT.fExists) { + fMeasuringMode = DWRITE_MEASURING_MODE_NATURAL; + } + } } SkScalerContext_DW::~SkScalerContext_DW() { diff --git a/chromium/third_party/skia/src/ports/SkTypeface_mac_ct.cpp b/chromium/third_party/skia/src/ports/SkTypeface_mac_ct.cpp new file mode 100644 index 00000000000..8055f6bcb28 --- /dev/null +++ b/chromium/third_party/skia/src/ports/SkTypeface_mac_ct.cpp @@ -0,0 +1,1470 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#ifdef SK_BUILD_FOR_MAC +#import <ApplicationServices/ApplicationServices.h> +#endif + +#ifdef SK_BUILD_FOR_IOS +#include <CoreText/CoreText.h> +#include <CoreText/CTFontManager.h> +#include <CoreGraphics/CoreGraphics.h> +#include <CoreFoundation/CoreFoundation.h> +#endif + +#include "include/core/SkColor.h" +#include "include/core/SkData.h" +#include "include/core/SkFontArguments.h" +#include "include/core/SkFontParameters.h" +#include "include/core/SkFontStyle.h" +#include "include/core/SkFontTypes.h" +#include "include/core/SkRect.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkStream.h" +#include "include/core/SkString.h" +#include "include/core/SkTypeface.h" +#include "include/ports/SkTypeface_mac.h" +#include "include/private/SkFixed.h" +#include "include/private/SkMalloc.h" +#include "include/private/SkMutex.h" +#include "include/private/SkOnce.h" +#include "include/private/SkTDArray.h" +#include "include/private/SkTemplates.h" +#include "include/private/SkTo.h" +#include "src/core/SkAdvancedTypefaceMetrics.h" +#include "src/core/SkEndian.h" +#include "src/core/SkFontDescriptor.h" +#include "src/core/SkMask.h" +#include "src/core/SkScalerContext.h" +#include "src/core/SkTypefaceCache.h" +#include "src/core/SkUtils.h" +#include "src/ports/SkScalerContext_mac_ct.h" +#include "src/ports/SkTypeface_mac_ct.h" +#include "src/sfnt/SkOTTableTypes.h" +#include "src/sfnt/SkOTTable_OS_2.h" +#include "src/sfnt/SkOTTable_OS_2_V4.h" +#include "src/sfnt/SkOTUtils.h" +#include "src/sfnt/SkSFNTHeader.h" +#include "src/utils/SkUTF.h" +#include "src/utils/mac/SkCGBase.h" +#include "src/utils/mac/SkCGGeometry.h" +#include "src/utils/mac/SkCTFontSmoothBehavior.h" +#include "src/utils/mac/SkUniqueCFRef.h" + +#include <dlfcn.h> +#include <limits.h> +#include <string.h> +#include <memory> + +// In macOS 10.12 and later any variation on the CGFont which has default axis value will be +// dropped when creating the CTFont. Unfortunately, in macOS 10.15 the priority of setting +// the optical size (and opsz variation) is +// 1. the value of kCTFontOpticalSizeAttribute in the CTFontDescriptor (undocumented) +// 2. the opsz axis default value if kCTFontOpticalSizeAttribute is 'none' (undocumented) +// 3. the opsz variation on the nascent CTFont from the CGFont (was dropped if default) +// 4. the opsz variation in kCTFontVariationAttribute in CTFontDescriptor (crashes 10.10) +// 5. the size requested (can fudge in SkTypeface but not SkScalerContext) +// The first one which is found will be used to set the opsz variation (after clamping). +static void add_opsz_attr(CFMutableDictionaryRef attr, double opsz) { + SkUniqueCFRef<CFNumberRef> opszValueNumber( + CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &opsz)); + // Avoid using kCTFontOpticalSizeAttribute directly + CFStringRef SkCTFontOpticalSizeAttribute = CFSTR("NSCTFontOpticalSizeAttribute"); + CFDictionarySetValue(attr, SkCTFontOpticalSizeAttribute, opszValueNumber.get()); +} + +// This turns off application of the 'trak' table to advances, but also all other tracking. +static void add_notrak_attr(CFMutableDictionaryRef attr) { + int zero = 0; + SkUniqueCFRef<CFNumberRef> unscaledTrackingNumber( + CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &zero)); + CFStringRef SkCTFontUnscaledTrackingAttribute = CFSTR("NSCTFontUnscaledTrackingAttribute"); + CFDictionarySetValue(attr, SkCTFontUnscaledTrackingAttribute, unscaledTrackingNumber.get()); +} + +SkUniqueCFRef<CTFontRef> SkCTFontCreateExactCopy(CTFontRef baseFont, CGFloat textSize, + OpszVariation opsz) +{ + SkUniqueCFRef<CFMutableDictionaryRef> attr( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + if (opsz.isSet) { + add_opsz_attr(attr.get(), opsz.value); +#if !defined(SK_IGNORE_MAC_OPSZ_FORCE) + } else { + // On (at least) 10.10 though 10.14 the default system font was SFNSText/SFNSDisplay. + // The CTFont is backed by both; optical size < 20 means SFNSText else SFNSDisplay. + // On at least 10.11 the glyph ids in these fonts became non-interchangable. + // To keep glyph ids stable over size changes, preserve the optical size. + // In 10.15 this was replaced with use of variable fonts with an opsz axis. + // A CTFont backed by multiple fonts picked by opsz where the multiple backing fonts are + // variable fonts with opsz axis and non-interchangeable glyph ids would break the + // opsz.isSet branch above, but hopefully that never happens. + // See https://crbug.com/524646 . + CFStringRef SkCTFontOpticalSizeAttribute = CFSTR("NSCTFontOpticalSizeAttribute"); + SkUniqueCFRef<CFTypeRef> opsz(CTFontCopyAttribute(baseFont, SkCTFontOpticalSizeAttribute)); + double opsz_val; + if (!opsz || + CFGetTypeID(opsz.get()) != CFNumberGetTypeID() || + !CFNumberGetValue(static_cast<CFNumberRef>(opsz.get()),kCFNumberDoubleType,&opsz_val) || + opsz_val <= 0) + { + opsz_val = CTFontGetSize(baseFont); + } + add_opsz_attr(attr.get(), opsz_val); +#endif + } + add_notrak_attr(attr.get()); + + SkUniqueCFRef<CTFontDescriptorRef> desc(CTFontDescriptorCreateWithAttributes(attr.get())); + +#if !defined(SK_IGNORE_MAC_OPSZ_FORCE) + return SkUniqueCFRef<CTFontRef>( + CTFontCreateCopyWithAttributes(baseFont, textSize, nullptr, desc.get())); +#else + SkUniqueCFRef<CGFontRef> baseCGFont(CTFontCopyGraphicsFont(baseFont, nullptr)); + return SkUniqueCFRef<CTFontRef>( + CTFontCreateWithGraphicsFont(baseCGFont.get(), textSize, nullptr, desc.get())); + +#endif +} + +CTFontRef SkTypeface_GetCTFontRef(const SkTypeface* face) { + return face ? (CTFontRef)face->internal_private_getCTFontRef() : nullptr; +} + +static bool find_by_CTFontRef(SkTypeface* cached, void* context) { + CTFontRef self = (CTFontRef)context; + CTFontRef other = (CTFontRef)cached->internal_private_getCTFontRef(); + + return CFEqual(self, other); +} + +/** Creates a typeface, searching the cache if isLocalStream is false. */ +sk_sp<SkTypeface> SkTypeface_Mac::Make(SkUniqueCFRef<CTFontRef> font, + OpszVariation opszVariation, + std::unique_ptr<SkStreamAsset> providedData) { + static SkMutex gTFCacheMutex; + static SkTypefaceCache gTFCache; + + SkASSERT(font); + const bool isFromStream(providedData); + + if (!isFromStream) { + SkAutoMutexExclusive ama(gTFCacheMutex); + sk_sp<SkTypeface> face = gTFCache.findByProcAndRef(find_by_CTFontRef, (void*)font.get()); + if (face) { + return face; + } + } + + SkUniqueCFRef<CTFontDescriptorRef> desc(CTFontCopyFontDescriptor(font.get())); + SkFontStyle style = SkCTFontDescriptorGetSkFontStyle(desc.get(), isFromStream); + CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(font.get()); + bool isFixedPitch = SkToBool(traits & kCTFontMonoSpaceTrait); + + sk_sp<SkTypeface> face(new SkTypeface_Mac(std::move(font), style, + isFixedPitch, opszVariation, + std::move(providedData))); + if (!isFromStream) { + SkAutoMutexExclusive ama(gTFCacheMutex); + gTFCache.add(face); + } + return face; +} + +/* This function is visible on the outside. It first searches the cache, and if + * not found, returns a new entry (after adding it to the cache). + */ +sk_sp<SkTypeface> SkMakeTypefaceFromCTFont(CTFontRef font) { + CFRetain(font); + return SkTypeface_Mac::Make(SkUniqueCFRef<CTFontRef>(font), + OpszVariation(), + nullptr); +} + +static bool find_dict_CGFloat(CFDictionaryRef dict, CFStringRef name, CGFloat* value) { + CFNumberRef num; + return CFDictionaryGetValueIfPresent(dict, name, (const void**)&num) + && CFNumberIsFloatType(num) + && CFNumberGetValue(num, kCFNumberCGFloatType, value); +} + +template <typename S, typename D, typename C> struct LinearInterpolater { + struct Mapping { + S src_val; + D dst_val; + }; + constexpr LinearInterpolater(Mapping const mapping[], int mappingCount) + : fMapping(mapping), fMappingCount(mappingCount) {} + + static D map(S value, S src_min, S src_max, D dst_min, D dst_max) { + SkASSERT(src_min < src_max); + SkASSERT(dst_min <= dst_max); + return C()(dst_min + (((value - src_min) * (dst_max - dst_min)) / (src_max - src_min))); + } + + D map(S val) const { + // -Inf to [0] + if (val < fMapping[0].src_val) { + return fMapping[0].dst_val; + } + + // Linear from [i] to [i+1] + for (int i = 0; i < fMappingCount - 1; ++i) { + if (val < fMapping[i+1].src_val) { + return map(val, fMapping[i].src_val, fMapping[i+1].src_val, + fMapping[i].dst_val, fMapping[i+1].dst_val); + } + } + + // From [n] to +Inf + // if (fcweight < Inf) + return fMapping[fMappingCount - 1].dst_val; + } + + Mapping const * fMapping; + int fMappingCount; +}; + +struct RoundCGFloatToInt { + int operator()(CGFloat s) { return s + 0.5; } +}; +struct CGFloatIdentity { + CGFloat operator()(CGFloat s) { return s; } +}; + +/** Returns the [-1, 1] CTFontDescriptor weights for the + * <0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000> CSS weights. + * + * It is assumed that the values will be interpolated linearly between these points. + * NSFontWeightXXX were added in 10.11, appear in 10.10, but do not appear in 10.9. + * The actual values appear to be stable, but they may change in the future without notice. + */ +static CGFloat(&get_NSFontWeight_mapping())[11] { + + // Declarations in <AppKit/AppKit.h> on macOS, <UIKit/UIKit.h> on iOS +#ifdef SK_BUILD_FOR_MAC +# define SK_KIT_FONT_WEIGHT_PREFIX "NS" +#endif +#ifdef SK_BUILD_FOR_IOS +# define SK_KIT_FONT_WEIGHT_PREFIX "UI" +#endif + static constexpr struct { + CGFloat defaultValue; + const char* name; + } nsFontWeightLoaderInfos[] = { + { -0.80f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightUltraLight" }, + { -0.60f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightThin" }, + { -0.40f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightLight" }, + { 0.00f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightRegular" }, + { 0.23f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightMedium" }, + { 0.30f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightSemibold" }, + { 0.40f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightBold" }, + { 0.56f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightHeavy" }, + { 0.62f, SK_KIT_FONT_WEIGHT_PREFIX "FontWeightBlack" }, + }; + + static_assert(SK_ARRAY_COUNT(nsFontWeightLoaderInfos) == 9, ""); + static CGFloat nsFontWeights[11]; + static SkOnce once; + once([&] { + size_t i = 0; + nsFontWeights[i++] = -1.00; + for (const auto& nsFontWeightLoaderInfo : nsFontWeightLoaderInfos) { + void* nsFontWeightValuePtr = dlsym(RTLD_DEFAULT, nsFontWeightLoaderInfo.name); + if (nsFontWeightValuePtr) { + nsFontWeights[i++] = *(static_cast<CGFloat*>(nsFontWeightValuePtr)); + } else { + nsFontWeights[i++] = nsFontWeightLoaderInfo.defaultValue; + } + } + nsFontWeights[i++] = 1.00; + }); + return nsFontWeights; +} + +/** Convert the [0, 1000] CSS weight to [-1, 1] CTFontDescriptor weight (for system fonts). + * + * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the + * CTFont is native or created from a CGDataProvider. + */ +CGFloat SkCTFontCTWeightForCSSWeight(int fontstyleWeight) { + using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>; + + // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100. + // However, on this end we can't tell, so this is ignored. + + static Interpolator::Mapping nativeWeightMappings[11]; + static SkOnce once; + once([&] { + CGFloat(&nsFontWeights)[11] = get_NSFontWeight_mapping(); + for (int i = 0; i < 11; ++i) { + nativeWeightMappings[i].src_val = i * 100; + nativeWeightMappings[i].dst_val = nsFontWeights[i]; + } + }); + static constexpr Interpolator nativeInterpolator( + nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings)); + + return nativeInterpolator.map(fontstyleWeight); +} + + +/** Convert the [-1, 1] CTFontDescriptor weight to [0, 1000] CSS weight. + * + * The -1 to 1 weights reported by CTFontDescriptors have different mappings depending on if the + * CTFont is native or created from a CGDataProvider. + */ +static int ct_weight_to_fontstyle(CGFloat cgWeight, bool fromDataProvider) { + using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>; + + // Note that Mac supports the old OS2 version A so 0 through 10 are as if multiplied by 100. + // However, on this end we can't tell, so this is ignored. + + /** This mapping for CGDataProvider created fonts is determined by creating font data with every + * weight, creating a CTFont, and asking the CTFont for its weight. See the TypefaceStyle test + * in tests/TypefaceTest.cpp for the code used to determine these values. + */ + static constexpr Interpolator::Mapping dataProviderWeightMappings[] = { + { -1.00, 0 }, + { -0.70, 100 }, + { -0.50, 200 }, + { -0.23, 300 }, + { 0.00, 400 }, + { 0.20, 500 }, + { 0.30, 600 }, + { 0.40, 700 }, + { 0.60, 800 }, + { 0.80, 900 }, + { 1.00, 1000 }, + }; + static constexpr Interpolator dataProviderInterpolator( + dataProviderWeightMappings, SK_ARRAY_COUNT(dataProviderWeightMappings)); + + static Interpolator::Mapping nativeWeightMappings[11]; + static SkOnce once; + once([&] { + CGFloat(&nsFontWeights)[11] = get_NSFontWeight_mapping(); + for (int i = 0; i < 11; ++i) { + nativeWeightMappings[i].src_val = nsFontWeights[i]; + nativeWeightMappings[i].dst_val = i * 100; + } + }); + static constexpr Interpolator nativeInterpolator( + nativeWeightMappings, SK_ARRAY_COUNT(nativeWeightMappings)); + + return fromDataProvider ? dataProviderInterpolator.map(cgWeight) + : nativeInterpolator.map(cgWeight); +} + +/** Convert the [0, 10] CSS weight to [-1, 1] CTFontDescriptor width. */ +CGFloat SkCTFontCTWidthForCSSWidth(int fontstyleWidth) { + using Interpolator = LinearInterpolater<int, CGFloat, CGFloatIdentity>; + + // Values determined by creating font data with every width, creating a CTFont, + // and asking the CTFont for its width. See TypefaceStyle test for basics. + static constexpr Interpolator::Mapping widthMappings[] = { + { 0, -0.5 }, + { 10, 0.5 }, + }; + static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings)); + return interpolator.map(fontstyleWidth); +} + +/** Convert the [-1, 1] CTFontDescriptor width to [0, 10] CSS weight. */ +static int ct_width_to_fontstyle(CGFloat cgWidth) { + using Interpolator = LinearInterpolater<CGFloat, int, RoundCGFloatToInt>; + + // Values determined by creating font data with every width, creating a CTFont, + // and asking the CTFont for its width. See TypefaceStyle test for basics. + static constexpr Interpolator::Mapping widthMappings[] = { + { -0.5, 0 }, + { 0.5, 10 }, + }; + static constexpr Interpolator interpolator(widthMappings, SK_ARRAY_COUNT(widthMappings)); + return interpolator.map(cgWidth); +} + +SkFontStyle SkCTFontDescriptorGetSkFontStyle(CTFontDescriptorRef desc, bool fromDataProvider) { + SkUniqueCFRef<CFTypeRef> traits(CTFontDescriptorCopyAttribute(desc, kCTFontTraitsAttribute)); + if (!traits || CFDictionaryGetTypeID() != CFGetTypeID(traits.get())) { + return SkFontStyle(); + } + SkUniqueCFRef<CFDictionaryRef> fontTraitsDict(static_cast<CFDictionaryRef>(traits.release())); + + CGFloat weight, width, slant; + if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWeightTrait, &weight)) { + weight = 0; + } + if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontWidthTrait, &width)) { + width = 0; + } + if (!find_dict_CGFloat(fontTraitsDict.get(), kCTFontSlantTrait, &slant)) { + slant = 0; + } + + return SkFontStyle(ct_weight_to_fontstyle(weight, fromDataProvider), + ct_width_to_fontstyle(width), + slant ? SkFontStyle::kItalic_Slant + : SkFontStyle::kUpright_Slant); +} + + +// Web fonts added to the CTFont registry do not return their character set. +// Iterate through the font in this case. The existing caller caches the result, +// so the performance impact isn't too bad. +static void populate_glyph_to_unicode_slow(CTFontRef ctFont, CFIndex glyphCount, + SkUnichar* out) { + sk_bzero(out, glyphCount * sizeof(SkUnichar)); + UniChar unichar = 0; + while (glyphCount > 0) { + CGGlyph glyph; + if (CTFontGetGlyphsForCharacters(ctFont, &unichar, &glyph, 1)) { + if (out[glyph] == 0) { + out[glyph] = unichar; + --glyphCount; + } + } + if (++unichar == 0) { + break; + } + } +} + +static constexpr uint16_t kPlaneSize = 1 << 13; + +static void get_plane_glyph_map(const uint8_t* bits, + CTFontRef ctFont, + CFIndex glyphCount, + SkUnichar* glyphToUnicode, + uint8_t planeIndex) { + SkUnichar planeOrigin = (SkUnichar)planeIndex << 16; // top half of codepoint. + for (uint16_t i = 0; i < kPlaneSize; i++) { + uint8_t mask = bits[i]; + if (!mask) { + continue; + } + for (uint8_t j = 0; j < 8; j++) { + if (0 == (mask & ((uint8_t)1 << j))) { + continue; + } + uint16_t planeOffset = (i << 3) | j; + SkUnichar codepoint = planeOrigin | (SkUnichar)planeOffset; + uint16_t utf16[2] = {planeOffset, 0}; + size_t count = 1; + if (planeOrigin != 0) { + count = SkUTF::ToUTF16(codepoint, utf16); + } + CGGlyph glyphs[2] = {0, 0}; + if (CTFontGetGlyphsForCharacters(ctFont, utf16, glyphs, count)) { + SkASSERT(glyphs[1] == 0); + SkASSERT(glyphs[0] < glyphCount); + // CTFontCopyCharacterSet and CTFontGetGlyphsForCharacters seem to add 'support' + // for characters 0x9, 0xA, and 0xD mapping them to the glyph for character 0x20? + // Prefer mappings to codepoints at or above 0x20. + if (glyphToUnicode[glyphs[0]] < 0x20) { + glyphToUnicode[glyphs[0]] = codepoint; + } + } + } + } +} +// Construct Glyph to Unicode table. +static void populate_glyph_to_unicode(CTFontRef ctFont, CFIndex glyphCount, + SkUnichar* glyphToUnicode) { + sk_bzero(glyphToUnicode, sizeof(SkUnichar) * glyphCount); + SkUniqueCFRef<CFCharacterSetRef> charSet(CTFontCopyCharacterSet(ctFont)); + if (!charSet) { + populate_glyph_to_unicode_slow(ctFont, glyphCount, glyphToUnicode); + return; + } + + SkUniqueCFRef<CFDataRef> bitmap( + CFCharacterSetCreateBitmapRepresentation(nullptr, charSet.get())); + if (!bitmap) { + return; + } + CFIndex dataLength = CFDataGetLength(bitmap.get()); + if (!dataLength) { + return; + } + SkASSERT(dataLength >= kPlaneSize); + const UInt8* bits = CFDataGetBytePtr(bitmap.get()); + + get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, 0); + /* + A CFData object that specifies the bitmap representation of the Unicode + character points the for the new character set. The bitmap representation could + contain all the Unicode character range starting from BMP to Plane 16. The + first 8KiB (8192 bytes) of the data represent the BMP range. The BMP range 8KiB + can be followed by zero to sixteen 8KiB bitmaps, each prepended with the plane + index byte. For example, the bitmap representing the BMP and Plane 2 has the + size of 16385 bytes (8KiB for BMP, 1 byte index, and a 8KiB bitmap for Plane + 2). The plane index byte, in this case, contains the integer value two. + */ + + if (dataLength <= kPlaneSize) { + return; + } + int extraPlaneCount = (dataLength - kPlaneSize) / (1 + kPlaneSize); + SkASSERT(dataLength == kPlaneSize + extraPlaneCount * (1 + kPlaneSize)); + while (extraPlaneCount-- > 0) { + bits += kPlaneSize; + uint8_t planeIndex = *bits++; + SkASSERT(planeIndex >= 1); + SkASSERT(planeIndex <= 16); + get_plane_glyph_map(bits, ctFont, glyphCount, glyphToUnicode, planeIndex); + } +} + +/** Assumes src and dst are not nullptr. */ +void SkStringFromCFString(CFStringRef src, SkString* dst) { + // Reserve enough room for the worst-case string, + // plus 1 byte for the trailing null. + CFIndex length = CFStringGetMaximumSizeForEncoding(CFStringGetLength(src), + kCFStringEncodingUTF8) + 1; + dst->resize(length); + CFStringGetCString(src, dst->writable_str(), length, kCFStringEncodingUTF8); + // Resize to the actual UTF-8 length used, stripping the null character. + dst->resize(strlen(dst->c_str())); +} + +void SkTypeface_Mac::getGlyphToUnicodeMap(SkUnichar* dstArray) const { + SkUniqueCFRef<CTFontRef> ctFont = + SkCTFontCreateExactCopy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()), + fOpszVariation); + CFIndex glyphCount = CTFontGetGlyphCount(ctFont.get()); + populate_glyph_to_unicode(ctFont.get(), glyphCount, dstArray); +} + +std::unique_ptr<SkAdvancedTypefaceMetrics> SkTypeface_Mac::onGetAdvancedMetrics() const { + + SkUniqueCFRef<CTFontRef> ctFont = + SkCTFontCreateExactCopy(fFontRef.get(), CTFontGetUnitsPerEm(fFontRef.get()), + fOpszVariation); + + std::unique_ptr<SkAdvancedTypefaceMetrics> info(new SkAdvancedTypefaceMetrics); + + { + SkUniqueCFRef<CFStringRef> fontName(CTFontCopyPostScriptName(ctFont.get())); + if (fontName.get()) { + SkStringFromCFString(fontName.get(), &info->fPostScriptName); + info->fFontName = info->fPostScriptName; + } + } + + // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when + // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always + // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and + // CGFontCopyVariations here until support for 10.10 and earlier is removed. + SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont.get(), nullptr)); + if (cgFont) { + SkUniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get())); + if (cgAxes && CFArrayGetCount(cgAxes.get()) > 0) { + info->fFlags |= SkAdvancedTypefaceMetrics::kMultiMaster_FontFlag; + } + } + + SkOTTableOS2_V4::Type fsType; + if (sizeof(fsType) == this->getTableData(SkTEndian_SwapBE32(SkOTTableOS2::TAG), + offsetof(SkOTTableOS2_V4, fsType), + sizeof(fsType), + &fsType)) { + SkOTUtils::SetAdvancedTypefaceFlags(fsType, info.get()); + } + + // If it's not a truetype font, mark it as 'other'. Assume that TrueType + // fonts always have both glyf and loca tables. At the least, this is what + // sfntly needs to subset the font. CTFontCopyAttribute() does not always + // succeed in determining this directly. + if (!this->getTableSize('glyf') || !this->getTableSize('loca')) { + return info; + } + + info->fType = SkAdvancedTypefaceMetrics::kTrueType_Font; + CTFontSymbolicTraits symbolicTraits = CTFontGetSymbolicTraits(ctFont.get()); + if (symbolicTraits & kCTFontMonoSpaceTrait) { + info->fStyle |= SkAdvancedTypefaceMetrics::kFixedPitch_Style; + } + if (symbolicTraits & kCTFontItalicTrait) { + info->fStyle |= SkAdvancedTypefaceMetrics::kItalic_Style; + } + CTFontStylisticClass stylisticClass = symbolicTraits & kCTFontClassMaskTrait; + if (stylisticClass >= kCTFontOldStyleSerifsClass && stylisticClass <= kCTFontSlabSerifsClass) { + info->fStyle |= SkAdvancedTypefaceMetrics::kSerif_Style; + } else if (stylisticClass & kCTFontScriptsClass) { + info->fStyle |= SkAdvancedTypefaceMetrics::kScript_Style; + } + info->fItalicAngle = (int16_t) CTFontGetSlantAngle(ctFont.get()); + info->fAscent = (int16_t) CTFontGetAscent(ctFont.get()); + info->fDescent = (int16_t) CTFontGetDescent(ctFont.get()); + info->fCapHeight = (int16_t) CTFontGetCapHeight(ctFont.get()); + CGRect bbox = CTFontGetBoundingBox(ctFont.get()); + + SkRect r; + r.setLTRB(SkScalarFromCGFloat(SkCGRectGetMinX(bbox)), // Left + SkScalarFromCGFloat(SkCGRectGetMaxY(bbox)), // Top + SkScalarFromCGFloat(SkCGRectGetMaxX(bbox)), // Right + SkScalarFromCGFloat(SkCGRectGetMinY(bbox))); // Bottom + + r.roundOut(&(info->fBBox)); + + // Figure out a good guess for StemV - Min width of i, I, !, 1. + // This probably isn't very good with an italic font. + int16_t min_width = SHRT_MAX; + info->fStemV = 0; + static const UniChar stem_chars[] = {'i', 'I', '!', '1'}; + const size_t count = sizeof(stem_chars) / sizeof(stem_chars[0]); + CGGlyph glyphs[count]; + CGRect boundingRects[count]; + if (CTFontGetGlyphsForCharacters(ctFont.get(), stem_chars, glyphs, count)) { + CTFontGetBoundingRectsForGlyphs(ctFont.get(), kCTFontOrientationHorizontal, + glyphs, boundingRects, count); + for (size_t i = 0; i < count; i++) { + int16_t width = (int16_t) boundingRects[i].size.width; + if (width > 0 && width < min_width) { + min_width = width; + info->fStemV = min_width; + } + } + } + return info; +} + +static SK_SFNT_ULONG get_font_type_tag(CTFontRef ctFont) { + SkUniqueCFRef<CFNumberRef> fontFormatRef( + static_cast<CFNumberRef>(CTFontCopyAttribute(ctFont, kCTFontFormatAttribute))); + if (!fontFormatRef) { + return 0; + } + + SInt32 fontFormatValue; + if (!CFNumberGetValue(fontFormatRef.get(), kCFNumberSInt32Type, &fontFormatValue)) { + return 0; + } + + switch (fontFormatValue) { + case kCTFontFormatOpenTypePostScript: + return SkSFNTHeader::fontType_OpenTypeCFF::TAG; + case kCTFontFormatOpenTypeTrueType: + return SkSFNTHeader::fontType_WindowsTrueType::TAG; + case kCTFontFormatTrueType: + return SkSFNTHeader::fontType_MacTrueType::TAG; + case kCTFontFormatPostScript: + return SkSFNTHeader::fontType_PostScript::TAG; + case kCTFontFormatBitmap: + return SkSFNTHeader::fontType_MacTrueType::TAG; + case kCTFontFormatUnrecognized: + default: + return 0; + } +} + +std::unique_ptr<SkStreamAsset> SkTypeface_Mac::onOpenStream(int* ttcIndex) const { + *ttcIndex = 0; + + fInitStream([this]{ + if (fStream) { + return; + } + + SK_SFNT_ULONG fontType = get_font_type_tag(fFontRef.get()); + + // get table tags + int numTables = this->countTables(); + SkTDArray<SkFontTableTag> tableTags; + tableTags.setCount(numTables); + this->getTableTags(tableTags.begin()); + + // CT seems to be unreliable in being able to obtain the type, + // even if all we want is the first four bytes of the font resource. + // Just the presence of the FontForge 'FFTM' table seems to throw it off. + if (fontType == 0) { + fontType = SkSFNTHeader::fontType_WindowsTrueType::TAG; + + // see https://skbug.com/7630#c7 + bool couldBeCFF = false; + constexpr SkFontTableTag CFFTag = SkSetFourByteTag('C', 'F', 'F', ' '); + constexpr SkFontTableTag CFF2Tag = SkSetFourByteTag('C', 'F', 'F', '2'); + for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { + if (CFFTag == tableTags[tableIndex] || CFF2Tag == tableTags[tableIndex]) { + couldBeCFF = true; + } + } + if (couldBeCFF) { + fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG; + } + } + + // Sometimes CoreGraphics incorrectly thinks a font is kCTFontFormatPostScript. + // It is exceedingly unlikely that this is the case, so double check + // (see https://crbug.com/809763 ). + if (fontType == SkSFNTHeader::fontType_PostScript::TAG) { + // see if there are any required 'typ1' tables (see Adobe Technical Note #5180) + bool couldBeTyp1 = false; + constexpr SkFontTableTag TYPE1Tag = SkSetFourByteTag('T', 'Y', 'P', '1'); + constexpr SkFontTableTag CIDTag = SkSetFourByteTag('C', 'I', 'D', ' '); + for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { + if (TYPE1Tag == tableTags[tableIndex] || CIDTag == tableTags[tableIndex]) { + couldBeTyp1 = true; + } + } + if (!couldBeTyp1) { + fontType = SkSFNTHeader::fontType_OpenTypeCFF::TAG; + } + } + + // get the table sizes and accumulate the total size of the font + SkTDArray<size_t> tableSizes; + size_t totalSize = sizeof(SkSFNTHeader) + sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables; + for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { + size_t tableSize = this->getTableSize(tableTags[tableIndex]); + totalSize += (tableSize + 3) & ~3; + *tableSizes.append() = tableSize; + } + + // reserve memory for stream, and zero it (tables must be zero padded) + fStream.reset(new SkMemoryStream(totalSize)); + char* dataStart = (char*)fStream->getMemoryBase(); + sk_bzero(dataStart, totalSize); + char* dataPtr = dataStart; + + // compute font header entries + uint16_t entrySelector = 0; + uint16_t searchRange = 1; + while (searchRange < numTables >> 1) { + entrySelector++; + searchRange <<= 1; + } + searchRange <<= 4; + uint16_t rangeShift = (numTables << 4) - searchRange; + + // write font header + SkSFNTHeader* header = (SkSFNTHeader*)dataPtr; + header->fontType = fontType; + header->numTables = SkEndian_SwapBE16(numTables); + header->searchRange = SkEndian_SwapBE16(searchRange); + header->entrySelector = SkEndian_SwapBE16(entrySelector); + header->rangeShift = SkEndian_SwapBE16(rangeShift); + dataPtr += sizeof(SkSFNTHeader); + + // write tables + SkSFNTHeader::TableDirectoryEntry* entry = (SkSFNTHeader::TableDirectoryEntry*)dataPtr; + dataPtr += sizeof(SkSFNTHeader::TableDirectoryEntry) * numTables; + for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) { + size_t tableSize = tableSizes[tableIndex]; + this->getTableData(tableTags[tableIndex], 0, tableSize, dataPtr); + entry->tag = SkEndian_SwapBE32(tableTags[tableIndex]); + entry->checksum = SkEndian_SwapBE32(SkOTUtils::CalcTableChecksum((SK_OT_ULONG*)dataPtr, + tableSize)); + entry->offset = SkEndian_SwapBE32(SkToU32(dataPtr - dataStart)); + entry->logicalLength = SkEndian_SwapBE32(SkToU32(tableSize)); + + dataPtr += (tableSize + 3) & ~3; + ++entry; + } + }); + return fStream->duplicate(); +} + +struct NonDefaultAxesContext { + SkFixed* axisValue; + CFArrayRef cgAxes; +}; +static void set_non_default_axes(CFTypeRef key, CFTypeRef value, void* context) { + NonDefaultAxesContext* self = static_cast<NonDefaultAxesContext*>(context); + + if (CFGetTypeID(key) != CFStringGetTypeID() || CFGetTypeID(value) != CFNumberGetTypeID()) { + return; + } + + // The key is a CFString which is a string from the 'name' table. + // Search the cgAxes for an axis with this name, and use its index to store the value. + CFIndex keyIndex = -1; + CFStringRef keyString = static_cast<CFStringRef>(key); + for (CFIndex i = 0; i < CFArrayGetCount(self->cgAxes); ++i) { + CFTypeRef cgAxis = CFArrayGetValueAtIndex(self->cgAxes, i); + if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) { + continue; + } + + CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis); + CFTypeRef cgAxisName = CFDictionaryGetValue(cgAxisDict, kCGFontVariationAxisName); + if (!cgAxisName || CFGetTypeID(cgAxisName) != CFStringGetTypeID()) { + continue; + } + CFStringRef cgAxisNameString = static_cast<CFStringRef>(cgAxisName); + if (CFStringCompare(keyString, cgAxisNameString, 0) == kCFCompareEqualTo) { + keyIndex = i; + break; + } + } + if (keyIndex == -1) { + return; + } + + CFNumberRef valueNumber = static_cast<CFNumberRef>(value); + double valueDouble; + if (!CFNumberGetValue(valueNumber, kCFNumberDoubleType, &valueDouble) || + valueDouble < SkFixedToDouble(SK_FixedMin) || SkFixedToDouble(SK_FixedMax) < valueDouble) + { + return; + } + self->axisValue[keyIndex] = SkDoubleToFixed(valueDouble); +} +static bool get_variations(CTFontRef ctFont, CFIndex* cgAxisCount, + SkAutoSTMalloc<4, SkFixed>* axisValues) +{ + // In 10.10 and earlier, CTFontCopyVariationAxes and CTFontCopyVariation do not work when + // applied to fonts which started life with CGFontCreateWithDataProvider (they simply always + // return nullptr). As a result, we are limited to CGFontCopyVariationAxes and + // CGFontCopyVariations here until support for 10.10 and earlier is removed. + SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr)); + if (!cgFont) { + return false; + } + + SkUniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get())); + // If a font has no variations CGFontCopyVariations returns nullptr (instead of an empty dict). + if (!cgVariations) { + return false; + } + + SkUniqueCFRef<CFArrayRef> cgAxes(CGFontCopyVariationAxes(cgFont.get())); + if (!cgAxes) { + return false; + } + *cgAxisCount = CFArrayGetCount(cgAxes.get()); + axisValues->reset(*cgAxisCount); + + // Set all of the axes to their default values. + // Fail if any default value cannot be determined. + for (CFIndex i = 0; i < *cgAxisCount; ++i) { + CFTypeRef cgAxis = CFArrayGetValueAtIndex(cgAxes.get(), i); + if (CFGetTypeID(cgAxis) != CFDictionaryGetTypeID()) { + return false; + } + + CFDictionaryRef cgAxisDict = static_cast<CFDictionaryRef>(cgAxis); + CFTypeRef axisDefaultValue = CFDictionaryGetValue(cgAxisDict, + kCGFontVariationAxisDefaultValue); + if (!axisDefaultValue || CFGetTypeID(axisDefaultValue) != CFNumberGetTypeID()) { + return false; + } + CFNumberRef axisDefaultValueNumber = static_cast<CFNumberRef>(axisDefaultValue); + double axisDefaultValueDouble; + if (!CFNumberGetValue(axisDefaultValueNumber, kCFNumberDoubleType, &axisDefaultValueDouble)) + { + return false; + } + if (axisDefaultValueDouble < SkFixedToDouble(SK_FixedMin) || + SkFixedToDouble(SK_FixedMax) < axisDefaultValueDouble) + { + return false; + } + (*axisValues)[(int)i] = SkDoubleToFixed(axisDefaultValueDouble); + } + + // Override the default values with the given font's stated axis values. + NonDefaultAxesContext c = { axisValues->get(), cgAxes.get() }; + CFDictionaryApplyFunction(cgVariations.get(), set_non_default_axes, &c); + + return true; +} +std::unique_ptr<SkFontData> SkTypeface_Mac::onMakeFontData() const { + int index; + std::unique_ptr<SkStreamAsset> stream(this->onOpenStream(&index)); + + CFIndex cgAxisCount; + SkAutoSTMalloc<4, SkFixed> axisValues; + if (get_variations(fFontRef.get(), &cgAxisCount, &axisValues)) { + return std::make_unique<SkFontData>(std::move(stream), index, + axisValues.get(), cgAxisCount); + } + return std::make_unique<SkFontData>(std::move(stream), index, nullptr, 0); +} + +/** Creates a CT variation dictionary {tag, value} from a CG variation dictionary {name, value}. */ +static SkUniqueCFRef<CFDictionaryRef> ct_variation_from_cg_variation(CFDictionaryRef cgVariations, + CFArrayRef ctAxes) { + + SkUniqueCFRef<CFMutableDictionaryRef> ctVariation( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + CFIndex axisCount = CFArrayGetCount(ctAxes); + for (CFIndex i = 0; i < axisCount; ++i) { + CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes, i); + if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { + return nullptr; + } + CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); + + // The assumption is that values produced by kCTFontVariationAxisNameKey and + // kCGFontVariationAxisName will always be equal. + CFTypeRef axisName = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisNameKey); + if (!axisName || CFGetTypeID(axisName) != CFStringGetTypeID()) { + return nullptr; + } + + CFTypeRef axisValue = CFDictionaryGetValue(cgVariations, axisName); + if (!axisValue || CFGetTypeID(axisValue) != CFNumberGetTypeID()) { + return nullptr; + } + + CFTypeRef axisTag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); + if (!axisTag || CFGetTypeID(axisTag) != CFNumberGetTypeID()) { + return nullptr; + } + + CFDictionaryAddValue(ctVariation.get(), axisTag, axisValue); + } + return std::move(ctVariation); +} + +int SkTypeface_Mac::onGetVariationDesignPosition( + SkFontArguments::VariationPosition::Coordinate coordinates[], int coordinateCount) const +{ + // The CGFont variation data does not contain the tag. + + // CTFontCopyVariationAxes returns nullptr for CGFontCreateWithDataProvider fonts with + // macOS 10.10 and iOS 9 or earlier. When this happens, there is no API to provide the tag. + SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get())); + if (!ctAxes) { + return -1; + } + CFIndex axisCount = CFArrayGetCount(ctAxes.get()); + if (!coordinates || coordinateCount < axisCount) { + return axisCount; + } + + // This call always returns nullptr on 10.11 and under for CGFontCreateWithDataProvider fonts. + // When this happens, try converting the CG variation to a CT variation. + // On 10.12 and later, this only returns non-default variations. + SkUniqueCFRef<CFDictionaryRef> ctVariation(CTFontCopyVariation(fFontRef.get())); + if (!ctVariation) { + // When 10.11 and earlier are no longer supported, the following code can be replaced with + // return -1 and ct_variation_from_cg_variation can be removed. + SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr)); + if (!cgFont) { + return -1; + } + SkUniqueCFRef<CFDictionaryRef> cgVariations(CGFontCopyVariations(cgFont.get())); + if (!cgVariations) { + return -1; + } + ctVariation = ct_variation_from_cg_variation(cgVariations.get(), ctAxes.get()); + if (!ctVariation) { + return -1; + } + } + + for (int i = 0; i < axisCount; ++i) { + CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); + if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { + return -1; + } + CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); + + CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); + if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { + return -1; + } + CFNumberRef tagNumber = static_cast<CFNumberRef>(tag); + int64_t tagLong; + if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { + return -1; + } + coordinates[i].axis = tagLong; + + CGFloat variationCGFloat; + CFTypeRef variationValue = CFDictionaryGetValue(ctVariation.get(), tagNumber); + if (variationValue) { + if (CFGetTypeID(variationValue) != CFNumberGetTypeID()) { + return -1; + } + CFNumberRef variationNumber = static_cast<CFNumberRef>(variationValue); + if (!CFNumberGetValue(variationNumber, kCFNumberCGFloatType, &variationCGFloat)) { + return -1; + } + } else { + CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey); + if (!def || CFGetTypeID(def) != CFNumberGetTypeID()) { + return -1; + } + CFNumberRef defNumber = static_cast<CFNumberRef>(def); + if (!CFNumberGetValue(defNumber, kCFNumberCGFloatType, &variationCGFloat)) { + return -1; + } + } + coordinates[i].value = SkScalarFromCGFloat(variationCGFloat); + + } + return axisCount; +} + +int SkTypeface_Mac::onGetUPEM() const { + SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(fFontRef.get(), nullptr)); + return CGFontGetUnitsPerEm(cgFont.get()); +} + +SkTypeface::LocalizedStrings* SkTypeface_Mac::onCreateFamilyNameIterator() const { + sk_sp<SkTypeface::LocalizedStrings> nameIter = + SkOTUtils::LocalizedStrings_NameTable::MakeForFamilyNames(*this); + if (!nameIter) { + CFStringRef cfLanguageRaw; + SkUniqueCFRef<CFStringRef> cfFamilyName( + CTFontCopyLocalizedName(fFontRef.get(), kCTFontFamilyNameKey, &cfLanguageRaw)); + SkUniqueCFRef<CFStringRef> cfLanguage(cfLanguageRaw); + + SkString skLanguage; + SkString skFamilyName; + if (cfLanguage) { + SkStringFromCFString(cfLanguage.get(), &skLanguage); + } else { + skLanguage = "und"; //undetermined + } + if (cfFamilyName) { + SkStringFromCFString(cfFamilyName.get(), &skFamilyName); + } + + nameIter = sk_make_sp<SkOTUtils::LocalizedStrings_SingleName>(skFamilyName, skLanguage); + } + return nameIter.release(); +} + +int SkTypeface_Mac::onGetTableTags(SkFontTableTag tags[]) const { + SkUniqueCFRef<CFArrayRef> cfArray( + CTFontCopyAvailableTables(fFontRef.get(), kCTFontTableOptionNoOptions)); + if (!cfArray) { + return 0; + } + int count = SkToInt(CFArrayGetCount(cfArray.get())); + if (tags) { + for (int i = 0; i < count; ++i) { + uintptr_t fontTag = reinterpret_cast<uintptr_t>( + CFArrayGetValueAtIndex(cfArray.get(), i)); + tags[i] = static_cast<SkFontTableTag>(fontTag); + } + } + return count; +} + +// If, as is the case with web fonts, the CTFont data isn't available, +// the CGFont data may work. While the CGFont may always provide the +// right result, leave the CTFont code path to minimize disruption. +static SkUniqueCFRef<CFDataRef> copy_table_from_font(CTFontRef ctFont, SkFontTableTag tag) { + SkUniqueCFRef<CFDataRef> data(CTFontCopyTable(ctFont, (CTFontTableTag) tag, + kCTFontTableOptionNoOptions)); + if (!data) { + SkUniqueCFRef<CGFontRef> cgFont(CTFontCopyGraphicsFont(ctFont, nullptr)); + data.reset(CGFontCopyTableForTag(cgFont.get(), tag)); + } + return data; +} + +size_t SkTypeface_Mac::onGetTableData(SkFontTableTag tag, size_t offset, + size_t length, void* dstData) const { + SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag); + if (!srcData) { + return 0; + } + + size_t srcSize = CFDataGetLength(srcData.get()); + if (offset >= srcSize) { + return 0; + } + if (length > srcSize - offset) { + length = srcSize - offset; + } + if (dstData) { + memcpy(dstData, CFDataGetBytePtr(srcData.get()) + offset, length); + } + return length; +} + +sk_sp<SkData> SkTypeface_Mac::onCopyTableData(SkFontTableTag tag) const { + SkUniqueCFRef<CFDataRef> srcData = copy_table_from_font(fFontRef.get(), tag); + if (!srcData) { + return nullptr; + } + const UInt8* data = CFDataGetBytePtr(srcData.get()); + CFIndex length = CFDataGetLength(srcData.get()); + return SkData::MakeWithProc(data, length, + [](const void*, void* ctx) { + CFRelease((CFDataRef)ctx); + }, (void*)srcData.release()); +} + +SkScalerContext* SkTypeface_Mac::onCreateScalerContext(const SkScalerContextEffects& effects, + const SkDescriptor* desc) const { + return new SkScalerContext_Mac(sk_ref_sp(const_cast<SkTypeface_Mac*>(this)), effects, desc); +} + +void SkTypeface_Mac::onFilterRec(SkScalerContextRec* rec) const { + if (rec->fFlags & SkScalerContext::kLCD_BGROrder_Flag || + rec->fFlags & SkScalerContext::kLCD_Vertical_Flag) + { + rec->fMaskFormat = SkMask::kA8_Format; + // Render the glyphs as close as possible to what was requested. + // The above turns off subpixel rendering, but the user requested it. + // Normal hinting will cause the A8 masks to be generated from CoreGraphics subpixel masks. + // See comments below for more details. + rec->setHinting(SkFontHinting::kNormal); + } + + unsigned flagsWeDontSupport = SkScalerContext::kForceAutohinting_Flag | + SkScalerContext::kLCD_BGROrder_Flag | + SkScalerContext::kLCD_Vertical_Flag; + + rec->fFlags &= ~flagsWeDontSupport; + + const SkCTFontSmoothBehavior smoothBehavior = SkCTFontGetSmoothBehavior(); + + // Only two levels of hinting are supported. + // kNo_Hinting means avoid CoreGraphics outline dilation (smoothing). + // kNormal_Hinting means CoreGraphics outline dilation (smoothing) is allowed. + if (rec->getHinting() != SkFontHinting::kNone) { + rec->setHinting(SkFontHinting::kNormal); + } + // If smoothing has no effect, don't request it. + if (smoothBehavior == SkCTFontSmoothBehavior::none) { + rec->setHinting(SkFontHinting::kNone); + } + + // FIXME: lcd smoothed un-hinted rasterization unsupported. + // Tracked by http://code.google.com/p/skia/issues/detail?id=915 . + // There is no current means to honor a request for unhinted lcd, + // so arbitrarilly ignore the hinting request and honor lcd. + + // Hinting and smoothing should be orthogonal, but currently they are not. + // CoreGraphics has no API to influence hinting. However, its lcd smoothed + // output is drawn from auto-dilated outlines (the amount of which is + // determined by AppleFontSmoothing). Its regular anti-aliased output is + // drawn from un-dilated outlines. + + // The behavior of Skia is as follows: + // [AA][no-hint]: generate AA using CoreGraphic's AA output. + // [AA][yes-hint]: use CoreGraphic's LCD output and reduce it to a single + // channel. This matches [LCD][yes-hint] in weight. + // [LCD][no-hint]: currently unable to honor, and must pick which to respect. + // Currently side with LCD, effectively ignoring the hinting setting. + // [LCD][yes-hint]: generate LCD using CoreGraphic's LCD output. + if (rec->fMaskFormat == SkMask::kLCD16_Format) { + if (smoothBehavior == SkCTFontSmoothBehavior::subpixel) { + //CoreGraphics creates 555 masks for smoothed text anyway. + rec->fMaskFormat = SkMask::kLCD16_Format; + rec->setHinting(SkFontHinting::kNormal); + } else { + rec->fMaskFormat = SkMask::kA8_Format; + if (smoothBehavior != SkCTFontSmoothBehavior::none) { + rec->setHinting(SkFontHinting::kNormal); + } + } + } + + // CoreText provides no information as to whether a glyph will be color or not. + // Fonts may mix outlines and bitmaps, so information is needed on a glyph by glyph basis. + // If a font contains an 'sbix' table, consider it to be a color font, and disable lcd. + if (fHasColorGlyphs) { + rec->fMaskFormat = SkMask::kARGB32_Format; + } + + // Unhinted A8 masks (those not derived from LCD masks) must respect SK_GAMMA_APPLY_TO_A8. + // All other masks can use regular gamma. + if (SkMask::kA8_Format == rec->fMaskFormat && SkFontHinting::kNone == rec->getHinting()) { +#ifndef SK_GAMMA_APPLY_TO_A8 + // SRGBTODO: Is this correct? Do we want contrast boost? + rec->ignorePreBlend(); +#endif + } else { + SkColor color = rec->getLuminanceColor(); + if (smoothBehavior == SkCTFontSmoothBehavior::some) { + // CoreGraphics smoothed text without subpixel coverage blitting goes from a gamma of + // 2.0 for black foreground to a gamma of 1.0 for white foreground. Emulate this + // through the mask gamma by reducing the color values to 1/2. + color = SkColorSetRGB(SkColorGetR(color) * 1/2, + SkColorGetG(color) * 1/2, + SkColorGetB(color) * 1/2); + } else if (smoothBehavior == SkCTFontSmoothBehavior::subpixel) { + // CoreGraphics smoothed text with subpixel coverage blitting goes from a gamma of + // 2.0 for black foreground to a gamma of ~1.4? for white foreground. Emulate this + // through the mask gamma by reducing the color values to 3/4. + color = SkColorSetRGB(SkColorGetR(color) * 3/4, + SkColorGetG(color) * 3/4, + SkColorGetB(color) * 3/4); + } + rec->setLuminanceColor(color); + + // CoreGraphics dialates smoothed text to provide contrast. + rec->setContrast(0); + } +} + +/** Takes ownership of the CFStringRef. */ +static const char* get_str(CFStringRef ref, SkString* str) { + if (nullptr == ref) { + return nullptr; + } + SkStringFromCFString(ref, str); + CFRelease(ref); + return str->c_str(); +} + +void SkTypeface_Mac::onGetFamilyName(SkString* familyName) const { + get_str(CTFontCopyFamilyName(fFontRef.get()), familyName); +} + +void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc, + bool* isLocalStream) const { + SkString tmpStr; + + desc->setFamilyName(get_str(CTFontCopyFamilyName(fFontRef.get()), &tmpStr)); + desc->setFullName(get_str(CTFontCopyFullName(fFontRef.get()), &tmpStr)); + desc->setPostscriptName(get_str(CTFontCopyPostScriptName(fFontRef.get()), &tmpStr)); + desc->setStyle(this->fontStyle()); + *isLocalStream = fIsFromStream; +} + +void SkTypeface_Mac::onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const { + // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points: + // When a surrogate pair is detected, the glyph index used is the index of the high surrogate. + // It is documented that if a mapping is unavailable, the glyph will be set to 0. + + SkAutoSTMalloc<1024, UniChar> charStorage; + const UniChar* src; // UniChar is a UTF-16 16-bit code unit. + int srcCount; + const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(uni); + UniChar* utf16 = charStorage.reset(2 * count); + src = utf16; + for (int i = 0; i < count; ++i) { + utf16 += SkUTF::ToUTF16(utf32[i], utf16); + } + srcCount = SkToInt(utf16 - src); + + // If there are any non-bmp code points, the provided 'glyphs' storage will be inadequate. + SkAutoSTMalloc<1024, uint16_t> glyphStorage; + uint16_t* macGlyphs = glyphs; + if (srcCount > count) { + macGlyphs = glyphStorage.reset(srcCount); + } + + CTFontGetGlyphsForCharacters(fFontRef.get(), src, macGlyphs, srcCount); + + // If there were any non-bmp, then copy and compact. + // If all are bmp, 'glyphs' already contains the compact glyphs. + // If some are non-bmp, copy and compact into 'glyphs'. + if (srcCount > count) { + SkASSERT(glyphs != macGlyphs); + int extra = 0; + for (int i = 0; i < count; ++i) { + glyphs[i] = macGlyphs[i + extra]; + if (SkUTF16_IsLeadingSurrogate(src[i + extra])) { + ++extra; + } + } + } else { + SkASSERT(glyphs == macGlyphs); + } +} + +int SkTypeface_Mac::onCountGlyphs() const { + return SkToInt(CTFontGetGlyphCount(fFontRef.get())); +} + +/** Creates a dictionary suitable for setting the axes on a CTFont. */ +CTFontVariation SkCTVariationFromSkFontArguments(CTFontRef ct, const SkFontArguments& args) { + OpszVariation opsz; + constexpr const SkFourByteTag opszTag = SkSetFourByteTag('o','p','s','z'); + + SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(ct)); + if (!ctAxes) { + return CTFontVariation(); + } + CFIndex axisCount = CFArrayGetCount(ctAxes.get()); + + const SkFontArguments::VariationPosition position = args.getVariationDesignPosition(); + + SkUniqueCFRef<CFMutableDictionaryRef> dict( + CFDictionaryCreateMutable(kCFAllocatorDefault, axisCount, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + for (int i = 0; i < axisCount; ++i) { + CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); + if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { + return CTFontVariation(); + } + CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); + + CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); + if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { + return CTFontVariation(); + } + CFNumberRef tagNumber = static_cast<CFNumberRef>(tag); + int64_t tagLong; + if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { + return CTFontVariation(); + } + + // The variation axes can be set to any value, but cg will effectively pin them. + // Pin them here to normalize. + CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey); + CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey); + CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey); + if (!min || CFGetTypeID(min) != CFNumberGetTypeID() || + !max || CFGetTypeID(max) != CFNumberGetTypeID() || + !def || CFGetTypeID(def) != CFNumberGetTypeID()) + { + return CTFontVariation(); + } + CFNumberRef minNumber = static_cast<CFNumberRef>(min); + CFNumberRef maxNumber = static_cast<CFNumberRef>(max); + CFNumberRef defNumber = static_cast<CFNumberRef>(def); + double minDouble; + double maxDouble; + double defDouble; + if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) || + !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble) || + !CFNumberGetValue(defNumber, kCFNumberDoubleType, &defDouble)) + { + return CTFontVariation(); + } + + double value = defDouble; + // The position may be over specified. If there are multiple values for a given axis, + // use the last one since that's what css-fonts-4 requires. + for (int j = position.coordinateCount; j --> 0;) { + if (position.coordinates[j].axis == tagLong) { + value = SkTPin(SkScalarToDouble(position.coordinates[j].value), + minDouble, maxDouble); + if (tagLong == opszTag) { + opsz.isSet = true; + } + break; + } + } + if (tagLong == opszTag) { + opsz.value = value; + } + SkUniqueCFRef<CFNumberRef> valueNumber( + CFNumberCreate(kCFAllocatorDefault, kCFNumberDoubleType, &value)); + CFDictionaryAddValue(dict.get(), tagNumber, valueNumber.get()); + } + return { SkUniqueCFRef<CFDictionaryRef>(std::move(dict)), opsz }; +} + +sk_sp<SkTypeface> SkTypeface_Mac::onMakeClone(const SkFontArguments& args) const { + CTFontVariation ctVariation = SkCTVariationFromSkFontArguments(fFontRef.get(), args); + + SkUniqueCFRef<CTFontRef> ctVariant; + if (ctVariation.dict) { + SkUniqueCFRef<CFMutableDictionaryRef> attributes( + CFDictionaryCreateMutable(kCFAllocatorDefault, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + CFDictionaryAddValue(attributes.get(), + kCTFontVariationAttribute, ctVariation.dict.get()); + SkUniqueCFRef<CTFontDescriptorRef> varDesc( + CTFontDescriptorCreateWithAttributes(attributes.get())); + ctVariant.reset(CTFontCreateCopyWithAttributes(fFontRef.get(), 0, nullptr, varDesc.get())); + } else { + ctVariant.reset((CTFontRef)CFRetain(fFontRef.get())); + } + if (!ctVariant) { + return nullptr; + } + + return SkTypeface_Mac::Make(std::move(ctVariant), ctVariation.opsz, + fStream ? fStream->duplicate() : nullptr); +} + +int SkTypeface_Mac::onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], + int parameterCount) const +{ + SkUniqueCFRef<CFArrayRef> ctAxes(CTFontCopyVariationAxes(fFontRef.get())); + if (!ctAxes) { + return -1; + } + CFIndex axisCount = CFArrayGetCount(ctAxes.get()); + + if (!parameters || parameterCount < axisCount) { + return axisCount; + } + + // Added in 10.13 + CFStringRef* kCTFontVariationAxisHiddenKeyPtr = + static_cast<CFStringRef*>(dlsym(RTLD_DEFAULT, "kCTFontVariationAxisHiddenKey")); + + for (int i = 0; i < axisCount; ++i) { + CFTypeRef axisInfo = CFArrayGetValueAtIndex(ctAxes.get(), i); + if (CFDictionaryGetTypeID() != CFGetTypeID(axisInfo)) { + return -1; + } + CFDictionaryRef axisInfoDict = static_cast<CFDictionaryRef>(axisInfo); + + CFTypeRef tag = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisIdentifierKey); + if (!tag || CFGetTypeID(tag) != CFNumberGetTypeID()) { + return -1; + } + CFNumberRef tagNumber = static_cast<CFNumberRef>(tag); + int64_t tagLong; + if (!CFNumberGetValue(tagNumber, kCFNumberSInt64Type, &tagLong)) { + return -1; + } + + CFTypeRef min = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMinimumValueKey); + CFTypeRef max = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisMaximumValueKey); + CFTypeRef def = CFDictionaryGetValue(axisInfoDict, kCTFontVariationAxisDefaultValueKey); + if (!min || CFGetTypeID(min) != CFNumberGetTypeID() || + !max || CFGetTypeID(max) != CFNumberGetTypeID() || + !def || CFGetTypeID(def) != CFNumberGetTypeID()) + { + return -1; + } + CFNumberRef minNumber = static_cast<CFNumberRef>(min); + CFNumberRef maxNumber = static_cast<CFNumberRef>(max); + CFNumberRef defNumber = static_cast<CFNumberRef>(def); + double minDouble; + double maxDouble; + double defDouble; + if (!CFNumberGetValue(minNumber, kCFNumberDoubleType, &minDouble) || + !CFNumberGetValue(maxNumber, kCFNumberDoubleType, &maxDouble) || + !CFNumberGetValue(defNumber, kCFNumberDoubleType, &defDouble)) + { + return -1; + } + + SkFontParameters::Variation::Axis& skAxis = parameters[i]; + skAxis.tag = tagLong; + skAxis.min = minDouble; + skAxis.max = maxDouble; + skAxis.def = defDouble; + skAxis.setHidden(false); + if (kCTFontVariationAxisHiddenKeyPtr) { + CFTypeRef hidden = CFDictionaryGetValue(axisInfoDict,*kCTFontVariationAxisHiddenKeyPtr); + if (hidden) { + if (CFGetTypeID(hidden) != CFBooleanGetTypeID()) { + return -1; + } + CFBooleanRef hiddenBoolean = static_cast<CFBooleanRef>(hidden); + skAxis.setHidden(CFBooleanGetValue(hiddenBoolean)); + } + } + } + return axisCount; +} + +#endif diff --git a/chromium/third_party/skia/src/ports/SkTypeface_mac_ct.h b/chromium/third_party/skia/src/ports/SkTypeface_mac_ct.h new file mode 100644 index 00000000000..49f55b384f3 --- /dev/null +++ b/chromium/third_party/skia/src/ports/SkTypeface_mac_ct.h @@ -0,0 +1,128 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkTypeface_mac_ct_DEFINED +#define SkTypeface_mac_ct_DEFINED + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#include "include/core/SkFontArguments.h" +#include "include/core/SkFontParameters.h" +#include "include/core/SkFontStyle.h" +#include "include/core/SkRefCnt.h" +#include "include/core/SkScalar.h" +#include "include/core/SkStream.h" +#include "include/core/SkTypeface.h" +#include "include/private/SkOnce.h" +#include "src/utils/mac/SkUniqueCFRef.h" + +#ifdef SK_BUILD_FOR_MAC +#import <ApplicationServices/ApplicationServices.h> +#endif + +#ifdef SK_BUILD_FOR_IOS +#include <CoreText/CoreText.h> +#include <CoreText/CTFontManager.h> +#include <CoreGraphics/CoreGraphics.h> +#include <CoreFoundation/CoreFoundation.h> +#endif + +#include <memory> + +class SkData; +class SkDescriptor; +class SkFontData; +class SkFontDescriptor; +class SkScalerContext; +class SkString; +struct SkAdvancedTypefaceMetrics; +struct SkScalerContextEffects; +struct SkScalerContextRec; + +struct OpszVariation { + bool isSet = false; + double value = 0; +}; + +struct CTFontVariation { + SkUniqueCFRef<CFDictionaryRef> dict; + OpszVariation opsz; +}; + +CTFontVariation SkCTVariationFromSkFontArguments(CTFontRef ct, const SkFontArguments& args); + +SkUniqueCFRef<CTFontRef> SkCTFontCreateExactCopy(CTFontRef baseFont, CGFloat textSize, + OpszVariation opsz); + +SkFontStyle SkCTFontDescriptorGetSkFontStyle(CTFontDescriptorRef desc, bool fromDataProvider); + +CGFloat SkCTFontCTWeightForCSSWeight(int fontstyleWeight); +CGFloat SkCTFontCTWidthForCSSWidth(int fontstyleWidth); + +void SkStringFromCFString(CFStringRef src, SkString* dst); + +class SkTypeface_Mac : public SkTypeface { +private: + SkTypeface_Mac(SkUniqueCFRef<CTFontRef> fontRef, const SkFontStyle& fs, bool isFixedPitch, + OpszVariation opszVariation, std::unique_ptr<SkStreamAsset> providedData) + : SkTypeface(fs, isFixedPitch) + , fFontRef(std::move(fontRef)) + , fOpszVariation(opszVariation) + , fHasColorGlyphs( + SkToBool(CTFontGetSymbolicTraits(fFontRef.get()) & kCTFontColorGlyphsTrait)) + , fStream(std::move(providedData)) + , fIsFromStream(fStream) + { + SkASSERT(fFontRef); + } + +public: + static sk_sp<SkTypeface> Make(SkUniqueCFRef<CTFontRef> font, + OpszVariation opszVariation, + std::unique_ptr<SkStreamAsset> providedData); + + SkUniqueCFRef<CTFontRef> fFontRef; + const OpszVariation fOpszVariation; + const bool fHasColorGlyphs; + +protected: + int onGetUPEM() const override; + std::unique_ptr<SkStreamAsset> onOpenStream(int* ttcIndex) const override; + std::unique_ptr<SkFontData> onMakeFontData() const override; + int onGetVariationDesignPosition(SkFontArguments::VariationPosition::Coordinate coordinates[], + int coordinateCount) const override; + void onGetFamilyName(SkString* familyName) const override; + SkTypeface::LocalizedStrings* onCreateFamilyNameIterator() const override; + int onGetTableTags(SkFontTableTag tags[]) const override; + size_t onGetTableData(SkFontTableTag, size_t offset, size_t length, void* data) const override; + sk_sp<SkData> onCopyTableData(SkFontTableTag) const override; + SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&, + const SkDescriptor*) const override; + void onFilterRec(SkScalerContextRec*) const override; + void onGetFontDescriptor(SkFontDescriptor*, bool*) const override; + void getGlyphToUnicodeMap(SkUnichar*) const override; + std::unique_ptr<SkAdvancedTypefaceMetrics> onGetAdvancedMetrics() const override; + void onCharsToGlyphs(const SkUnichar* chars, int count, SkGlyphID glyphs[]) const override; + int onCountGlyphs() const override; + void getPostScriptGlyphNames(SkString*) const override {} + int onGetVariationDesignParameters(SkFontParameters::Variation::Axis parameters[], + int parameterCount) const override; + sk_sp<SkTypeface> onMakeClone(const SkFontArguments&) const override; + + void* onGetCTFontRef() const override { return (void*)fFontRef.get(); } + +private: + mutable std::unique_ptr<SkStreamAsset> fStream; + bool fIsFromStream; + mutable SkOnce fInitStream; + + typedef SkTypeface INHERITED; +}; + +#endif +#endif //SkTypeface_mac_ct_DEFINED diff --git a/chromium/third_party/skia/src/sfnt/SkOTTable_name.cpp b/chromium/third_party/skia/src/sfnt/SkOTTable_name.cpp index c9d47b8f82e..ecb3ce4bdd8 100644 --- a/chromium/third_party/skia/src/sfnt/SkOTTable_name.cpp +++ b/chromium/third_party/skia/src/sfnt/SkOTTable_name.cpp @@ -506,6 +506,7 @@ bool SkOTTableName::Iterator::next(SkOTTableName::Iterator::Record& record) { record.name.reset(); break; // continue? } + [[fallthrough]]; case SkOTTableName::Record::PlatformID::Unicode: case SkOTTableName::Record::PlatformID::ISO: SkString_from_UTF16BE(nameString, nameLength, record.name); diff --git a/chromium/third_party/skia/src/shaders/SkColorFilterShader.cpp b/chromium/third_party/skia/src/shaders/SkColorFilterShader.cpp index 6b39bc67b7a..c3cf2444a66 100644 --- a/chromium/third_party/skia/src/shaders/SkColorFilterShader.cpp +++ b/chromium/third_party/skia/src/shaders/SkColorFilterShader.cpp @@ -8,6 +8,7 @@ #include "include/core/SkShader.h" #include "include/core/SkString.h" #include "src/core/SkArenaAlloc.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkRasterPipeline.h" #include "src/core/SkReadBuffer.h" #include "src/core/SkVM.h" @@ -22,7 +23,7 @@ SkColorFilterShader::SkColorFilterShader(sk_sp<SkShader> shader, float alpha, sk_sp<SkColorFilter> filter) : fShader(std::move(shader)) - , fFilter(std::move(filter)) + , fFilter(as_CFB_sp(std::move(filter))) , fAlpha (alpha) { SkASSERT(fShader); @@ -39,9 +40,7 @@ sk_sp<SkFlattenable> SkColorFilterShader::CreateProc(SkReadBuffer& buffer) { } bool SkColorFilterShader::isOpaque() const { - return fShader->isOpaque() - && fAlpha == 1.0f - && (fFilter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) != 0; + return fShader->isOpaque() && fAlpha == 1.0f && as_CFB(fFilter)->isAlphaUnchanged(); } void SkColorFilterShader::flatten(SkWriteBuffer& buffer) const { @@ -62,12 +61,15 @@ bool SkColorFilterShader::onAppendStages(const SkStageRec& rec) const { } skvm::Color SkColorFilterShader::onProgram(skvm::Builder* p, - skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider& matrices, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { // Run the shader. - skvm::Color c = as_SB(fShader)->program(p, x,y, paint, ctm,localM, quality,dst, uniforms,alloc); + skvm::Color c = as_SB(fShader)->program(p, device,local, paint, + matrices,localM, + quality,dst, + uniforms,alloc); if (!c) { return {}; } diff --git a/chromium/third_party/skia/src/shaders/SkColorFilterShader.h b/chromium/third_party/skia/src/shaders/SkColorFilterShader.h index e1d470086d4..c3bd0b081fc 100644 --- a/chromium/third_party/skia/src/shaders/SkColorFilterShader.h +++ b/chromium/third_party/skia/src/shaders/SkColorFilterShader.h @@ -8,7 +8,7 @@ #ifndef SkColorFilterShader_DEFINED #define SkColorFilterShader_DEFINED -#include "include/core/SkColorFilter.h" +#include "src/core/SkColorFilterBase.h" #include "src/shaders/SkShaderBase.h" class SkArenaAlloc; @@ -26,16 +26,16 @@ private: void flatten(SkWriteBuffer&) const override; bool onAppendStages(const SkStageRec&) const override; - skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc*) const override; SK_FLATTENABLE_HOOKS(SkColorFilterShader) - sk_sp<SkShader> fShader; - sk_sp<SkColorFilter> fFilter; - float fAlpha; + sk_sp<SkShader> fShader; + sk_sp<SkColorFilterBase> fFilter; + float fAlpha; typedef SkShaderBase INHERITED; }; diff --git a/chromium/third_party/skia/src/shaders/SkColorShader.cpp b/chromium/third_party/skia/src/shaders/SkColorShader.cpp index 83149989275..8afdda1128e 100644 --- a/chromium/third_party/skia/src/shaders/SkColorShader.cpp +++ b/chromium/third_party/skia/src/shaders/SkColorShader.cpp @@ -92,16 +92,18 @@ bool SkColor4Shader::onAppendStages(const SkStageRec& rec) const { } skvm::Color SkColorShader::onProgram(skvm::Builder* p, - skvm::F32 /*x*/, skvm::F32 /*y*/, skvm::Color /*paint*/, - const SkMatrix& /*ctm*/, const SkMatrix* /*localM*/, + skvm::Coord /*device*/, skvm::Coord /*local*/, + skvm::Color /*paint*/, + const SkMatrixProvider&, const SkMatrix* /*localM*/, SkFilterQuality /*quality*/, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc*) const { return p->uniformPremul(SkColor4f::FromColor(fColor), sk_srgb_singleton(), uniforms, dst.colorSpace()); } skvm::Color SkColor4Shader::onProgram(skvm::Builder* p, - skvm::F32 /*x*/, skvm::F32 /*y*/, skvm::Color /*paint*/, - const SkMatrix& /*ctm*/, const SkMatrix* /*localM*/, + skvm::Coord /*device*/, skvm::Coord /*local*/, + skvm::Color /*paint*/, + const SkMatrixProvider&, const SkMatrix* /*localM*/, SkFilterQuality /*quality*/, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc*) const { return p->uniformPremul(fColor, fColorSpace.get(), @@ -118,7 +120,8 @@ skvm::Color SkColor4Shader::onProgram(skvm::Builder* p, std::unique_ptr<GrFragmentProcessor> SkColorShader::asFragmentProcessor( const GrFPArgs& args) const { SkPMColor4f color = SkColorToPMColor4f(fColor, *args.fDstColorInfo); - return GrConstColorProcessor::Make(color, GrConstColorProcessor::InputMode::kModulateA); + return GrConstColorProcessor::Make(/*inputFP=*/nullptr, color, + GrConstColorProcessor::InputMode::kModulateA); } std::unique_ptr<GrFragmentProcessor> SkColor4Shader::asFragmentProcessor( @@ -127,7 +130,7 @@ std::unique_ptr<GrFragmentProcessor> SkColor4Shader::asFragmentProcessor( args.fDstColorInfo->colorSpace(), kUnpremul_SkAlphaType }; SkColor4f color = fColor; steps.apply(color.vec()); - return GrConstColorProcessor::Make(color.premul(), + return GrConstColorProcessor::Make(/*inputFP=*/nullptr, color.premul(), GrConstColorProcessor::InputMode::kModulateA); } diff --git a/chromium/third_party/skia/src/shaders/SkColorShader.h b/chromium/third_party/skia/src/shaders/SkColorShader.h index 0e9225cb6db..5b876655970 100644 --- a/chromium/third_party/skia/src/shaders/SkColorShader.h +++ b/chromium/third_party/skia/src/shaders/SkColorShader.h @@ -44,8 +44,8 @@ private: bool onAppendStages(const SkStageRec&) const override; - skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc*) const override; @@ -69,8 +69,8 @@ private: void flatten(SkWriteBuffer&) const override; bool onAppendStages(const SkStageRec&) const override; - skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc*) const override; diff --git a/chromium/third_party/skia/src/shaders/SkComposeShader.cpp b/chromium/third_party/skia/src/shaders/SkComposeShader.cpp index 96ebf79726f..77fbfeb42ae 100644 --- a/chromium/third_party/skia/src/shaders/SkComposeShader.cpp +++ b/chromium/third_party/skia/src/shaders/SkComposeShader.cpp @@ -127,13 +127,14 @@ bool SkShader_Blend::onAppendStages(const SkStageRec& orig_rec) const { return true; } -skvm::Color SkShader_Blend::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, +skvm::Color SkShader_Blend::onProgram(skvm::Builder* p, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider& mats, const SkMatrix* localM, SkFilterQuality q, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { skvm::Color d,s; - if ((d = as_SB(fDst)->program(p, x,y, paint, ctm,localM, q, dst, uniforms, alloc)) && - (s = as_SB(fSrc)->program(p, x,y, paint, ctm,localM, q, dst, uniforms, alloc))) + if ((d = as_SB(fDst)->program(p, device,local, paint, mats,localM, q,dst, uniforms,alloc)) && + (s = as_SB(fSrc)->program(p, device,local, paint, mats,localM, q,dst, uniforms,alloc))) { return p->blend(fMode, s,d); } @@ -167,13 +168,14 @@ bool SkShader_Lerp::onAppendStages(const SkStageRec& orig_rec) const { return true; } -skvm::Color SkShader_Lerp::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, +skvm::Color SkShader_Lerp::onProgram(skvm::Builder* p, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider& mats, const SkMatrix* localM, SkFilterQuality q, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { skvm::Color d,s; - if ((d = as_SB(fDst)->program(p, x,y, paint, ctm,localM, q, dst, uniforms, alloc)) && - (s = as_SB(fSrc)->program(p, x,y, paint, ctm,localM, q, dst, uniforms, alloc))) + if ((d = as_SB(fDst)->program(p, device,local, paint, mats,localM, q,dst, uniforms,alloc)) && + (s = as_SB(fSrc)->program(p, device,local, paint, mats,localM, q,dst, uniforms,alloc))) { auto t = p->uniformF(uniforms->pushF(fWeight)); return { diff --git a/chromium/third_party/skia/src/shaders/SkComposeShader.h b/chromium/third_party/skia/src/shaders/SkComposeShader.h index dd36d38816a..96ae0a04b51 100644 --- a/chromium/third_party/skia/src/shaders/SkComposeShader.h +++ b/chromium/third_party/skia/src/shaders/SkComposeShader.h @@ -27,8 +27,8 @@ protected: SkShader_Blend(SkReadBuffer&); void flatten(SkWriteBuffer&) const override; bool onAppendStages(const SkStageRec&) const override; - skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality, const SkColorInfo& dst, skvm::Uniforms*, SkArenaAlloc*) const override; @@ -60,8 +60,8 @@ protected: SkShader_Lerp(SkReadBuffer&); void flatten(SkWriteBuffer&) const override; bool onAppendStages(const SkStageRec&) const override; - skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality, const SkColorInfo& dst, skvm::Uniforms*, SkArenaAlloc*) const override; diff --git a/chromium/third_party/skia/src/shaders/SkEmptyShader.h b/chromium/third_party/skia/src/shaders/SkEmptyShader.h index edd1e27dc2d..414be6c199d 100644 --- a/chromium/third_party/skia/src/shaders/SkEmptyShader.h +++ b/chromium/third_party/skia/src/shaders/SkEmptyShader.h @@ -37,9 +37,10 @@ protected: return false; } - skvm::Color onProgram(skvm::Builder*, skvm::F32, skvm::F32, skvm::Color, const SkMatrix&, - const SkMatrix*, SkFilterQuality, const SkColorInfo&, skvm::Uniforms*, - SkArenaAlloc*) const override; + skvm::Color onProgram(skvm::Builder*, skvm::Coord, skvm::Coord, skvm::Color, + const SkMatrixProvider&, const SkMatrix*, + SkFilterQuality, const SkColorInfo&, + skvm::Uniforms*, SkArenaAlloc*) const override; private: SK_FLATTENABLE_HOOKS(SkEmptyShader) diff --git a/chromium/third_party/skia/src/shaders/SkImageShader.cpp b/chromium/third_party/skia/src/shaders/SkImageShader.cpp index 93bada25380..7f69d8413d1 100755 --- a/chromium/third_party/skia/src/shaders/SkImageShader.cpp +++ b/chromium/third_party/skia/src/shaders/SkImageShader.cpp @@ -37,11 +37,13 @@ static SkTileMode optimize(SkTileMode tm, int dimension) { SkImageShader::SkImageShader(sk_sp<SkImage> img, SkTileMode tmx, SkTileMode tmy, const SkMatrix* localMatrix, + FilterEnum filtering, bool clampAsIfUnpremul) : INHERITED(localMatrix) , fImage(std::move(img)) , fTileModeX(optimize(tmx, fImage->width())) , fTileModeY(optimize(tmy, fImage->height())) + , fFiltering(filtering) , fClampAsIfUnpremul(clampAsIfUnpremul) {} @@ -51,18 +53,26 @@ SkImageShader::SkImageShader(sk_sp<SkImage> img, sk_sp<SkFlattenable> SkImageShader::CreateProc(SkReadBuffer& buffer) { auto tmx = buffer.read32LE<SkTileMode>(SkTileMode::kLastTileMode); auto tmy = buffer.read32LE<SkTileMode>(SkTileMode::kLastTileMode); + + FilterEnum filtering = kInheritFromPaint; + if (!buffer.isVersionLT(SkPicturePriv::kFilteringInImageShader_Version)) { + filtering = buffer.read32LE<FilterEnum>(kInheritFromPaint); + } + SkMatrix localMatrix; buffer.readMatrix(&localMatrix); sk_sp<SkImage> img = buffer.readImage(); if (!img) { return nullptr; } - return SkImageShader::Make(std::move(img), tmx, tmy, &localMatrix); + + return SkImageShader::Make(std::move(img), tmx, tmy, &localMatrix, filtering); } void SkImageShader::flatten(SkWriteBuffer& buffer) const { buffer.writeUInt((unsigned)fTileModeX); buffer.writeUInt((unsigned)fTileModeY); + buffer.writeUInt((unsigned)fFiltering); buffer.writeMatrix(this->getLocalMatrix()); buffer.writeImage(fImage.get()); SkASSERT(fClampAsIfUnpremul == false); @@ -75,9 +85,7 @@ bool SkImageShader::isOpaque() const { #ifdef SK_ENABLE_LEGACY_SHADERCONTEXT static bool legacy_shader_can_handle(const SkMatrix& inv) { - if (inv.hasPerspective()) { - return false; - } + SkASSERT(!inv.hasPerspective()); // Scale+translate methods are always present, but affine might not be. if (!SkOpts::S32_alpha_D32_filter_DXDY && !inv.isScaleTranslate()) { @@ -102,6 +110,11 @@ static bool legacy_shader_can_handle(const SkMatrix& inv) { SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec, SkArenaAlloc* alloc) const { + SkFilterQuality quality = this->resolveFiltering(rec.fPaint->getFilterQuality()); + + if (quality == kHigh_SkFilterQuality) { + return nullptr; + } if (fImage->alphaType() == kUnpremul_SkAlphaType) { return nullptr; } @@ -140,8 +153,16 @@ SkShaderBase::Context* SkImageShader::onMakeContext(const ContextRec& rec, return nullptr; } + // Send in a modified paint with different filter-quality if we don't agree with the paint + SkPaint modifiedPaint; + ContextRec modifiedRec = rec; + if (quality != rec.fPaint->getFilterQuality()) { + modifiedPaint = *rec.fPaint; + modifiedPaint.setFilterQuality(quality); + modifiedRec.fPaint = &modifiedPaint; + } return SkBitmapProcLegacyShader::MakeContext(*this, fTileModeX, fTileModeY, - as_IB(fImage.get()), rec, alloc); + as_IB(fImage.get()), modifiedRec, alloc); } #endif @@ -159,11 +180,14 @@ SkImage* SkImageShader::onIsAImage(SkMatrix* texM, SkTileMode xy[]) const { sk_sp<SkShader> SkImageShader::Make(sk_sp<SkImage> image, SkTileMode tmx, SkTileMode tmy, const SkMatrix* localMatrix, + FilterEnum filtering, bool clampAsIfUnpremul) { if (!image) { return sk_make_sp<SkEmptyShader>(); } - return sk_sp<SkShader>{ new SkImageShader(image, tmx, tmy, localMatrix, clampAsIfUnpremul) }; + return sk_sp<SkShader>{ + new SkImageShader(image, tmx, tmy, localMatrix, filtering, clampAsIfUnpremul) + }; } /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -195,7 +219,7 @@ std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor( // are provided by the caller. bool doBicubic; GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode( - fImage->width(), fImage->height(), args.fFilterQuality, + fImage->width(), fImage->height(), this->resolveFiltering(args.fFilterQuality), args.fMatrixProvider.localToDevice(), *lm, args.fContext->priv().options().fSharpenMipmappedTextures, &doBicubic); GrMipMapped mipMapped = GrMipMapped::kNo; @@ -240,7 +264,7 @@ std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor( sk_sp<SkShader> SkMakeBitmapShader(const SkBitmap& src, SkTileMode tmx, SkTileMode tmy, const SkMatrix* localMatrix, SkCopyPixelsMode cpm) { return SkImageShader::Make(SkMakeImageFromRasterBitmap(src, cpm), - tmx, tmy, localMatrix); + tmx, tmy, localMatrix, SkImageShader::kInheritFromPaint); } sk_sp<SkShader> SkMakeBitmapShaderForPaint(const SkPaint& paint, const SkBitmap& src, @@ -336,14 +360,15 @@ static void tweak_quality_and_inv_matrix(SkFilterQuality* quality, SkMatrix* mat } bool SkImageShader::doStages(const SkStageRec& rec, SkImageStageUpdater* updater) const { - if (updater && rec.fPaint.getFilterQuality() == kMedium_SkFilterQuality) { + auto quality = this->resolveFiltering(rec.fPaint.getFilterQuality()); + + if (updater && quality == kMedium_SkFilterQuality) { // TODO: medium: recall RequestBitmap and update width/height accordingly return false; } SkRasterPipeline* p = rec.fPipeline; SkArenaAlloc* alloc = rec.fAlloc; - auto quality = rec.fPaint.getFilterQuality(); SkMatrix matrix; if (!this->computeTotalInverse(rec.fMatrixProvider.localToDevice(), rec.fLocalM, &matrix)) { @@ -464,14 +489,6 @@ bool SkImageShader::doStages(const SkStageRec& rec, SkImageStageUpdater* updater }; auto append_misc = [&] { - // This is an inessential optimization... it's logically safe to set this to false. - // But if... - // - we know the image is definitely normalized, and - // - we're doing some color space conversion, and - // - sRGB curves are involved, - // then we can use slightly faster math that doesn't work well outside [0,1]. - bool src_is_normalized = SkColorTypeIsNormalized(info.colorType()); - SkColorSpace* cs = info.colorSpace(); SkAlphaType at = info.alphaType(); @@ -480,7 +497,6 @@ bool SkImageShader::doStages(const SkStageRec& rec, SkImageStageUpdater* updater SkColor4f rgb = rec.fPaint.getColor4f(); p->append_set_rgb(alloc, rgb); - src_is_normalized = rgb.fitsInBytes(); cs = sk_srgb_singleton(); at = kUnpremul_SkAlphaType; } @@ -491,13 +507,12 @@ bool SkImageShader::doStages(const SkStageRec& rec, SkImageStageUpdater* updater p->append(at == kUnpremul_SkAlphaType || fClampAsIfUnpremul ? SkRasterPipeline::clamp_1 : SkRasterPipeline::clamp_a); - src_is_normalized = true; } // Transform color space and alpha type to match shader convention (dst CS, premul alpha). alloc->make<SkColorSpaceXformSteps>(cs, at, rec.fDstCS, kPremul_SkAlphaType) - ->apply(p, src_is_normalized); + ->apply(p); return true; }; @@ -624,12 +639,15 @@ SkStageUpdater* SkImageShader::onAppendUpdatableStages(const SkStageRec& rec) co return this->doStages(rec, updater) ? updater : nullptr; } -skvm::Color SkImageShader::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, +skvm::Color SkImageShader::onProgram(skvm::Builder* p, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider& matrices, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { + quality = this->resolveFiltering(quality); + SkMatrix inv; - if (!this->computeTotalInverse(ctm, localM, &inv)) { + if (!this->computeTotalInverse(matrices.localToDevice(), localM, &inv)) { return {}; } @@ -646,7 +664,7 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, inv.normalizePerspective(); // Apply matrix to convert dst coords to sample center coords. - SkShaderBase::ApplyMatrix(p, inv, &x,&y,uniforms); + local = SkShaderBase::ApplyMatrix(p, inv, local, uniforms); // Bail out if sample() can't yet handle our image's color type. switch (pm.colorType()) { @@ -771,14 +789,14 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color c; if (quality == kNone_SkFilterQuality) { - c = sample(x,y); + c = sample(local.x,local.y); } else if (quality == kLow_SkFilterQuality) { // Our four sample points are the corners of a logical 1x1 pixel // box surrounding (x,y) at (0.5,0.5) off-center. - skvm::F32 left = x - 0.5f, - top = y - 0.5f, - right = x + 0.5f, - bottom = y + 0.5f; + skvm::F32 left = local.x - 0.5f, + top = local.y - 0.5f, + right = local.x + 0.5f, + bottom = local.y + 0.5f; // The fractional parts of right and bottom are our lerp factors in x and y respectively. skvm::F32 fx = fract(right ), @@ -791,8 +809,8 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, // All bicubic samples have the same fractional offset (fx,fy) from the center. // They're either the 16 corners of a 3x3 grid/ surrounding (x,y) at (0.5,0.5) off-center. - skvm::F32 fx = fract(x + 0.5f), - fy = fract(y + 0.5f); + skvm::F32 fx = fract(local.x + 0.5f), + fy = fract(local.y + 0.5f); // See GrCubicEffect for details of these weights. // TODO: these maybe don't seem right looking at gm/bicubic and GrBicubicEffect. @@ -819,9 +837,9 @@ skvm::Color SkImageShader::onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, c.r = c.g = c.b = c.a = p->splat(0.0f); - skvm::F32 sy = y - 1.5f; + skvm::F32 sy = local.y - 1.5f; for (int j = 0; j < 4; j++, sy += 1.0f) { - skvm::F32 sx = x - 1.5f; + skvm::F32 sx = local.x - 1.5f; for (int i = 0; i < 4; i++, sx += 1.0f) { skvm::Color s = sample(sx,sy); skvm::F32 w = wx[i] * wy[j]; diff --git a/chromium/third_party/skia/src/shaders/SkImageShader.h b/chromium/third_party/skia/src/shaders/SkImageShader.h index 24f6b81b76c..a653a9f332a 100644 --- a/chromium/third_party/skia/src/shaders/SkImageShader.h +++ b/chromium/third_party/skia/src/shaders/SkImageShader.h @@ -17,10 +17,20 @@ class SkImageStageUpdater; class SkImageShader : public SkShaderBase { public: + enum FilterEnum { // first 4 entries match SkFilterQuality + kNone, + kLow, + kMedium, + kHigh, + // this is the special value for backward compatibility + kInheritFromPaint, + }; + static sk_sp<SkShader> Make(sk_sp<SkImage>, SkTileMode tmx, SkTileMode tmy, const SkMatrix* localMatrix, + FilterEnum, bool clampAsIfUnpremul = false); bool isOpaque() const override; @@ -36,6 +46,7 @@ private: SkTileMode tmx, SkTileMode tmy, const SkMatrix* localMatrix, + FilterEnum, bool clampAsIfUnpremul); void flatten(SkWriteBuffer&) const override; @@ -47,16 +58,21 @@ private: bool onAppendStages(const SkStageRec&) const override; SkStageUpdater* onAppendUpdatableStages(const SkStageRec&) const override; - skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc*) const override; bool doStages(const SkStageRec&, SkImageStageUpdater* = nullptr) const; + SkFilterQuality resolveFiltering(SkFilterQuality paintQuality) const { + return fFiltering == kInheritFromPaint ? paintQuality : (SkFilterQuality)fFiltering; + } + sk_sp<SkImage> fImage; const SkTileMode fTileModeX; const SkTileMode fTileModeY; + const FilterEnum fFiltering; const bool fClampAsIfUnpremul; friend class SkShaderBase; diff --git a/chromium/third_party/skia/src/shaders/SkLocalMatrixShader.cpp b/chromium/third_party/skia/src/shaders/SkLocalMatrixShader.cpp index 66ee52be696..c0ef126ffa4 100644 --- a/chromium/third_party/skia/src/shaders/SkLocalMatrixShader.cpp +++ b/chromium/third_party/skia/src/shaders/SkLocalMatrixShader.cpp @@ -12,6 +12,7 @@ #if SK_SUPPORT_GPU #include "src/gpu/GrFragmentProcessor.h" +#include "src/gpu/effects/generated/GrDeviceSpaceEffect.h" #endif #if SK_SUPPORT_GPU @@ -77,15 +78,18 @@ bool SkLocalMatrixShader::onAppendStages(const SkStageRec& rec) const { skvm::Color SkLocalMatrixShader::onProgram(skvm::Builder* p, - skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider& matrices, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { SkTCopyOnFirstWrite<SkMatrix> lm(this->getLocalMatrix()); if (localM) { lm.writable()->preConcat(*localM); } - return as_SB(fProxyShader)->program(p, x,y, paint, ctm,lm.get(), quality,dst, uniforms,alloc); + return as_SB(fProxyShader)->program(p, device,local, paint, + matrices,lm.get(), + quality,dst, + uniforms,alloc); } sk_sp<SkShader> SkShader::makeWithLocalMatrix(const SkMatrix& localMatrix) const { @@ -152,11 +156,16 @@ protected: return as_SB(fProxyShader)->appendStages(newRec); } - skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color onProgram(skvm::Builder* p, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider& matrices, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override { - return as_SB(fProxyShader)->program(p, x,y,paint, fCTM,localM, quality,dst, uniforms,alloc); + SkOverrideDeviceMatrixProvider matrixProvider(matrices, fCTM); + return as_SB(fProxyShader)->program(p, device,local, paint, + matrixProvider,localM, + quality,dst, + uniforms,alloc); } private: @@ -172,8 +181,23 @@ private: #if SK_SUPPORT_GPU std::unique_ptr<GrFragmentProcessor> SkCTMShader::asFragmentProcessor( const GrFPArgs& args) const { - return as_SB(fProxyShader)->asFragmentProcessor( - GrFPArgs::WithPreLocalMatrix(args, this->getLocalMatrix())); + SkMatrix ctmInv; + if (!fCTM.invert(&ctmInv)) { + return nullptr; + } + + auto ctmProvider = SkOverrideDeviceMatrixProvider(args.fMatrixProvider, fCTM); + auto base = as_SB(fProxyShader)->asFragmentProcessor( + GrFPArgs::WithPreLocalMatrix(args.withNewMatrixProvider(ctmProvider), + this->getLocalMatrix())); + if (!base) { + return nullptr; + } + + // In order for the shader to be evaluated with the original CTM, we explicitly evaluate it + // at sk_FragCoord, and pass that through the inverse of the original CTM. This avoids requiring + // local coords for the shader and mapping from the draw's local to device and then back. + return GrDeviceSpaceEffect::Make(std::move(base), ctmInv); } #endif @@ -183,6 +207,5 @@ sk_sp<SkFlattenable> SkCTMShader::CreateProc(SkReadBuffer& buffer) { } sk_sp<SkShader> SkShaderBase::makeWithCTM(const SkMatrix& postM) const { - return postM.isIdentity() ? sk_ref_sp(this) - : sk_sp<SkShader>(new SkCTMShader(sk_ref_sp(this), postM)); + return sk_sp<SkShader>(new SkCTMShader(sk_ref_sp(this), postM)); } diff --git a/chromium/third_party/skia/src/shaders/SkLocalMatrixShader.h b/chromium/third_party/skia/src/shaders/SkLocalMatrixShader.h index 603e30e2603..b1fd8826901 100644 --- a/chromium/third_party/skia/src/shaders/SkLocalMatrixShader.h +++ b/chromium/third_party/skia/src/shaders/SkLocalMatrixShader.h @@ -48,8 +48,8 @@ protected: bool onAppendStages(const SkStageRec&) const override; - skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc*) const override; diff --git a/chromium/third_party/skia/src/shaders/SkPerlinNoiseShader.cpp b/chromium/third_party/skia/src/shaders/SkPerlinNoiseShader.cpp index 2d00c03aa4a..a17d7507f54 100644 --- a/chromium/third_party/skia/src/shaders/SkPerlinNoiseShader.cpp +++ b/chromium/third_party/skia/src/shaders/SkPerlinNoiseShader.cpp @@ -21,6 +21,7 @@ #include "src/gpu/GrCoordTransform.h" #include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/SkGr.h" +#include "src/gpu/effects/GrTextureEffect.h" #include "src/gpu/effects/generated/GrConstColorProcessor.h" #include "src/gpu/glsl/GrGLSLFragmentProcessor.h" #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h" @@ -119,7 +120,7 @@ public: fPermutationsBitmap.installPixels(info, fLatticeSelector, info.minRowBytes()); fPermutationsBitmap.setImmutable(); - info = SkImageInfo::MakeN32Premul(kBlockSize, 4); + info = SkImageInfo::Make(kBlockSize, 4, kRGBA_8888_SkColorType, kPremul_SkAlphaType); fNoiseBitmap.installPixels(info, fNoise[0][0], info.minRowBytes()); fNoiseBitmap.setImmutable(); @@ -144,7 +145,7 @@ public: 1, 0, 2, 0, 0, 2, 1, 0, 1, 0, 0, 0 }; - info = SkImageInfo::MakeN32Premul(16, 1); + info = SkImageInfo::Make(16, 1, kBGRA_8888_SkColorType, kPremul_SkAlphaType); fGradientBitmap.installPixels(info, gradients, info.minRowBytes()); fGradientBitmap.setImmutable(); #endif @@ -717,13 +718,26 @@ private: class GrPerlinNoise2Effect : public GrFragmentProcessor { public: static std::unique_ptr<GrFragmentProcessor> Make( - SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles, + SkPerlinNoiseShaderImpl::Type type, + int numOctaves, + bool stitchTiles, std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData, - GrSurfaceProxyView permutationsView, GrSurfaceProxyView noiseView, - const SkMatrix& matrix) { - return std::unique_ptr<GrFragmentProcessor>(new GrPerlinNoise2Effect( - type, numOctaves, stitchTiles, std::move(paintingData), - std::move(permutationsView), std::move(noiseView), matrix)); + GrSurfaceProxyView permutationsView, + GrSurfaceProxyView noiseView, + const SkMatrix& matrix, + const GrCaps& caps) { + static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat, + GrSamplerState::WrapMode::kClamp, + GrSamplerState::Filter::kNearest}; + auto permutationsFP = + GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType, + SkMatrix::I(), kRepeatXSampler, caps); + auto noiseFP = GrTextureEffect::Make(std::move(noiseView), kPremul_SkAlphaType, + SkMatrix::I(), kRepeatXSampler, caps); + + return std::unique_ptr<GrFragmentProcessor>( + new GrPerlinNoise2Effect(type, numOctaves, stitchTiles, std::move(paintingData), + std::move(permutationsFP), std::move(noiseFP), matrix)); } const char* name() const override { return "PerlinNoise"; } @@ -759,19 +773,20 @@ private: fPaintingData->fStitchDataInit == s.fPaintingData->fStitchDataInit; } - GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type, int numOctaves, bool stitchTiles, + GrPerlinNoise2Effect(SkPerlinNoiseShaderImpl::Type type, + int numOctaves, + bool stitchTiles, std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData, - GrSurfaceProxyView permutationsView, - GrSurfaceProxyView noiseView, + std::unique_ptr<GrFragmentProcessor> permutationsFP, + std::unique_ptr<GrFragmentProcessor> noiseFP, const SkMatrix& matrix) : INHERITED(kGrPerlinNoise2Effect_ClassID, kNone_OptimizationFlags) , fType(type) , fNumOctaves(numOctaves) , fStitchTiles(stitchTiles) - , fPermutationsSampler(std::move(permutationsView)) - , fNoiseSampler(std::move(noiseView)) , fPaintingData(std::move(paintingData)) { - this->setTextureSamplerCnt(2); + this->registerExplicitlySampledChild(std::move(permutationsFP)); + this->registerExplicitlySampledChild(std::move(noiseFP)); fCoordTransform = GrCoordTransform(matrix); this->addCoordTransform(&fCoordTransform); } @@ -782,16 +797,11 @@ private: , fCoordTransform(that.fCoordTransform) , fNumOctaves(that.fNumOctaves) , fStitchTiles(that.fStitchTiles) - , fPermutationsSampler(that.fPermutationsSampler) - , fNoiseSampler(that.fNoiseSampler) , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) { - this->setTextureSamplerCnt(2); + this->cloneAndRegisterAllChildProcessors(that); this->addCoordTransform(&fCoordTransform); } - const TextureSampler& onTextureSampler(int i) const override { - return IthTextureSampler(i, fPermutationsSampler, fNoiseSampler); - } GR_DECLARE_FRAGMENT_PROCESSOR_TEST @@ -799,8 +809,7 @@ private: GrCoordTransform fCoordTransform; int fNumOctaves; bool fStitchTiles; - TextureSampler fPermutationsSampler; - TextureSampler fNoiseSampler; + std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData; typedef GrFragmentProcessor INHERITED; @@ -851,86 +860,36 @@ void GrGLPerlinNoise::emitCode(EmitArgs& args) { stitchDataUni = uniformHandler->getUniformCStr(fStitchDataUni); } - // There are 4 lines, so the center of each line is 1/8, 3/8, 5/8 and 7/8 - const char* chanCoordR = "0.125"; - const char* chanCoordG = "0.375"; - const char* chanCoordB = "0.625"; - const char* chanCoordA = "0.875"; - const char* chanCoord = "chanCoord"; - const char* stitchData = "stitchData"; - const char* ratio = "ratio"; - const char* noiseVec = "noiseVec"; - const char* noiseSmooth = "noiseSmooth"; - const char* floorVal = "floorVal"; - const char* fractVal = "fractVal"; - const char* uv = "uv"; - const char* ab = "ab"; - const char* latticeIdx = "latticeIdx"; - const char* bcoords = "bcoords"; - const char* lattice = "lattice"; - const char* inc8bit = "0.00390625"; // 1.0 / 256.0 - // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a - // [-1,1] vector and perform a dot product between that vector and the provided vector. - const char* dotLattice = "dot(((%s.ga + %s.rb * half2(%s)) * half2(2.0) - half2(1.0)), %s);"; - // Add noise function - const GrShaderVar gPerlinNoiseArgs[] = { - GrShaderVar(chanCoord, kHalf_GrSLType), - GrShaderVar(noiseVec, kHalf2_GrSLType) - }; + const GrShaderVar gPerlinNoiseArgs[] = {{"chanCoord", kHalf_GrSLType }, + {"noiseVec ", kHalf2_GrSLType}}; - const GrShaderVar gPerlinNoiseStitchArgs[] = { - GrShaderVar(chanCoord, kHalf_GrSLType), - GrShaderVar(noiseVec, kHalf2_GrSLType), - GrShaderVar(stitchData, kHalf2_GrSLType) - }; + const GrShaderVar gPerlinNoiseStitchArgs[] = {{"chanCoord" , kHalf_GrSLType }, + {"noiseVec" , kHalf2_GrSLType}, + {"stitchData", kHalf2_GrSLType}}; SkString noiseCode; - noiseCode.appendf("\thalf4 %s;\n", floorVal); - noiseCode.appendf("\t%s.xy = floor(%s);\n", floorVal, noiseVec); - noiseCode.appendf("\t%s.zw = %s.xy + half2(1.0);\n", floorVal, floorVal); - noiseCode.appendf("\thalf2 %s = fract(%s);\n", fractVal, noiseVec); - - // smooth curve : t * t * (3 - 2 * t) - noiseCode.appendf("\n\thalf2 %s = %s * %s * (half2(3.0) - half2(2.0) * %s);", - noiseSmooth, fractVal, fractVal, fractVal); + noiseCode.append( + R"(half4 floorVal; + floorVal.xy = floor(noiseVec); + floorVal.zw = floorVal.xy + half2(1); + half2 fractVal = fract(noiseVec); + // smooth curve : t^2*(3 - 2*t) + half2 noiseSmooth = fractVal*fractVal*(half2(3) - 2*fractVal);)"); // Adjust frequencies if we're stitching tiles if (pne.stitchTiles()) { - noiseCode.appendf("\n\tif(%s.x >= %s.x) { %s.x -= %s.x; }", - floorVal, stitchData, floorVal, stitchData); - noiseCode.appendf("\n\tif(%s.y >= %s.y) { %s.y -= %s.y; }", - floorVal, stitchData, floorVal, stitchData); - noiseCode.appendf("\n\tif(%s.z >= %s.x) { %s.z -= %s.x; }", - floorVal, stitchData, floorVal, stitchData); - noiseCode.appendf("\n\tif(%s.w >= %s.y) { %s.w -= %s.y; }", - floorVal, stitchData, floorVal, stitchData); + noiseCode.append( + R"(if (floorVal.x >= stitchData.x) { floorVal.x -= stitchData.x; }; + if (floorVal.y >= stitchData.y) { floorVal.y -= stitchData.y; }; + if (floorVal.z >= stitchData.x) { floorVal.z -= stitchData.x; }; + if (floorVal.w >= stitchData.y) { floorVal.w -= stitchData.y; };)"); } - // Get texture coordinates and normalize - noiseCode.appendf("\n\t%s = fract(floor(mod(%s, 256.0)) / half4(256.0));\n", - floorVal, floorVal); - - // Get permutation for x - { - SkString xCoords(""); - xCoords.appendf("half2(%s.x, 0.5)", floorVal); - - noiseCode.appendf("\n\thalf2 %s;\n\t%s.x = ", latticeIdx, latticeIdx); - fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str()); - noiseCode.append(".r;"); - } - - // Get permutation for x + 1 - { - SkString xCoords(""); - xCoords.appendf("half2(%s.z, 0.5)", floorVal); - - noiseCode.appendf("\n\t%s.y = ", latticeIdx); - fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[0], xCoords.c_str()); - noiseCode.append(".r;"); - } + SkString sampleX = this->invokeChild(0, args, "half2(floorVal.x, 0.5)"); + SkString sampleY = this->invokeChild(0, args, "half2(floorVal.z, 0.5)"); + noiseCode.appendf("half2 latticeIdx = half2(%s.r, %s.r);", sampleX.c_str(), sampleY.c_str()); #if defined(SK_BUILD_FOR_ANDROID) // Android rounding for Tegra devices, like, for example: Xoom (Tegra 2), Nexus 7 (Tegra 3). @@ -939,65 +898,54 @@ void GrGLPerlinNoise::emitCode(EmitArgs& args) { // (or 0.484368 here). The following rounding operation prevents these precision issues from // affecting the result of the noise by making sure that we only have multiples of 1/255. // (Note that 1/255 is about 0.003921569, which is the value used here). - noiseCode.appendf("\n\t%s = floor(%s * half2(255.0) + half2(0.5)) * half2(0.003921569);", - latticeIdx, latticeIdx); + noiseCode.append( + "latticeIdx = floor(latticeIdx * half2(255.0) + half2(0.5)) * half2(0.003921569);"); #endif // Get (x,y) coordinates with the permutated x - noiseCode.appendf("\n\thalf4 %s = fract(%s.xyxy + %s.yyww);", bcoords, latticeIdx, floorVal); + noiseCode.append("half4 bcoords = 256*latticeIdx.xyxy + floorVal.yyww;"); + + noiseCode.append("half2 uv;"); + + // This is the math to convert the two 16bit integer packed into rgba 8 bit input into a + // [-1,1] vector and perform a dot product between that vector and the provided vector. + // Save it as a string because we will repeat it 4x. + static constexpr const char* inc8bit = "0.00390625"; // 1.0 / 256.0 + SkString dotLattice = + SkStringPrintf("dot((lattice.ga + lattice.rb*%s)*2 - half2(1), fractVal)", inc8bit); + + SkString sampleA = this->invokeChild(1, args, "half2(bcoords.x, chanCoord)"); + SkString sampleB = this->invokeChild(1, args, "half2(bcoords.y, chanCoord)"); + SkString sampleC = this->invokeChild(1, args, "half2(bcoords.w, chanCoord)"); + SkString sampleD = this->invokeChild(1, args, "half2(bcoords.z, chanCoord)"); - noiseCode.appendf("\n\n\thalf2 %s;", uv); // Compute u, at offset (0,0) - { - SkString latticeCoords(""); - latticeCoords.appendf("half2(%s.x, %s)", bcoords, chanCoord); - noiseCode.appendf("\n\thalf4 %s = ", lattice); - fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str()); - noiseCode.appendf(".bgra;\n\t%s.x = ", uv); - noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); - } + noiseCode.appendf("half4 lattice = %s;", sampleA.c_str()); + noiseCode.appendf("uv.x = %s;", dotLattice.c_str()); - noiseCode.appendf("\n\t%s.x -= 1.0;", fractVal); // Compute v, at offset (-1,0) - { - SkString latticeCoords(""); - latticeCoords.appendf("half2(%s.y, %s)", bcoords, chanCoord); - noiseCode.append("\n\tlattice = "); - fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str()); - noiseCode.appendf(".bgra;\n\t%s.y = ", uv); - noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); - } + noiseCode.append("fractVal.x -= 1.0;"); + noiseCode.appendf("lattice = %s;", sampleB.c_str()); + noiseCode.appendf("uv.y = %s;", dotLattice.c_str()); // Compute 'a' as a linear interpolation of 'u' and 'v' - noiseCode.appendf("\n\thalf2 %s;", ab); - noiseCode.appendf("\n\t%s.x = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); + noiseCode.append("half2 ab;"); + noiseCode.append("ab.x = mix(uv.x, uv.y, noiseSmooth.x);"); - noiseCode.appendf("\n\t%s.y -= 1.0;", fractVal); // Compute v, at offset (-1,-1) - { - SkString latticeCoords(""); - latticeCoords.appendf("half2(%s.w, %s)", bcoords, chanCoord); - noiseCode.append("\n\tlattice = "); - fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str()); - noiseCode.appendf(".bgra;\n\t%s.y = ", uv); - noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); - } + noiseCode.append("fractVal.y -= 1.0;"); + noiseCode.appendf("lattice = %s;", sampleC.c_str()); + noiseCode.appendf("uv.y = %s;", dotLattice.c_str()); - noiseCode.appendf("\n\t%s.x += 1.0;", fractVal); // Compute u, at offset (0,-1) - { - SkString latticeCoords(""); - latticeCoords.appendf("half2(%s.z, %s)", bcoords, chanCoord); - noiseCode.append("\n\tlattice = "); - fragBuilder->appendTextureLookup(&noiseCode, args.fTexSamplers[1], latticeCoords.c_str()); - noiseCode.appendf(".bgra;\n\t%s.x = ", uv); - noiseCode.appendf(dotLattice, lattice, lattice, inc8bit, fractVal); - } + noiseCode.append("fractVal.x += 1.0;"); + noiseCode.appendf("lattice = %s;", sampleD.c_str()); + noiseCode.appendf("uv.x = %s;", dotLattice.c_str()); // Compute 'b' as a linear interpolation of 'u' and 'v' - noiseCode.appendf("\n\t%s.y = mix(%s.x, %s.y, %s.x);", ab, uv, uv, noiseSmooth); + noiseCode.append("ab.y = mix(uv.x, uv.y, noiseSmooth.x);"); // Compute the noise as a linear interpolation of 'a' and 'b' - noiseCode.appendf("\n\treturn mix(%s.x, %s.y, %s.y);\n", ab, ab, noiseSmooth); + noiseCode.append("return mix(ab.x, ab.y, noiseSmooth.y);"); SkString noiseFuncName; if (pne.stitchTiles()) { @@ -1011,68 +959,73 @@ void GrGLPerlinNoise::emitCode(EmitArgs& args) { } // There are rounding errors if the floor operation is not performed here - fragBuilder->codeAppendf("\n\t\thalf2 %s = half2(floor(%s.xy) * %s);", - noiseVec, vCoords.c_str(), baseFrequencyUni); + fragBuilder->codeAppendf("half2 noiseVec = half2(floor(%s.xy) * %s);", + vCoords.c_str(), baseFrequencyUni); // Clear the color accumulator - fragBuilder->codeAppendf("\n\t\t%s = half4(0.0);", args.fOutputColor); + fragBuilder->codeAppendf("%s = half4(0.0);", args.fOutputColor); if (pne.stitchTiles()) { // Set up TurbulenceInitial stitch values. - fragBuilder->codeAppendf("\n\t\thalf2 %s = %s;", stitchData, stitchDataUni); + fragBuilder->codeAppendf("half2 stitchData = %s;", stitchDataUni); } - fragBuilder->codeAppendf("\n\t\thalf %s = 1.0;", ratio); + fragBuilder->codeAppendf("half ratio = 1.0;"); // Loop over all octaves fragBuilder->codeAppendf("for (int octave = 0; octave < %d; ++octave) {", pne.numOctaves()); - - fragBuilder->codeAppendf("\n\t\t\t%s += ", args.fOutputColor); + fragBuilder->codeAppendf(" %s += ", args.fOutputColor); if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) { fragBuilder->codeAppend("abs("); } + + // There are 4 lines, put y coords at center of each. + static constexpr const char* chanCoordR = "0.5"; + static constexpr const char* chanCoordG = "1.5"; + static constexpr const char* chanCoordB = "2.5"; + static constexpr const char* chanCoordA = "3.5"; if (pne.stitchTiles()) { - fragBuilder->codeAppendf( - "half4(\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s)," - "\n\t\t\t\t%s(%s, %s, %s),\n\t\t\t\t%s(%s, %s, %s))", - noiseFuncName.c_str(), chanCoordR, noiseVec, stitchData, - noiseFuncName.c_str(), chanCoordG, noiseVec, stitchData, - noiseFuncName.c_str(), chanCoordB, noiseVec, stitchData, - noiseFuncName.c_str(), chanCoordA, noiseVec, stitchData); + fragBuilder->codeAppendf(R"( + half4(%s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData)," + %s(%s, noiseVec, stitchData), %s(%s, noiseVec, stitchData)))", + noiseFuncName.c_str(), chanCoordR, + noiseFuncName.c_str(), chanCoordG, + noiseFuncName.c_str(), chanCoordB, + noiseFuncName.c_str(), chanCoordA); } else { - fragBuilder->codeAppendf( - "half4(\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s)," - "\n\t\t\t\t%s(%s, %s),\n\t\t\t\t%s(%s, %s))", - noiseFuncName.c_str(), chanCoordR, noiseVec, - noiseFuncName.c_str(), chanCoordG, noiseVec, - noiseFuncName.c_str(), chanCoordB, noiseVec, - noiseFuncName.c_str(), chanCoordA, noiseVec); + fragBuilder->codeAppendf(R"( + half4(%s(%s, noiseVec), %s(%s, noiseVec), + %s(%s, noiseVec), %s(%s, noiseVec)))", + noiseFuncName.c_str(), chanCoordR, + noiseFuncName.c_str(), chanCoordG, + noiseFuncName.c_str(), chanCoordB, + noiseFuncName.c_str(), chanCoordA); } if (pne.type() != SkPerlinNoiseShaderImpl::kFractalNoise_Type) { - fragBuilder->codeAppendf(")"); // end of "abs(" + fragBuilder->codeAppend(")"); // end of "abs(" } - fragBuilder->codeAppendf(" * %s;", ratio); + fragBuilder->codeAppend(" * ratio;"); - fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", noiseVec); - fragBuilder->codeAppendf("\n\t\t\t%s *= 0.5;", ratio); + fragBuilder->codeAppend(R"(noiseVec *= half2(2.0); + ratio *= 0.5;)"); if (pne.stitchTiles()) { - fragBuilder->codeAppendf("\n\t\t\t%s *= half2(2.0);", stitchData); + fragBuilder->codeAppend("stitchData *= half2(2.0);"); } - fragBuilder->codeAppend("\n\t\t}"); // end of the for loop on octaves + fragBuilder->codeAppend("}"); // end of the for loop on octaves if (pne.type() == SkPerlinNoiseShaderImpl::kFractalNoise_Type) { // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult) + 1) / 2 // by fractalNoise and (turbulenceFunctionResult) by turbulence. - fragBuilder->codeAppendf("\n\t\t%s = %s * half4(0.5) + half4(0.5);", - args.fOutputColor,args.fOutputColor); + fragBuilder->codeAppendf("%s = %s * half4(0.5) + half4(0.5);", + args.fOutputColor, args.fOutputColor); } // Clamp values - fragBuilder->codeAppendf("\n\t\t%s = saturate(%s);", args.fOutputColor, args.fOutputColor); + fragBuilder->codeAppendf("%s = saturate(%s);", args.fOutputColor, args.fOutputColor); // Pre-multiply the result - fragBuilder->codeAppendf("\n\t\t%s = half4(%s.rgb * %s.aaa, %s.a);\n", + fragBuilder->codeAppendf("%s = half4(%s.rgb * %s.aaa, %s.a);\n", args.fOutputColor, args.fOutputColor, args.fOutputColor, args.fOutputColor); } @@ -1116,7 +1069,7 @@ void GrGLPerlinNoise::onSetData(const GrGLSLProgramDataManager& pdman, if (turbulence.stitchTiles()) { const SkPerlinNoiseShaderImpl::StitchData& stitchData = turbulence.stitchData(); pdman.set2f(fStitchDataUni, SkIntToScalar(stitchData.fWidth), - SkIntToScalar(stitchData.fHeight)); + SkIntToScalar(stitchData.fHeight)); } } @@ -1143,13 +1096,24 @@ private: class GrImprovedPerlinNoiseEffect : public GrFragmentProcessor { public: static std::unique_ptr<GrFragmentProcessor> Make( - int octaves, SkScalar z, + int octaves, + SkScalar z, std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData, - GrSurfaceProxyView permutationsView, GrSurfaceProxyView gradientView, - const SkMatrix& matrix) { + GrSurfaceProxyView permutationsView, + GrSurfaceProxyView gradientView, + const SkMatrix& matrix, + const GrCaps& caps) { + static constexpr GrSamplerState kRepeatXSampler = {GrSamplerState::WrapMode::kRepeat, + GrSamplerState::WrapMode::kClamp, + GrSamplerState::Filter::kNearest}; + auto permutationsFP = + GrTextureEffect::Make(std::move(permutationsView), kPremul_SkAlphaType, + SkMatrix::I(), kRepeatXSampler, caps); + auto gradientFP = GrTextureEffect::Make(std::move(gradientView), kPremul_SkAlphaType, + SkMatrix::I(), kRepeatXSampler, caps); return std::unique_ptr<GrFragmentProcessor>(new GrImprovedPerlinNoiseEffect( - octaves, z, std::move(paintingData), std::move(permutationsView), - std::move(gradientView), matrix)); + octaves, z, std::move(paintingData), std::move(permutationsFP), + std::move(gradientFP), matrix)); } const char* name() const override { return "ImprovedPerlinNoise"; } @@ -1178,18 +1142,18 @@ private: fPaintingData->fBaseFrequency == s.fPaintingData->fBaseFrequency; } - GrImprovedPerlinNoiseEffect(int octaves, SkScalar z, + GrImprovedPerlinNoiseEffect(int octaves, + SkScalar z, std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> paintingData, - GrSurfaceProxyView permutationsView, - GrSurfaceProxyView gradientView, + std::unique_ptr<GrFragmentProcessor> permutationsFP, + std::unique_ptr<GrFragmentProcessor> gradientFP, const SkMatrix& matrix) : INHERITED(kGrImprovedPerlinNoiseEffect_ClassID, kNone_OptimizationFlags) , fOctaves(octaves) , fZ(z) - , fPermutationsSampler(std::move(permutationsView)) - , fGradientSampler(std::move(gradientView)) , fPaintingData(std::move(paintingData)) { - this->setTextureSamplerCnt(2); + this->registerExplicitlySampledChild(std::move(permutationsFP)); + this->registerExplicitlySampledChild(std::move(gradientFP)); fCoordTransform = GrCoordTransform(matrix); this->addCoordTransform(&fCoordTransform); } @@ -1199,24 +1163,17 @@ private: , fCoordTransform(that.fCoordTransform) , fOctaves(that.fOctaves) , fZ(that.fZ) - , fPermutationsSampler(that.fPermutationsSampler) - , fGradientSampler(that.fGradientSampler) , fPaintingData(new SkPerlinNoiseShaderImpl::PaintingData(*that.fPaintingData)) { - this->setTextureSamplerCnt(2); + this->cloneAndRegisterAllChildProcessors(that); this->addCoordTransform(&fCoordTransform); } - const TextureSampler& onTextureSampler(int i) const override { - return IthTextureSampler(i, fPermutationsSampler, fGradientSampler); - } - GR_DECLARE_FRAGMENT_PROCESSOR_TEST GrCoordTransform fCoordTransform; int fOctaves; SkScalar fZ; - TextureSampler fPermutationsSampler; - TextureSampler fGradientSampler; + std::unique_ptr<SkPerlinNoiseShaderImpl::PaintingData> fPaintingData; typedef GrFragmentProcessor INHERITED; @@ -1271,44 +1228,39 @@ void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) { // perm function const GrShaderVar permArgs[] = { - GrShaderVar("x", kHalf_GrSLType) + {"x", kHalf_GrSLType} }; + SkString samplePerm = this->invokeChild(0, args, "float2(x, 0.5)"); SkString permFuncName; - SkString permCode("return "); - // FIXME even though I'm creating these textures with kRepeat_TileMode, they're clamped. Not - // sure why. Using fract() (here and the next texture lookup) as a workaround. - fragBuilder->appendTextureLookup(&permCode, args.fTexSamplers[0], - "float2(fract(x / 256.0), 0.0)"); - permCode.append(".r * 255.0;"); + SkString permCode = SkStringPrintf("return %s.r * 255;", samplePerm.c_str()); fragBuilder->emitFunction(kHalf_GrSLType, "perm", SK_ARRAY_COUNT(permArgs), permArgs, permCode.c_str(), &permFuncName); // grad function const GrShaderVar gradArgs[] = { - GrShaderVar("x", kHalf_GrSLType), - GrShaderVar("p", kHalf3_GrSLType) + {"x", kHalf_GrSLType}, + {"p", kHalf3_GrSLType} }; + SkString sampleGrad = this->invokeChild(1, args, "float2(x, 0.5)"); SkString gradFuncName; - SkString gradCode("return half(dot("); - fragBuilder->appendTextureLookup(&gradCode, args.fTexSamplers[1], - "float2(fract(x / 16.0), 0.0)"); - gradCode.append(".rgb * 255.0 - float3(1.0), p));"); + SkString gradCode = SkStringPrintf("return half(dot(%s.rgb * 255.0 - float3(1.0), p));", + sampleGrad.c_str()); fragBuilder->emitFunction(kHalf_GrSLType, "grad", SK_ARRAY_COUNT(gradArgs), gradArgs, gradCode.c_str(), &gradFuncName); // lerp function const GrShaderVar lerpArgs[] = { - GrShaderVar("a", kHalf_GrSLType), - GrShaderVar("b", kHalf_GrSLType), - GrShaderVar("w", kHalf_GrSLType) + {"a", kHalf_GrSLType}, + {"b", kHalf_GrSLType}, + {"w", kHalf_GrSLType} }; SkString lerpFuncName; fragBuilder->emitFunction(kHalf_GrSLType, "lerp", SK_ARRAY_COUNT(lerpArgs), lerpArgs, "return a + w * (b - a);", &lerpFuncName); // noise function - const GrShaderVar noiseArgs[] = { - GrShaderVar("p", kHalf3_GrSLType), + const GrShaderVar noiseArgs[] = { + {"p", kHalf3_GrSLType}, }; SkString noiseFuncName; SkString noiseCode; @@ -1345,7 +1297,7 @@ void GrGLImprovedPerlinNoise::emitCode(EmitArgs& args) { // noiseOctaves function const GrShaderVar noiseOctavesArgs[] = { - GrShaderVar("p", kHalf3_GrSLType) + {"p", kHalf3_GrSLType} }; SkString noiseOctavesFuncName; SkString noiseOctavesCode; @@ -1432,9 +1384,13 @@ std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcesso const SkBitmap& gradientBitmap = paintingData->getGradientBitmap(); SkASSERT(SkIsPow2(gradientBitmap.width()) && SkIsPow2(gradientBitmap.height())); auto gradientView = GrMakeCachedBitmapProxyView(context, gradientBitmap); - return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, fSeed, std::move(paintingData), + return GrImprovedPerlinNoiseEffect::Make(fNumOctaves, + fSeed, + std::move(paintingData), std::move(permutationsView), - std::move(gradientView), m); + std::move(gradientView), + m, + *context->priv().caps()); } if (0 == fNumOctaves) { @@ -1443,13 +1399,13 @@ std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcesso // TODO: Either treat the output of this shader as sRGB or allow client to specify a // color space of the noise. Either way, this case (and the GLSL) need to convert to // the destination. - auto inner = - GrConstColorProcessor::Make(SkPMColor4f::FromBytes_RGBA(0x80404040), - GrConstColorProcessor::InputMode::kModulateRGBA); + auto inner = GrConstColorProcessor::Make( + /*inputFP=*/nullptr, SkPMColor4f::FromBytes_RGBA(0x80404040), + GrConstColorProcessor::InputMode::kModulateRGBA); return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner)); } // Emit zero. - return GrConstColorProcessor::Make(SK_PMColor4fTRANSPARENT, + return GrConstColorProcessor::Make(/*inputFP=*/nullptr, SK_PMColor4fTRANSPARENT, GrConstColorProcessor::InputMode::kIgnore); } @@ -1471,7 +1427,8 @@ std::unique_ptr<GrFragmentProcessor> SkPerlinNoiseShaderImpl::asFragmentProcesso std::move(paintingData), std::move(permutationsView), std::move(noiseView), - m); + m, + *context->priv().caps()); return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner)); } return nullptr; diff --git a/chromium/third_party/skia/src/shaders/SkPictureShader.cpp b/chromium/third_party/skia/src/shaders/SkPictureShader.cpp index 009ae54d36e..6a77004b49c 100644 --- a/chromium/third_party/skia/src/shaders/SkPictureShader.cpp +++ b/chromium/third_party/skia/src/shaders/SkPictureShader.cpp @@ -275,20 +275,24 @@ bool SkPictureShader::onAppendStages(const SkStageRec& rec) const { } skvm::Color SkPictureShader::onProgram(skvm::Builder* p, - skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider& matrices, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { auto lm = this->totalLocalMatrix(localM); // Keep bitmapShader alive by using alloc instead of stack memory auto& bitmapShader = *alloc->make<sk_sp<SkShader>>(); - bitmapShader = this->refBitmapShader(ctm, &lm, dst.colorType(), dst.colorSpace()); + bitmapShader = this->refBitmapShader(matrices.localToDevice(), &lm, + dst.colorType(), dst.colorSpace()); if (!bitmapShader) { return {}; } - return as_SB(bitmapShader)->program(p, x,y, paint, ctm, lm, quality, dst, uniforms, alloc); + return as_SB(bitmapShader)->program(p, device,local, paint, + matrices,lm, + quality,dst, + uniforms,alloc); } ///////////////////////////////////////////////////////////////////////////////////////// diff --git a/chromium/third_party/skia/src/shaders/SkPictureShader.h b/chromium/third_party/skia/src/shaders/SkPictureShader.h index 0bdc9cd9e09..01ef4b4d122 100644 --- a/chromium/third_party/skia/src/shaders/SkPictureShader.h +++ b/chromium/third_party/skia/src/shaders/SkPictureShader.h @@ -37,8 +37,8 @@ protected: SkPictureShader(SkReadBuffer&); void flatten(SkWriteBuffer&) const override; bool onAppendStages(const SkStageRec&) const override; - skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override; diff --git a/chromium/third_party/skia/src/shaders/SkShader.cpp b/chromium/third_party/skia/src/shaders/SkShader.cpp index c1c09e7d9a2..e8bcdb9927c 100644 --- a/chromium/third_party/skia/src/shaders/SkShader.cpp +++ b/chromium/third_party/skia/src/shaders/SkShader.cpp @@ -189,14 +189,15 @@ bool SkShaderBase::onAppendStages(const SkStageRec& rec) const { rec.fPipeline->append(SkRasterPipeline::callback, cb); rec.fAlloc->make<SkColorSpaceXformSteps>(sk_srgb_singleton(), kPremul_SkAlphaType, rec.fDstCS, kPremul_SkAlphaType) - ->apply(rec.fPipeline, true); + ->apply(rec.fPipeline); return true; } return false; } -skvm::Color SkShaderBase::program(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, +skvm::Color SkShaderBase::program(skvm::Builder* p, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider& matrices, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { // Force opaque alpha for all opaque shaders. @@ -211,7 +212,8 @@ skvm::Color SkShaderBase::program(skvm::Builder* p, skvm::F32 x, skvm::F32 y, sk // shader program hash and blitter Key. This makes it safe for us to use // that bit to make decisions when constructing an SkVMBlitter, like doing // SrcOver -> Src strength reduction. - if (auto color = this->onProgram(p, x,y, paint, ctm,localM, quality,dst, uniforms,alloc)) { + if (auto color = this->onProgram(p, device,local, paint, matrices,localM, quality,dst, + uniforms,alloc)) { if (this->isOpaque()) { color.a = p->splat(1.0f); } @@ -220,11 +222,12 @@ skvm::Color SkShaderBase::program(skvm::Builder* p, skvm::F32 x, skvm::F32 y, sk return {}; } -skvm::Color SkShaderBase::onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, +skvm::Color SkShaderBase::onProgram(skvm::Builder*, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { - //SkDebugf("cannot onProgram %s\n", this->getTypeName()); + // SkDebugf("cannot onProgram %s\n", this->getTypeName()); return {}; } @@ -234,36 +237,40 @@ sk_sp<SkShader> SkShaderBase::makeInvertAlpha() const { } -void SkShaderBase::ApplyMatrix(skvm::Builder* p, const SkMatrix& m, - skvm::F32* x, skvm::F32* y, skvm::Uniforms* uniforms) { +skvm::Coord SkShaderBase::ApplyMatrix(skvm::Builder* p, const SkMatrix& m, + skvm::Coord coord, skvm::Uniforms* uniforms) { + skvm::F32 x = coord.x, + y = coord.y; if (m.isIdentity()) { // That was easy. } else if (m.isTranslate()) { - *x = p->add(*x, p->uniformF(uniforms->pushF(m[2]))); - *y = p->add(*y, p->uniformF(uniforms->pushF(m[5]))); + x = p->add(x, p->uniformF(uniforms->pushF(m[2]))); + y = p->add(y, p->uniformF(uniforms->pushF(m[5]))); } else if (m.isScaleTranslate()) { - *x = p->mad(*x, p->uniformF(uniforms->pushF(m[0])), p->uniformF(uniforms->pushF(m[2]))); - *y = p->mad(*y, p->uniformF(uniforms->pushF(m[4])), p->uniformF(uniforms->pushF(m[5]))); + x = p->mad(x, p->uniformF(uniforms->pushF(m[0])), p->uniformF(uniforms->pushF(m[2]))); + y = p->mad(y, p->uniformF(uniforms->pushF(m[4])), p->uniformF(uniforms->pushF(m[5]))); } else { // Affine or perspective. - auto dot = [&,X=*x,Y=*y](int row) { - return p->mad(X, p->uniformF(uniforms->pushF(m[3*row+0])), - p->mad(Y, p->uniformF(uniforms->pushF(m[3*row+1])), + auto dot = [&,x,y](int row) { + return p->mad(x, p->uniformF(uniforms->pushF(m[3*row+0])), + p->mad(y, p->uniformF(uniforms->pushF(m[3*row+1])), p->uniformF(uniforms->pushF(m[3*row+2])))); }; - *x = dot(0); - *y = dot(1); + x = dot(0); + y = dot(1); if (m.hasPerspective()) { - *x = p->div(*x, dot(2)); - *y = p->div(*y, dot(2)); + x = p->div(x, dot(2)); + y = p->div(y, dot(2)); } } + return {x,y}; } /////////////////////////////////////////////////////////////////////////////////////////////////// -skvm::Color SkEmptyShader::onProgram(skvm::Builder*, skvm::F32, skvm::F32, skvm::Color, - const SkMatrix&, const SkMatrix*, SkFilterQuality, - const SkColorInfo&, skvm::Uniforms*, SkArenaAlloc*) const { +skvm::Color SkEmptyShader::onProgram(skvm::Builder*, skvm::Coord, skvm::Coord, skvm::Color, + const SkMatrixProvider&, const SkMatrix*, + SkFilterQuality, const SkColorInfo&, + skvm::Uniforms*, SkArenaAlloc*) const { return {}; // signal failure } diff --git a/chromium/third_party/skia/src/shaders/SkShaderBase.h b/chromium/third_party/skia/src/shaders/SkShaderBase.h index dda4d1aac5f..9119056bd93 100644 --- a/chromium/third_party/skia/src/shaders/SkShaderBase.h +++ b/chromium/third_party/skia/src/shaders/SkShaderBase.h @@ -211,8 +211,8 @@ public: return this->onAppendUpdatableStages(rec); } - skvm::Color program(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color program(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const; @@ -241,14 +241,15 @@ protected: virtual SkStageUpdater* onAppendUpdatableStages(const SkStageRec&) const { return nullptr; } protected: - static void ApplyMatrix(skvm::Builder*, const SkMatrix&, skvm::F32* x, skvm::F32* y, skvm::Uniforms*); + static skvm::Coord ApplyMatrix(skvm::Builder*, const SkMatrix&, skvm::Coord, skvm::Uniforms*); private: // This is essentially const, but not officially so it can be modified in constructors. SkMatrix fLocalMatrix; - virtual skvm::Color onProgram(skvm::Builder*, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + virtual skvm::Color onProgram(skvm::Builder*, + skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dst, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const; diff --git a/chromium/third_party/skia/src/shaders/gradients/Sk4fLinearGradient.cpp b/chromium/third_party/skia/src/shaders/gradients/Sk4fLinearGradient.cpp index d75bec96556..944ac9fdb47 100644 --- a/chromium/third_party/skia/src/shaders/gradients/Sk4fLinearGradient.cpp +++ b/chromium/third_party/skia/src/shaders/gradients/Sk4fLinearGradient.cpp @@ -190,17 +190,17 @@ LinearGradient4fContext::shadePremulSpan(int x, int y, SkPMColor dst[], int coun const SkLinearGradient& shader = static_cast<const SkLinearGradient&>(fShader); switch (shader.fTileMode) { case SkTileMode::kDecal: - SkASSERT(false); // decal only supported via stages - // fall-through + SkASSERT(false); // decal only supported via stages + [[fallthrough]]; case SkTileMode::kClamp: this->shadeSpanInternal<premul, SkTileMode::kClamp >(x, y, dst, count, bias0, bias1); - break; + break; case SkTileMode::kRepeat: this->shadeSpanInternal<premul, SkTileMode::kRepeat>(x, y, dst, count, bias0, bias1); - break; + break; case SkTileMode::kMirror: this->shadeSpanInternal<premul, SkTileMode::kMirror>(x, y, dst, count, bias0, bias1); - break; + break; } } diff --git a/chromium/third_party/skia/src/shaders/gradients/SkGradientShader.cpp b/chromium/third_party/skia/src/shaders/gradients/SkGradientShader.cpp index 205a18f05b3..23e5d9a8495 100644 --- a/chromium/third_party/skia/src/shaders/gradients/SkGradientShader.cpp +++ b/chromium/third_party/skia/src/shaders/gradients/SkGradientShader.cpp @@ -299,7 +299,8 @@ bool SkGradientShaderBase::onAppendStages(const SkStageRec& rec) const { decal_ctx->limit_x = SkBits2Float(SkFloat2Bits(1.0f) + 1); // reuse mask + limit_x stage, or create a custom decal_1 that just stores the mask p->append(SkRasterPipeline::decal_x, decal_ctx); - // fall-through to clamp + [[fallthrough]]; + case SkTileMode::kClamp: if (!fOrigPos) { // We clamp only when the stops are evenly spaced. @@ -419,21 +420,22 @@ bool SkGradientShaderBase::onAppendStages(const SkStageRec& rec) const { } skvm::Color SkGradientShaderBase::onProgram(skvm::Builder* p, - skvm::F32 x, skvm::F32 y, skvm::Color /*paint*/, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Coord device, skvm::Coord local, + skvm::Color /*paint*/, + const SkMatrixProvider& mats, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dstInfo, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const { SkMatrix inv; - if (!this->computeTotalInverse(ctm, localM, &inv)) { + if (!this->computeTotalInverse(mats.localToDevice(), localM, &inv)) { return {}; } inv.postConcat(fPtsToUnit); inv.normalizePerspective(); - SkShaderBase::ApplyMatrix(p, inv, &x,&y,uniforms); + local = SkShaderBase::ApplyMatrix(p, inv, local, uniforms); skvm::I32 mask = p->splat(~0); - skvm::F32 t = this->transformT(p,uniforms, x,y, &mask); + skvm::F32 t = this->transformT(p,uniforms, local, &mask); // Perhaps unexpectedly, clamping is handled naturally by our search, so we // don't explicitly clamp t to [0,1]. That clamp would break hard stops diff --git a/chromium/third_party/skia/src/shaders/gradients/SkGradientShaderPriv.h b/chromium/third_party/skia/src/shaders/gradients/SkGradientShaderPriv.h index 2a3bfca1808..f33c444f9b5 100644 --- a/chromium/third_party/skia/src/shaders/gradients/SkGradientShaderPriv.h +++ b/chromium/third_party/skia/src/shaders/gradients/SkGradientShaderPriv.h @@ -79,8 +79,8 @@ protected: bool onAppendStages(const SkStageRec&) const override; - skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint, - const SkMatrix& ctm, const SkMatrix* localM, + skvm::Color onProgram(skvm::Builder*, skvm::Coord device, skvm::Coord local, skvm::Color paint, + const SkMatrixProvider&, const SkMatrix* localM, SkFilterQuality quality, const SkColorInfo& dstCS, skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override; @@ -89,7 +89,7 @@ protected: // Produce t from (x,y), modifying mask if it should be anything other than ~0. virtual skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*, - skvm::F32 x, skvm::F32 y, skvm::I32* mask) const = 0; + skvm::Coord coord, skvm::I32* mask) const = 0; template <typename T, typename... Args> static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) { diff --git a/chromium/third_party/skia/src/shaders/gradients/SkLinearGradient.cpp b/chromium/third_party/skia/src/shaders/gradients/SkLinearGradient.cpp index ad5129ccc3b..347fd177f00 100644 --- a/chromium/third_party/skia/src/shaders/gradients/SkLinearGradient.cpp +++ b/chromium/third_party/skia/src/shaders/gradients/SkLinearGradient.cpp @@ -76,9 +76,9 @@ void SkLinearGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline*, } skvm::F32 SkLinearGradient::transformT(skvm::Builder* p, skvm::Uniforms*, - skvm::F32 x, skvm::F32 y, skvm::I32* mask) const { + skvm::Coord coord, skvm::I32* mask) const { // We've baked getting t in x into the matrix, so this is pretty trivial. - return x; + return coord.x; } SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { diff --git a/chromium/third_party/skia/src/shaders/gradients/SkLinearGradient.h b/chromium/third_party/skia/src/shaders/gradients/SkLinearGradient.h index c8f9bc678f5..063b9c5a647 100644 --- a/chromium/third_party/skia/src/shaders/gradients/SkLinearGradient.h +++ b/chromium/third_party/skia/src/shaders/gradients/SkLinearGradient.h @@ -30,7 +30,7 @@ protected: SkRasterPipeline* postPipeline) const final; skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*, - skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final; + skvm::Coord coord, skvm::I32* mask) const final; private: SK_FLATTENABLE_HOOKS(SkLinearGradient) diff --git a/chromium/third_party/skia/src/shaders/gradients/SkRadialGradient.cpp b/chromium/third_party/skia/src/shaders/gradients/SkRadialGradient.cpp index aeefe15e741..fea9ca6b316 100644 --- a/chromium/third_party/skia/src/shaders/gradients/SkRadialGradient.cpp +++ b/chromium/third_party/skia/src/shaders/gradients/SkRadialGradient.cpp @@ -64,8 +64,8 @@ void SkRadialGradient::appendGradientStages(SkArenaAlloc*, SkRasterPipeline* p, } skvm::F32 SkRadialGradient::transformT(skvm::Builder* p, skvm::Uniforms*, - skvm::F32 x, skvm::F32 y, skvm::I32* mask) const { - return sqrt(x*x + y*y); + skvm::Coord coord, skvm::I32* mask) const { + return sqrt(coord.x*coord.x + coord.y*coord.y); } ///////////////////////////////////////////////////////////////////// diff --git a/chromium/third_party/skia/src/shaders/gradients/SkRadialGradient.h b/chromium/third_party/skia/src/shaders/gradients/SkRadialGradient.h index 75680978637..7396bb21d2b 100644 --- a/chromium/third_party/skia/src/shaders/gradients/SkRadialGradient.h +++ b/chromium/third_party/skia/src/shaders/gradients/SkRadialGradient.h @@ -27,7 +27,7 @@ protected: SkRasterPipeline* postPipeline) const override; skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*, - skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final; + skvm::Coord coord, skvm::I32* mask) const final; private: SK_FLATTENABLE_HOOKS(SkRadialGradient) diff --git a/chromium/third_party/skia/src/shaders/gradients/SkSweepGradient.cpp b/chromium/third_party/skia/src/shaders/gradients/SkSweepGradient.cpp index b8a8c51977d..6256cc6bf35 100644 --- a/chromium/third_party/skia/src/shaders/gradients/SkSweepGradient.cpp +++ b/chromium/third_party/skia/src/shaders/gradients/SkSweepGradient.cpp @@ -13,7 +13,7 @@ SkSweepGradient::SkSweepGradient(const SkPoint& center, SkScalar t0, SkScalar t1, const Descriptor& desc) - : SkGradientShaderBase(desc, SkMatrix::MakeTrans(-center.x(), -center.y())) + : SkGradientShaderBase(desc, SkMatrix::Translate(-center.x(), -center.y())) , fCenter(center) , fTBias(-t0) , fTScale(1 / (t1 - t0)) @@ -64,14 +64,13 @@ void SkSweepGradient::flatten(SkWriteBuffer& buffer) const { void SkSweepGradient::appendGradientStages(SkArenaAlloc* alloc, SkRasterPipeline* p, SkRasterPipeline*) const { p->append(SkRasterPipeline::xy_to_unit_angle); - p->append_matrix(alloc, SkMatrix::Concat(SkMatrix::MakeScale(fTScale, 1), - SkMatrix::MakeTrans(fTBias , 0))); + p->append_matrix(alloc, SkMatrix::Scale(fTScale, 1) * SkMatrix::Translate(fTBias, 0)); } skvm::F32 SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms, - skvm::F32 x, skvm::F32 y, skvm::I32* mask) const { - skvm::F32 xabs = abs(x), - yabs = abs(y), + skvm::Coord coord, skvm::I32* mask) const { + skvm::F32 xabs = abs(coord.x), + yabs = abs(coord.y), slope = min(xabs, yabs) / max(xabs, yabs); skvm::F32 s = slope * slope; @@ -83,9 +82,9 @@ skvm::F32 SkSweepGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms +2.476101927459239959716796875e-2f, -5.185396969318389892578125e-2f, +0.15912117063999176025390625f); - phi = select(xabs < yabs, (1/4.0f) - phi, phi); - phi = select( x < 0.0f, (1/2.0f) - phi, phi); - phi = select( y < 0.0f, (1/1.0f) - phi, phi); + phi = select( xabs < yabs, (1/4.0f) - phi, phi); + phi = select(coord.x < 0.0f, (1/2.0f) - phi, phi); + phi = select(coord.y < 0.0f, (1/1.0f) - phi, phi); skvm::F32 t = select(is_NaN(phi), p->splat(0.0f) , phi); diff --git a/chromium/third_party/skia/src/shaders/gradients/SkSweepGradient.h b/chromium/third_party/skia/src/shaders/gradients/SkSweepGradient.h index e7beae2dae5..86ca372ba0c 100644 --- a/chromium/third_party/skia/src/shaders/gradients/SkSweepGradient.h +++ b/chromium/third_party/skia/src/shaders/gradients/SkSweepGradient.h @@ -31,7 +31,7 @@ protected: SkRasterPipeline* postPipeline) const override; skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*, - skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final; + skvm::Coord coord, skvm::I32* mask) const final; private: SK_FLATTENABLE_HOOKS(SkSweepGradient) diff --git a/chromium/third_party/skia/src/shaders/gradients/SkTwoPointConicalGradient.cpp b/chromium/third_party/skia/src/shaders/gradients/SkTwoPointConicalGradient.cpp index 811d719b9d5..d3ec7552176 100644 --- a/chromium/third_party/skia/src/shaders/gradients/SkTwoPointConicalGradient.cpp +++ b/chromium/third_party/skia/src/shaders/gradients/SkTwoPointConicalGradient.cpp @@ -62,7 +62,7 @@ sk_sp<SkShader> SkTwoPointConicalGradient::Create(const SkPoint& c0, SkScalar r0 } // Concentric case: we can pretend we're radial (with a tiny twist). const SkScalar scale = sk_ieee_float_divide(1, std::max(r0, r1)); - gradientMatrix = SkMatrix::MakeTrans(-c1.x(), -c1.y()); + gradientMatrix = SkMatrix::Translate(-c1.x(), -c1.y()); gradientMatrix.postScale(scale, scale); gradientType = Type::kRadial; @@ -188,8 +188,7 @@ void SkTwoPointConicalGradient::appendGradientStages(SkArenaAlloc* alloc, SkRast auto scale = std::max(fRadius1, fRadius2) / dRadius; auto bias = -fRadius1 / dRadius; - p->append_matrix(alloc, SkMatrix::Concat(SkMatrix::MakeTrans(bias, 0), - SkMatrix::MakeScale(scale, 1))); + p->append_matrix(alloc, SkMatrix::Translate(bias, 0) * SkMatrix::Scale(scale, 1)); return; } @@ -235,11 +234,13 @@ void SkTwoPointConicalGradient::appendGradientStages(SkArenaAlloc* alloc, SkRast } skvm::F32 SkTwoPointConicalGradient::transformT(skvm::Builder* p, skvm::Uniforms* uniforms, - skvm::F32 x, skvm::F32 y, skvm::I32* mask) const { + skvm::Coord coord, skvm::I32* mask) const { // See https://skia.org/dev/design/conical, and onAppendStages() above. // There's a lot going on here, and I'm not really sure what's independent // or disjoint, what can be reordered, simplified, etc. Tweak carefully. + const skvm::F32 x = coord.x, + y = coord.y; if (fType == Type::kRadial) { float denom = 1.0f / (fRadius2 - fRadius1), scale = std::max(fRadius1, fRadius2) * denom, diff --git a/chromium/third_party/skia/src/shaders/gradients/SkTwoPointConicalGradient.h b/chromium/third_party/skia/src/shaders/gradients/SkTwoPointConicalGradient.h index a8893ce5e1f..d362ba0a303 100644 --- a/chromium/third_party/skia/src/shaders/gradients/SkTwoPointConicalGradient.h +++ b/chromium/third_party/skia/src/shaders/gradients/SkTwoPointConicalGradient.h @@ -70,7 +70,7 @@ protected: SkRasterPipeline* postPipeline) const override; skvm::F32 transformT(skvm::Builder*, skvm::Uniforms*, - skvm::F32 x, skvm::F32 y, skvm::I32* mask) const final; + skvm::Coord coord, skvm::I32* mask) const final; private: SK_FLATTENABLE_HOOKS(SkTwoPointConicalGradient) diff --git a/chromium/third_party/skia/src/sksl/README b/chromium/third_party/skia/src/sksl/README index 906fd814984..525726b7c08 100644 --- a/chromium/third_party/skia/src/sksl/README +++ b/chromium/third_party/skia/src/sksl/README @@ -150,10 +150,12 @@ Within an '.fp' fragment processor file: The first variant emits the child with a solid white input color. The second variant emits the child with the result of the 2nd argument's expression, which must evaluate to a half4. The process function returns a half4. -* By default, fragment processors must be non-null. The type for a nullable - fragment processor is 'fragmentProcessor?', as in - 'in fragmentProcessor? <name>'. You can check for the presence of such a - fragment processor by comparing it to 'null'. +* The 'fragmentProcessor' type cannot hold a null. Nullable fragment processors + should use the 'fragmentProcessor?' type: 'in fragmentProcessor? <name>'. You + can check for null fragment processors by comparing them against 'null', as + in: 'if (inputFP != null) { ... }'. Invoking 'sample()' on a null fragment + processor will return the inputColor unchanged (this defaults to solid white + if not explicitly specified). Creating a new .fp file diff --git a/chromium/third_party/skia/src/sksl/SkSLASTNode.cpp b/chromium/third_party/skia/src/sksl/SkSLASTNode.cpp index 7c5a2033a0c..a74d5ab338b 100644 --- a/chromium/third_party/skia/src/sksl/SkSLASTNode.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLASTNode.cpp @@ -34,7 +34,7 @@ String ASTNode::description() const { return "break"; case Kind::kCall: { auto iter = this->begin(); - String result = iter->description(); + String result = (iter++)->description(); result += "("; const char* separator = ""; while (iter != this->end()) { @@ -230,6 +230,11 @@ String ASTNode::description() const { } return result; } + case Kind::kWhile: { + return "while (" + this->begin()->description() + ") " + + (this->begin() + 1)->description(); + + } default: SkASSERT(false); return "<error>"; diff --git a/chromium/third_party/skia/src/sksl/SkSLByteCode.cpp b/chromium/third_party/skia/src/sksl/SkSLByteCode.cpp index 65e4301c4b9..132dc6d298e 100644 --- a/chromium/third_party/skia/src/sksl/SkSLByteCode.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLByteCode.cpp @@ -61,6 +61,7 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) { printf("callexternal %d, %d, %d", argumentCount, returnCount, externalValue); break; } + VECTOR_DISASSEMBLE(kCeil, "ceil") case ByteCodeInstruction::kClampIndex: printf("clampindex %d", READ8()); break; VECTOR_DISASSEMBLE(kCompareIEQ, "compareieq") VECTOR_DISASSEMBLE(kCompareINEQ, "compareineq") @@ -86,6 +87,7 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) { VECTOR_DISASSEMBLE(kDivideS, "divideS") VECTOR_DISASSEMBLE(kDivideU, "divideu") VECTOR_MATRIX_DISASSEMBLE(kDup, "dup") + VECTOR_DISASSEMBLE(kFloor, "floor") VECTOR_DISASSEMBLE(kFract, "fract") case ByteCodeInstruction::kInverse2x2: printf("inverse2x2"); break; case ByteCodeInstruction::kInverse3x3: printf("inverse3x3"); break; @@ -103,38 +105,12 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) { case ByteCodeInstruction::kLoadUniform2: printf("loaduniform2 %d", READ8()); break; case ByteCodeInstruction::kLoadUniform3: printf("loaduniform3 %d", READ8()); break; case ByteCodeInstruction::kLoadUniform4: printf("loaduniform4 %d", READ8()); break; - case ByteCodeInstruction::kLoadSwizzle: { - int target = READ8(); - int count = READ8(); - printf("loadswizzle %d %d", target, count); - for (int i = 0; i < count; ++i) { - printf(", %d", READ8()); - } - break; - } - case ByteCodeInstruction::kLoadSwizzleGlobal: { - int target = READ8(); - int count = READ8(); - printf("loadswizzleglobal %d %d", target, count); - for (int i = 0; i < count; ++i) { - printf(", %d", READ8()); - } - break; - } - case ByteCodeInstruction::kLoadSwizzleUniform: { - int target = READ8(); - int count = READ8(); - printf("loadswizzleuniform %d %d", target, count); - for (int i = 0; i < count; ++i) { - printf(", %d", READ8()); - } - break; - } case ByteCodeInstruction::kLoadExtended: printf("loadextended %d", READ8()); break; case ByteCodeInstruction::kLoadExtendedGlobal: printf("loadextendedglobal %d", READ8()); break; case ByteCodeInstruction::kLoadExtendedUniform: printf("loadextendeduniform %d", READ8()); break; + case ByteCodeInstruction::kLoadFragCoord: printf("loadfragcoord"); break; case ByteCodeInstruction::kMatrixToMatrix: { int srcCols = READ8(); int srcRows = READ8(); @@ -178,6 +154,8 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) { VECTOR_DISASSEMBLE(kRemainderU, "remainderu") case ByteCodeInstruction::kReserve: printf("reserve %d", READ8()); break; case ByteCodeInstruction::kReturn: printf("return %d", READ8()); break; + case ByteCodeInstruction::kSampleExplicit: printf("sample %d", READ8()); break; + case ByteCodeInstruction::kSampleMatrix: printf("sampleMtx %d", READ8()); break; case ByteCodeInstruction::kScalarToMatrix: { int cols = READ8(); int rows = READ8(); @@ -197,40 +175,6 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) { case ByteCodeInstruction::kStoreGlobal2: printf("storeglobal2 %d", READ8()); break; case ByteCodeInstruction::kStoreGlobal3: printf("storeglobal3 %d", READ8()); break; case ByteCodeInstruction::kStoreGlobal4: printf("storeglobal4 %d", READ8()); break; - case ByteCodeInstruction::kStoreSwizzle: { - int target = READ8(); - int count = READ8(); - printf("storeswizzle %d %d", target, count); - for (int i = 0; i < count; ++i) { - printf(", %d", READ8()); - } - break; - } - case ByteCodeInstruction::kStoreSwizzleGlobal: { - int target = READ8(); - int count = READ8(); - printf("storeswizzleglobal %d %d", target, count); - for (int i = 0; i < count; ++i) { - printf(", %d", READ8()); - } - break; - } - case ByteCodeInstruction::kStoreSwizzleIndirect: { - int count = READ8(); - printf("storeswizzleindirect %d", count); - for (int i = 0; i < count; ++i) { - printf(", %d", READ8()); - } - break; - } - case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: { - int count = READ8(); - printf("storeswizzleindirectglobal %d", count); - for (int i = 0; i < count; ++i) { - printf(", %d", READ8()); - } - break; - } case ByteCodeInstruction::kStoreExtended: printf("storeextended %d", READ8()); break; case ByteCodeInstruction::kStoreExtendedGlobal: printf("storeextendedglobal %d", READ8()); break; @@ -273,20 +217,23 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) { } #define VECTOR_BINARY_OP(base, field, op) \ - case ByteCodeInstruction::base ## 4: \ + case ByteCodeInstruction::base ## 4: { \ sp[-4] = sp[-4].field op sp[0].field; \ POP(); \ - /* fall through */ \ + [[fallthrough]]; \ + } \ case ByteCodeInstruction::base ## 3: { \ int count = (int)inst - (int)(ByteCodeInstruction::base) - 1; \ sp[count] = sp[count].field op sp[0].field; \ POP(); \ - } /* fall through */ \ + [[fallthrough]]; \ + } \ case ByteCodeInstruction::base ## 2: { \ int count = (int)inst - (int)(ByteCodeInstruction::base) - 1; \ sp[count] = sp[count].field op sp[0].field; \ POP(); \ - } /* fall through */ \ + [[fallthrough]]; \ + } \ case ByteCodeInstruction::base: { \ int count = (int)inst - (int)(ByteCodeInstruction::base) - 1; \ sp[count] = sp[count].field op sp[0].field; \ @@ -297,14 +244,15 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) { // A naive implementation of / or % using skvx operations will likely crash with a divide by zero // in inactive vector lanes, so we need to be sure to avoid masked-off lanes. #define VECTOR_BINARY_MASKED_OP(base, field, op) \ - case ByteCodeInstruction::base ## 4: \ + case ByteCodeInstruction::base ## 4: { \ for (int i = 0; i < VecWidth; ++i) { \ if (mask()[i]) { \ sp[-4].field[i] op ## = sp[0].field[i]; \ } \ } \ POP(); \ - /* fall through */ \ + [[fallthrough]]; \ + } \ case ByteCodeInstruction::base ## 3: { \ int count = (int)inst - (int)(ByteCodeInstruction::base) - 1; \ for (int i = 0; i < VecWidth; ++i) { \ @@ -313,7 +261,8 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) { } \ } \ POP(); \ - } /* fall through */ \ + [[fallthrough]]; \ + } \ case ByteCodeInstruction::base ## 2: { \ int count = (int)inst - (int)(ByteCodeInstruction::base) - 1; \ for (int i = 0; i < VecWidth; ++i) { \ @@ -322,7 +271,8 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) { } \ } \ POP(); \ - } /* fall through */ \ + [[fallthrough]]; \ + } \ case ByteCodeInstruction::base: { \ int count = (int)inst - (int)(ByteCodeInstruction::base) - 1; \ for (int i = 0; i < VecWidth; ++i) { \ @@ -347,20 +297,23 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) { } #define VECTOR_BINARY_FN(base, field, fn) \ - case ByteCodeInstruction::base ## 4: \ + case ByteCodeInstruction::base ## 4: { \ sp[-4] = fn(sp[-4].field, sp[0].field); \ POP(); \ - /* fall through */ \ + [[fallthrough]]; \ + } \ case ByteCodeInstruction::base ## 3: { \ int count = (int)inst - (int)(ByteCodeInstruction::base) - 1; \ sp[count] = fn(sp[count].field, sp[0].field); \ POP(); \ - } /* fall through */ \ + [[fallthrough]]; \ + } \ case ByteCodeInstruction::base ## 2: { \ int count = (int)inst - (int)(ByteCodeInstruction::base) - 1; \ sp[count] = fn(sp[count].field, sp[0].field); \ POP(); \ - } /* fall through */ \ + [[fallthrough]]; \ + } \ case ByteCodeInstruction::base: { \ int count = (int)inst - (int)(ByteCodeInstruction::base) - 1; \ sp[count] = fn(sp[count].field, sp[0].field); \ @@ -368,11 +321,11 @@ static const uint8_t* DisassembleInstruction(const uint8_t* ip) { continue; \ } -#define VECTOR_UNARY_FN(base, fn, field) \ - case ByteCodeInstruction::base ## 4: sp[-3] = fn(sp[-3].field); \ - case ByteCodeInstruction::base ## 3: sp[-2] = fn(sp[-2].field); \ - case ByteCodeInstruction::base ## 2: sp[-1] = fn(sp[-1].field); \ - case ByteCodeInstruction::base: sp[ 0] = fn(sp[ 0].field); \ +#define VECTOR_UNARY_FN(base, fn, field) \ + case ByteCodeInstruction::base ## 4: sp[-3] = fn(sp[-3].field); [[fallthrough]]; \ + case ByteCodeInstruction::base ## 3: sp[-2] = fn(sp[-2].field); [[fallthrough]]; \ + case ByteCodeInstruction::base ## 2: sp[-1] = fn(sp[-1].field); [[fallthrough]]; \ + case ByteCodeInstruction::base: sp[ 0] = fn(sp[ 0].field); \ continue; union VValue { @@ -561,9 +514,9 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue sp[-1] = sp[-1].fSigned & sp[0].fSigned; POP(); continue; - case ByteCodeInstruction::kNotB4: sp[-3] = ~sp[-3].fSigned; - case ByteCodeInstruction::kNotB3: sp[-2] = ~sp[-2].fSigned; - case ByteCodeInstruction::kNotB2: sp[-1] = ~sp[-1].fSigned; + case ByteCodeInstruction::kNotB4: sp[-3] = ~sp[-3].fSigned; [[fallthrough]]; + case ByteCodeInstruction::kNotB3: sp[-2] = ~sp[-2].fSigned; [[fallthrough]]; + case ByteCodeInstruction::kNotB2: sp[-1] = ~sp[-1].fSigned; [[fallthrough]]; case ByteCodeInstruction::kNotB: sp[ 0] = ~sp[ 0].fSigned; continue; case ByteCodeInstruction::kOrB: @@ -603,6 +556,8 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue continue; } + VECTOR_UNARY_FN(kCeil, skvx::ceil, fFloat) + case ByteCodeInstruction::kClampIndex: { int length = READ8(); if (skvx::any(mask() & ((sp[0].fSigned < 0) | (sp[0].fSigned >= length)))) { @@ -628,23 +583,44 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue VECTOR_BINARY_OP(kCompareULTEQ, fUnsigned, <=) VECTOR_BINARY_OP(kCompareFLTEQ, fFloat, <=) - case ByteCodeInstruction::kConvertFtoI4: sp[-3] = skvx::cast<int>(sp[-3].fFloat); - case ByteCodeInstruction::kConvertFtoI3: sp[-2] = skvx::cast<int>(sp[-2].fFloat); - case ByteCodeInstruction::kConvertFtoI2: sp[-1] = skvx::cast<int>(sp[-1].fFloat); - case ByteCodeInstruction::kConvertFtoI: sp[ 0] = skvx::cast<int>(sp[ 0].fFloat); - continue; + case ByteCodeInstruction::kConvertFtoI4: + sp[-3] = skvx::cast<int>(sp[-3].fFloat); + [[fallthrough]]; + case ByteCodeInstruction::kConvertFtoI3: + sp[-2] = skvx::cast<int>(sp[-2].fFloat); + [[fallthrough]]; + case ByteCodeInstruction::kConvertFtoI2: + sp[-1] = skvx::cast<int>(sp[-1].fFloat); + [[fallthrough]]; + case ByteCodeInstruction::kConvertFtoI: + sp[ 0] = skvx::cast<int>(sp[ 0].fFloat); + continue; - case ByteCodeInstruction::kConvertStoF4: sp[-3] = skvx::cast<float>(sp[-3].fSigned); - case ByteCodeInstruction::kConvertStoF3: sp[-2] = skvx::cast<float>(sp[-2].fSigned); - case ByteCodeInstruction::kConvertStoF2: sp[-1] = skvx::cast<float>(sp[-1].fSigned); - case ByteCodeInstruction::kConvertStoF: sp[ 0] = skvx::cast<float>(sp[ 0].fSigned); - continue; + case ByteCodeInstruction::kConvertStoF4: + sp[-3] = skvx::cast<float>(sp[-3].fSigned); + [[fallthrough]]; + case ByteCodeInstruction::kConvertStoF3: + sp[-2] = skvx::cast<float>(sp[-2].fSigned); + [[fallthrough]]; + case ByteCodeInstruction::kConvertStoF2: + sp[-1] = skvx::cast<float>(sp[-1].fSigned); + [[fallthrough]]; + case ByteCodeInstruction::kConvertStoF: + sp[ 0] = skvx::cast<float>(sp[ 0].fSigned); + continue; - case ByteCodeInstruction::kConvertUtoF4: sp[-3] = skvx::cast<float>(sp[-3].fUnsigned); - case ByteCodeInstruction::kConvertUtoF3: sp[-2] = skvx::cast<float>(sp[-2].fUnsigned); - case ByteCodeInstruction::kConvertUtoF2: sp[-1] = skvx::cast<float>(sp[-1].fUnsigned); - case ByteCodeInstruction::kConvertUtoF: sp[ 0] = skvx::cast<float>(sp[ 0].fUnsigned); - continue; + case ByteCodeInstruction::kConvertUtoF4: + sp[-3] = skvx::cast<float>(sp[-3].fUnsigned); + [[fallthrough]]; + case ByteCodeInstruction::kConvertUtoF3: + sp[-2] = skvx::cast<float>(sp[-2].fUnsigned); + [[fallthrough]]; + case ByteCodeInstruction::kConvertUtoF2: + sp[-1] = skvx::cast<float>(sp[-1].fUnsigned); + [[fallthrough]]; + case ByteCodeInstruction::kConvertUtoF: + sp[ 0] = skvx::cast<float>(sp[ 0].fUnsigned); + continue; VECTOR_UNARY_FN(kCos, skvx::cos, fFloat) @@ -652,11 +628,18 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue VECTOR_BINARY_MASKED_OP(kDivideU, fUnsigned, /) VECTOR_MATRIX_BINARY_OP(kDivideF, fFloat, /) - case ByteCodeInstruction::kDup4: PUSH(sp[(int)inst - (int)ByteCodeInstruction::kDup]); - case ByteCodeInstruction::kDup3: PUSH(sp[(int)inst - (int)ByteCodeInstruction::kDup]); - case ByteCodeInstruction::kDup2: PUSH(sp[(int)inst - (int)ByteCodeInstruction::kDup]); - case ByteCodeInstruction::kDup : PUSH(sp[(int)inst - (int)ByteCodeInstruction::kDup]); - continue; + case ByteCodeInstruction::kDup4: + PUSH(sp[(int)inst - (int)ByteCodeInstruction::kDup]); + [[fallthrough]]; + case ByteCodeInstruction::kDup3: + PUSH(sp[(int)inst - (int)ByteCodeInstruction::kDup]); + [[fallthrough]]; + case ByteCodeInstruction::kDup2: + PUSH(sp[(int)inst - (int)ByteCodeInstruction::kDup]); + [[fallthrough]]; + case ByteCodeInstruction::kDup : + PUSH(sp[(int)inst - (int)ByteCodeInstruction::kDup]); + continue; case ByteCodeInstruction::kDupN: { int count = READ8(); @@ -665,6 +648,7 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue continue; } + VECTOR_UNARY_FN(kFloor, skvx::floor, fFloat) VECTOR_UNARY_FN(kFract, skvx::fract, fFloat) case ByteCodeInstruction::kInverse2x2: @@ -692,29 +676,36 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue continue; } - case ByteCodeInstruction::kLoad4: sp[4] = stack[*ip + 3]; - case ByteCodeInstruction::kLoad3: sp[3] = stack[*ip + 2]; - case ByteCodeInstruction::kLoad2: sp[2] = stack[*ip + 1]; + case ByteCodeInstruction::kLoad4: sp[4] = stack[*ip + 3]; [[fallthrough]]; + case ByteCodeInstruction::kLoad3: sp[3] = stack[*ip + 2]; [[fallthrough]]; + case ByteCodeInstruction::kLoad2: sp[2] = stack[*ip + 1]; [[fallthrough]]; case ByteCodeInstruction::kLoad: sp[1] = stack[*ip + 0]; ++ip; sp += (int)ByteCodeInstruction::kLoad - (int)inst + 1; continue; - case ByteCodeInstruction::kLoadGlobal4: sp[4] = globals[*ip + 3]; - case ByteCodeInstruction::kLoadGlobal3: sp[3] = globals[*ip + 2]; - case ByteCodeInstruction::kLoadGlobal2: sp[2] = globals[*ip + 1]; + case ByteCodeInstruction::kLoadGlobal4: sp[4] = globals[*ip + 3]; [[fallthrough]]; + case ByteCodeInstruction::kLoadGlobal3: sp[3] = globals[*ip + 2]; [[fallthrough]]; + case ByteCodeInstruction::kLoadGlobal2: sp[2] = globals[*ip + 1]; [[fallthrough]]; case ByteCodeInstruction::kLoadGlobal: sp[1] = globals[*ip + 0]; ++ip; sp += (int)ByteCodeInstruction::kLoadGlobal - (int)inst + 1; continue; - case ByteCodeInstruction::kLoadUniform4: sp[4].fFloat = uniforms[*ip + 3]; - case ByteCodeInstruction::kLoadUniform3: sp[3].fFloat = uniforms[*ip + 2]; - case ByteCodeInstruction::kLoadUniform2: sp[2].fFloat = uniforms[*ip + 1]; - case ByteCodeInstruction::kLoadUniform: sp[1].fFloat = uniforms[*ip + 0]; - ++ip; - sp += (int)ByteCodeInstruction::kLoadUniform - (int)inst + 1; - continue; + case ByteCodeInstruction::kLoadUniform4: + sp[4].fFloat = uniforms[*ip + 3]; + [[fallthrough]]; + case ByteCodeInstruction::kLoadUniform3: + sp[3].fFloat = uniforms[*ip + 2]; + [[fallthrough]]; + case ByteCodeInstruction::kLoadUniform2: + sp[2].fFloat = uniforms[*ip + 1]; + [[fallthrough]]; + case ByteCodeInstruction::kLoadUniform: + sp[1].fFloat = uniforms[*ip + 0]; + ++ip; + sp += (int)ByteCodeInstruction::kLoadUniform - (int)inst + 1; + continue; case ByteCodeInstruction::kLoadExtended: { int count = READ8(); @@ -761,36 +752,6 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue continue; } - case ByteCodeInstruction::kLoadSwizzle: { - int src = READ8(); - int count = READ8(); - for (int i = 0; i < count; ++i) { - PUSH(stack[src + *(ip + i)]); - } - ip += count; - continue; - } - - case ByteCodeInstruction::kLoadSwizzleGlobal: { - int src = READ8(); - int count = READ8(); - for (int i = 0; i < count; ++i) { - PUSH(globals[src + *(ip + i)]); - } - ip += count; - continue; - } - - case ByteCodeInstruction::kLoadSwizzleUniform: { - int src = READ8(); - int count = READ8(); - for (int i = 0; i < count; ++i) { - PUSH(F32(uniforms[src + *(ip + i)])); - } - ip += count; - continue; - } - case ByteCodeInstruction::kMatrixToMatrix: { int srcCols = READ8(); int srcRows = READ8(); @@ -860,9 +821,9 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue VECTOR_BINARY_OP(kMultiplyI, fSigned, *) VECTOR_MATRIX_BINARY_OP(kMultiplyF, fFloat, *) - case ByteCodeInstruction::kNegateF4: sp[-3] = -sp[-3].fFloat; - case ByteCodeInstruction::kNegateF3: sp[-2] = -sp[-2].fFloat; - case ByteCodeInstruction::kNegateF2: sp[-1] = -sp[-1].fFloat; + case ByteCodeInstruction::kNegateF4: sp[-3] = -sp[-3].fFloat; [[fallthrough]]; + case ByteCodeInstruction::kNegateF3: sp[-2] = -sp[-2].fFloat; [[fallthrough]]; + case ByteCodeInstruction::kNegateF2: sp[-1] = -sp[-1].fFloat; [[fallthrough]]; case ByteCodeInstruction::kNegateF: sp[ 0] = -sp[ 0].fFloat; continue; @@ -874,15 +835,15 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue continue; } - case ByteCodeInstruction::kNegateI4: sp[-3] = -sp[-3].fSigned; - case ByteCodeInstruction::kNegateI3: sp[-2] = -sp[-2].fSigned; - case ByteCodeInstruction::kNegateI2: sp[-1] = -sp[-1].fSigned; + case ByteCodeInstruction::kNegateI4: sp[-3] = -sp[-3].fSigned; [[fallthrough]]; + case ByteCodeInstruction::kNegateI3: sp[-2] = -sp[-2].fSigned; [[fallthrough]]; + case ByteCodeInstruction::kNegateI2: sp[-1] = -sp[-1].fSigned; [[fallthrough]]; case ByteCodeInstruction::kNegateI: sp[ 0] = -sp[ 0].fSigned; continue; - case ByteCodeInstruction::kPop4: POP(); - case ByteCodeInstruction::kPop3: POP(); - case ByteCodeInstruction::kPop2: POP(); + case ByteCodeInstruction::kPop4: POP(); [[fallthrough]]; + case ByteCodeInstruction::kPop3: POP(); [[fallthrough]]; + case ByteCodeInstruction::kPop2: POP(); [[fallthrough]]; case ByteCodeInstruction::kPop: POP(); continue; @@ -993,10 +954,13 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue case ByteCodeInstruction::kStore4: stack[*ip+3] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+3].fFloat); + [[fallthrough]]; case ByteCodeInstruction::kStore3: stack[*ip+2] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+2].fFloat); + [[fallthrough]]; case ByteCodeInstruction::kStore2: stack[*ip+1] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+1].fFloat); + [[fallthrough]]; case ByteCodeInstruction::kStore: stack[*ip+0] = skvx::if_then_else(mask(), POP().fFloat, stack[*ip+0].fFloat); ++ip; @@ -1004,10 +968,13 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue case ByteCodeInstruction::kStoreGlobal4: globals[*ip+3] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+3].fFloat); + [[fallthrough]]; case ByteCodeInstruction::kStoreGlobal3: globals[*ip+2] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+2].fFloat); + [[fallthrough]]; case ByteCodeInstruction::kStoreGlobal2: globals[*ip+1] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+1].fFloat); + [[fallthrough]]; case ByteCodeInstruction::kStoreGlobal: globals[*ip+0] = skvx::if_then_else(mask(), POP().fFloat, globals[*ip+0].fFloat); ++ip; @@ -1044,60 +1011,6 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue continue; } - case ByteCodeInstruction::kStoreSwizzle: { - int target = READ8(); - int count = READ8(); - for (int i = count - 1; i >= 0; --i) { - stack[target + *(ip + i)] = skvx::if_then_else( - mask(), POP().fFloat, stack[target + *(ip + i)].fFloat); - } - ip += count; - continue; - } - - case ByteCodeInstruction::kStoreSwizzleGlobal: { - int target = READ8(); - int count = READ8(); - for (int i = count - 1; i >= 0; --i) { - globals[target + *(ip + i)] = skvx::if_then_else( - mask(), POP().fFloat, globals[target + *(ip + i)].fFloat); - } - ip += count; - continue; - } - - case ByteCodeInstruction::kStoreSwizzleIndirect: { - int count = READ8(); - I32 target = POP().fSigned; - I32 m = mask(); - for (int i = count - 1; i >= 0; --i) { - I32 v = POP().fSigned; - for (int j = 0; j < VecWidth; ++j) { - if (m[j]) { - stack[target[j] + *(ip + i)].fSigned[j] = v[j]; - } - } - } - ip += count; - continue; - } - - case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: { - int count = READ8(); - I32 target = POP().fSigned; - I32 m = mask(); - for (int i = count - 1; i >= 0; --i) { - I32 v = POP().fSigned; - for (int j = 0; j < VecWidth; ++j) { - if (m[j]) { - globals[target[j] + *(ip + i)].fSigned[j] = v[j]; - } - } - } - ip += count; - continue; - } - VECTOR_BINARY_OP(kSubtractI, fSigned, -) VECTOR_MATRIX_BINARY_OP(kSubtractF, fFloat, -) @@ -1188,6 +1101,14 @@ static bool InnerRun(const ByteCode* byteCode, const ByteCodeFunction* f, VValue *loopPtr &= ~m; continue; } + + case ByteCodeInstruction::kLoadFragCoord: + case ByteCodeInstruction::kSampleExplicit: + case ByteCodeInstruction::kSampleMatrix: + default: + // TODO: Support these? + SkASSERT(false); + return false; } } } diff --git a/chromium/third_party/skia/src/sksl/SkSLByteCode.h b/chromium/third_party/skia/src/sksl/SkSLByteCode.h index 0e98736910c..79f2befb886 100644 --- a/chromium/third_party/skia/src/sksl/SkSLByteCode.h +++ b/chromium/third_party/skia/src/sksl/SkSLByteCode.h @@ -34,6 +34,7 @@ enum class ByteCodeInstruction : uint16_t { // Followed by three bytes indicating: the number of argument slots, the number of return slots, // and the index of the external value to call kCallExternal, + VECTOR(kCeil), // For dynamic array access: Followed by byte indicating length of array kClampIndex, VECTOR(kCompareIEQ), @@ -61,6 +62,7 @@ enum class ByteCodeInstruction : uint16_t { VECTOR(kDivideU), // Duplicates the top stack value VECTOR_MATRIX(kDup), + VECTOR(kFloor), VECTOR(kFract), kInverse2x2, kInverse3x3, @@ -71,15 +73,13 @@ enum class ByteCodeInstruction : uint16_t { VECTOR(kLoad), VECTOR(kLoadGlobal), VECTOR(kLoadUniform), - // As kLoad/kLoadGlobal, then a count byte (1-4), and then one byte per swizzle component (0-3). - kLoadSwizzle, - kLoadSwizzleGlobal, - kLoadSwizzleUniform, // kLoadExtended* are fallback load ops when we lack a specialization. They are followed by a // count byte, and get the slot to load from the top of the stack. kLoadExtended, kLoadExtendedGlobal, kLoadExtendedUniform, + // Loads "sk_FragCoord" [X, Y, Z, 1/W] + kLoadFragCoord, // Followed by four bytes: srcCols, srcRows, dstCols, dstRows. Consumes the src matrix from the // stack, and replaces it with the dst matrix. Per GLSL rules, there are no restrictions on // dimensions. Any overlapping values are copied, and any other values are filled in with the @@ -113,6 +113,11 @@ enum class ByteCodeInstruction : uint16_t { kReserve, // Followed by a byte indicating the number of slots being returned kReturn, + // kSampleExplicit/kSampleMatrix are followed by a byte indicating the FP slot to sample + // Expects stack to contain (X, Y), produces (R, G, B, A) + kSampleExplicit, + // Expects stack to contain a 3x3 matrix, produces (R, G, B, A) + kSampleMatrix, // Followed by two bytes indicating columns and rows of matrix (2, 3, or 4 each). // Takes a single value from the top of the stack, and converts to a CxR matrix with that value // replicated along the diagonal (and zero elsewhere), per the GLSL matrix construction rules. @@ -129,14 +134,6 @@ enum class ByteCodeInstruction : uint16_t { // Fallback stores. Followed by count byte, and get the slot to store from the top of the stack kStoreExtended, kStoreExtendedGlobal, - // As kStore/kStoreGlobal, then a count byte (1-4), then one byte per swizzle component (0-3). - // Expects the stack to look like: ... v1 v2 v3 v4, where the number of 'v's is equal to the - // number of swizzle components. After the store, all v's are popped from the stack. - kStoreSwizzle, - kStoreSwizzleGlobal, - // As above, but gets the store slot from the top of the stack (before values to be stored) - kStoreSwizzleIndirect, - kStoreSwizzleIndirectGlobal, // Followed by two count bytes (1-4), and then one byte per swizzle component (0-3). The first // count byte provides the current vector size (the vector is the top n stack elements), and the // second count byte provides the swizzle component count. @@ -276,6 +273,12 @@ public: } const Uniform& getUniform(int i) const { return fUniforms[i]; } + /** + * Some byte code programs can't be executed by the interpreter, due to unsupported features. + * They may still be used to convert to other formats, or for reflection of uniforms. + */ + bool canRun() const { return fChildFPCount == 0 && !fUsesFragCoord; } + private: ByteCode(const ByteCode&) = delete; ByteCode& operator=(const ByteCode&) = delete; @@ -285,6 +288,8 @@ private: int fGlobalSlotCount = 0; int fUniformSlotCount = 0; + int fChildFPCount = 0; + bool fUsesFragCoord = false; std::vector<Uniform> fUniforms; std::vector<std::unique_ptr<ByteCodeFunction>> fFunctions; diff --git a/chromium/third_party/skia/src/sksl/SkSLByteCodeGenerator.cpp b/chromium/third_party/skia/src/sksl/SkSLByteCodeGenerator.cpp index c625051ff0d..819a1a3c44e 100644 --- a/chromium/third_party/skia/src/sksl/SkSLByteCodeGenerator.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLByteCodeGenerator.cpp @@ -46,21 +46,25 @@ ByteCodeGenerator::ByteCodeGenerator(const Context* context, const Program* prog // they're available to "generic" interpreter programs (eg particles). // You can probably copy the declarations from sksl_gpu.inc. , fIntrinsics { - { "atan", ByteCodeInstruction::kATan }, - { "clamp", SpecialIntrinsic::kClamp }, - { "cos", ByteCodeInstruction::kCos }, - { "dot", SpecialIntrinsic::kDot }, - { "fract", ByteCodeInstruction::kFract }, - { "inverse", ByteCodeInstruction::kInverse2x2 }, - { "length", SpecialIntrinsic::kLength }, - { "max", SpecialIntrinsic::kMax }, - { "min", SpecialIntrinsic::kMin }, - { "mix", SpecialIntrinsic::kMix }, - { "pow", ByteCodeInstruction::kPow }, - { "saturate", SpecialIntrinsic::kSaturate }, - { "sin", ByteCodeInstruction::kSin }, - { "sqrt", ByteCodeInstruction::kSqrt }, - { "tan", ByteCodeInstruction::kTan }, + { "atan", ByteCodeInstruction::kATan }, + { "ceil", ByteCodeInstruction::kCeil }, + { "clamp", SpecialIntrinsic::kClamp }, + { "cos", ByteCodeInstruction::kCos }, + { "dot", SpecialIntrinsic::kDot }, + { "floor", ByteCodeInstruction::kFloor }, + { "fract", ByteCodeInstruction::kFract }, + { "inverse", ByteCodeInstruction::kInverse2x2 }, + { "length", SpecialIntrinsic::kLength }, + { "max", SpecialIntrinsic::kMax }, + { "min", SpecialIntrinsic::kMin }, + { "mix", SpecialIntrinsic::kMix }, + { "normalize", SpecialIntrinsic::kNormalize }, + { "pow", ByteCodeInstruction::kPow }, + { "sample", SpecialIntrinsic::kSample }, + { "saturate", SpecialIntrinsic::kSaturate }, + { "sin", ByteCodeInstruction::kSin }, + { "sqrt", ByteCodeInstruction::kSqrt }, + { "tan", ByteCodeInstruction::kTan }, { "lessThan", { ByteCodeInstruction::kCompareFLT, ByteCodeInstruction::kCompareSLT, @@ -150,6 +154,9 @@ bool ByteCodeGenerator::generateCode() { VarDeclarations& decl = (VarDeclarations&) e; for (const auto& v : decl.fVars) { const Variable* declVar = ((VarDeclaration&) *v).fVar; + if (declVar->fType == *fContext.fFragmentProcessor_Type) { + fOutput->fChildFPCount++; + } if (declVar->fModifiers.fLayout.fBuiltin >= 0 || is_in(*declVar)) { continue; } @@ -200,10 +207,27 @@ std::unique_ptr<ByteCodeFunction> ByteCodeGenerator::writeFunction(const Functio return result; } +// If the expression is a reference to a builtin global variable, return the builtin ID. +// Otherwise, return -1. +static int expression_as_builtin(const Expression& e) { + if (e.fKind == Expression::kVariableReference_Kind) { + const Variable& var(((VariableReference&)e).fVariable); + if (var.fStorage == Variable::kGlobal_Storage) { + return var.fModifiers.fLayout.fBuiltin; + } + } + return -1; +} + // A "simple" Swizzle is based on a variable (or a compound variable like a struct or array), and // that references consecutive values, such that it can be implemented using normal load/store ops // with an offset. Note that all single-component swizzles (of suitable base types) are simple. static bool swizzle_is_simple(const Swizzle& s) { + // Builtin variables use dedicated instructions that don't allow subset loads + if (expression_as_builtin(*s.fBase) >= 0) { + return false; + } + switch (s.fBase->fKind) { case Expression::kFieldAccess_Kind: case Expression::kIndex_Kind: @@ -253,7 +277,9 @@ int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) { VECTOR_UNARY_OP(kConvertUtoF) VECTOR_UNARY_OP(kATan) + VECTOR_UNARY_OP(kCeil) VECTOR_UNARY_OP(kCos) + VECTOR_UNARY_OP(kFloor) VECTOR_UNARY_OP(kFract) VECTOR_UNARY_OP(kSin) VECTOR_UNARY_OP(kSqrt) @@ -357,12 +383,10 @@ int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) { case ByteCodeInstruction::kLoadGlobal4: case ByteCodeInstruction::kLoadUniform4: case ByteCodeInstruction::kReadExternal4: + case ByteCodeInstruction::kLoadFragCoord: return 4; case ByteCodeInstruction::kDupN: - case ByteCodeInstruction::kLoadSwizzle: - case ByteCodeInstruction::kLoadSwizzleGlobal: - case ByteCodeInstruction::kLoadSwizzleUniform: return count; // Pushes 'count' values, minus one for the 'address' that's consumed first @@ -397,15 +421,11 @@ int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) { return -4; case ByteCodeInstruction::kPopN: - case ByteCodeInstruction::kStoreSwizzle: - case ByteCodeInstruction::kStoreSwizzleGlobal: return -count; // Consumes 'count' values, plus one for the 'address' case ByteCodeInstruction::kStoreExtended: case ByteCodeInstruction::kStoreExtendedGlobal: - case ByteCodeInstruction::kStoreSwizzleIndirect: - case ByteCodeInstruction::kStoreSwizzleIndirectGlobal: return -count - 1; // Strange ops where the caller computes the delta for us: @@ -420,6 +440,11 @@ int ByteCodeGenerator::StackUsage(ByteCodeInstruction inst, int count_) { // Miscellaneous + // (X, Y) -> (R, G, B, A) + case ByteCodeInstruction::kSampleExplicit: return 4 - 2; + // (float3x3) -> (R, G, B, A) + case ByteCodeInstruction::kSampleMatrix: return 4 - 9; + // kMix does a 3 -> 1 reduction (A, B, M -> A -or- B) for each component case ByteCodeInstruction::kMix: return -2; case ByteCodeInstruction::kMix2: return -4; @@ -485,6 +510,27 @@ ByteCodeGenerator::Location ByteCodeGenerator::getLocation(const Variable& var) return Location::MakeInvalid(); } case Variable::kGlobal_Storage: { + if (var.fType == *fContext.fFragmentProcessor_Type) { + int offset = 0; + for (const auto& e : fProgram) { + if (e.fKind == ProgramElement::kVar_Kind) { + VarDeclarations& decl = (VarDeclarations&) e; + for (const auto& v : decl.fVars) { + const Variable* declVar = ((VarDeclaration&) *v).fVar; + if (declVar->fType != *fContext.fFragmentProcessor_Type) { + continue; + } + if (declVar == &var) { + SkASSERT(offset <= 255); + return { offset, Storage::kChildFP }; + } + offset++; + } + } + } + SkASSERT(false); + return Location::MakeInvalid(); + } if (is_in(var)) { // If you see this error, it means the program is using raw 'in' variables. You // should either specialize the program (Compiler::specialize) to bake in the final @@ -987,27 +1033,41 @@ void ByteCodeGenerator::writeExternalValue(const ExternalValueReference& e) { } void ByteCodeGenerator::writeVariableExpression(const Expression& expr) { + if (int builtin = expression_as_builtin(expr); builtin >= 0) { + switch (builtin) { + case SK_FRAGCOORD_BUILTIN: + this->write(ByteCodeInstruction::kLoadFragCoord); + fOutput->fUsesFragCoord = true; + break; + default: + fErrors.error(expr.fOffset, "Unsupported builtin"); + break; + } + return; + } + Location location = this->getLocation(expr); int count = SlotCount(expr.fType); if (count == 0) { return; } - if (location.isOnStack() || count > 4) { - if (!location.isOnStack()) { - this->write(ByteCodeInstruction::kPushImmediate); - this->write32(location.fSlot); - } + if (location.isOnStack()) { this->write(location.selectLoad(ByteCodeInstruction::kLoadExtended, ByteCodeInstruction::kLoadExtendedGlobal, ByteCodeInstruction::kLoadExtendedUniform), count); this->write8(count); } else { - this->write(vector_instruction(location.selectLoad(ByteCodeInstruction::kLoad, - ByteCodeInstruction::kLoadGlobal, - ByteCodeInstruction::kLoadUniform), - count)); - this->write8(location.fSlot); + while (count) { + int loadCount = std::min(count, 4); + this->write(vector_instruction(location.selectLoad(ByteCodeInstruction::kLoad, + ByteCodeInstruction::kLoadGlobal, + ByteCodeInstruction::kLoadUniform), + loadCount)); + this->write8(location.fSlot); + count -= loadCount; + location.fSlot += loadCount; + } } } @@ -1046,6 +1106,29 @@ void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) { } }; + if (intrin.is_special && intrin.special == SpecialIntrinsic::kSample) { + // Sample is very special, the first argument is an FP, which can't be pushed to the stack + if (c.fArguments.size() != 2 || + c.fArguments[0]->fType != *fContext.fFragmentProcessor_Type || + (c.fArguments[1]->fType != *fContext.fFloat2_Type && + c.fArguments[1]->fType != *fContext.fFloat3x3_Type)) { + fErrors.error(c.fOffset, "Unsupported form of sample"); + return; + } + + // Write our coords or matrix + this->writeExpression(*c.fArguments[1]); + + this->write(c.fArguments[1]->fType == *fContext.fFloat3x3_Type + ? ByteCodeInstruction::kSampleMatrix + : ByteCodeInstruction::kSampleExplicit); + + Location childLoc = this->getLocation(*c.fArguments[0]); + SkASSERT(childLoc.fStorage == Storage::kChildFP); + this->write8(childLoc.fSlot); + return; + } + if (intrin.is_special && (intrin.special == SpecialIntrinsic::kClamp || intrin.special == SpecialIntrinsic::kSaturate)) { // These intrinsics are extra-special, we need instructions interleaved with arguments @@ -1162,6 +1245,19 @@ void ByteCodeGenerator::writeIntrinsicCall(const FunctionCall& c) { } } break; + case SpecialIntrinsic::kNormalize: { + SkASSERT(c.fArguments.size() == 1); + this->write(vector_instruction(ByteCodeInstruction::kDup , count)); + this->write(vector_instruction(ByteCodeInstruction::kDup , count)); + this->write(vector_instruction(ByteCodeInstruction::kMultiplyF, count)); + for (int i = count-1; i --> 0;) { + this->write(ByteCodeInstruction::kAddF); + } + this->write(ByteCodeInstruction::kSqrt); + dupSmallerType(1); + this->write(vector_instruction(ByteCodeInstruction::kDivideF, count)); + } break; + default: SkASSERT(false); } @@ -1375,29 +1471,12 @@ void ByteCodeGenerator::writeSwizzle(const Swizzle& s) { return; } - switch (s.fBase->fKind) { - case Expression::kVariableReference_Kind: { - Location location = this->getLocation(*s.fBase); - this->write(location.selectLoad(ByteCodeInstruction::kLoadSwizzle, - ByteCodeInstruction::kLoadSwizzleGlobal, - ByteCodeInstruction::kLoadSwizzleUniform), - s.fComponents.size()); - this->write8(location.fSlot); - this->write8(s.fComponents.size()); - for (int c : s.fComponents) { - this->write8(c); - } - break; - } - default: - this->writeExpression(*s.fBase); - this->write(ByteCodeInstruction::kSwizzle, - s.fComponents.size() - s.fBase->fType.columns()); - this->write8(s.fBase->fType.columns()); - this->write8(s.fComponents.size()); - for (int c : s.fComponents) { - this->write8(c); - } + this->writeExpression(*s.fBase); + this->write(ByteCodeInstruction::kSwizzle, s.fComponents.size() - s.fBase->fType.columns()); + this->write8(s.fBase->fType.columns()); + this->write8(s.fComponents.size()); + for (int c : s.fComponents) { + this->write8(c); } } @@ -1522,20 +1601,31 @@ public: if (!discard) { fGenerator.write(vector_instruction(ByteCodeInstruction::kDup, count)); } - ByteCodeGenerator::Location location = fGenerator.getLocation(*fSwizzle.fBase); - if (location.isOnStack()) { - fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreSwizzleIndirect, - ByteCodeInstruction::kStoreSwizzleIndirectGlobal), - count); - } else { - fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreSwizzle, - ByteCodeInstruction::kStoreSwizzleGlobal), - count); - fGenerator.write8(location.fSlot); - } - fGenerator.write8(count); - for (int c : fSwizzle.fComponents) { - fGenerator.write8(c); + // We already have the correct number of values on the stack, thanks to type checking. + // The algorithm: Walk down the values on the stack, doing 'count' single-element stores. + // For each value, use the corresponding swizzle component to offset the store location. + // + // Static locations: We (wastefully) call getLocation every time, but get good byte code. + // Note that we could (but don't) store adjacent/sequential values with fewer instructions. + // + // Dynamic locations: ... are bad. We have to recompute the base address on each iteration, + // because the stack doesn't let us retain that address between stores. Dynamic locations + // are rare though, and swizzled writes to those are even rarer, so we just live with this. + for (int i = count; i-- > 0;) { + ByteCodeGenerator::Location location = fGenerator.getLocation(*fSwizzle.fBase); + if (!location.isOnStack()) { + fGenerator.write(location.selectStore(ByteCodeInstruction::kStore, + ByteCodeInstruction::kStoreGlobal)); + fGenerator.write8(location.fSlot + fSwizzle.fComponents[i]); + } else { + fGenerator.write(ByteCodeInstruction::kPushImmediate); + fGenerator.write32(fSwizzle.fComponents[i]); + fGenerator.write(ByteCodeInstruction::kAddI); + fGenerator.write(location.selectStore(ByteCodeInstruction::kStoreExtended, + ByteCodeInstruction::kStoreExtendedGlobal), + 1); + fGenerator.write8(1); + } } } diff --git a/chromium/third_party/skia/src/sksl/SkSLByteCodeGenerator.h b/chromium/third_party/skia/src/sksl/SkSLByteCodeGenerator.h index 02e186b9d00..9178c4fd16e 100644 --- a/chromium/third_party/skia/src/sksl/SkSLByteCodeGenerator.h +++ b/chromium/third_party/skia/src/sksl/SkSLByteCodeGenerator.h @@ -146,6 +146,8 @@ private: kMax, kMin, kMix, + kNormalize, + kSample, kSaturate, }; @@ -170,6 +172,7 @@ private: kLocal, // include parameters kGlobal, // non-uniform globals kUniform, // uniform globals + kChildFP, // child fragment processors }; struct Location { @@ -179,10 +182,14 @@ private: // Not really invalid, but a "safe" placeholder to be more explicit at call-sites static Location MakeInvalid() { return { 0, Storage::kLocal }; } - Location makeOnStack() { return { -1, fStorage }; } + Location makeOnStack() { + SkASSERT(fStorage != Storage::kChildFP); + return { -1, fStorage }; + } bool isOnStack() const { return fSlot < 0; } Location operator+(int offset) { + SkASSERT(fStorage != Storage::kChildFP); SkASSERT(fSlot >= 0); return { fSlot + offset, fStorage }; } @@ -194,8 +201,9 @@ private: case Storage::kLocal: return local; case Storage::kGlobal: return global; case Storage::kUniform: return uniform; + case Storage::kChildFP: ABORT("Trying to load an FP"); break; } - SkUNREACHABLE; + return local; } ByteCodeInstruction selectStore(ByteCodeInstruction local, @@ -204,6 +212,7 @@ private: case Storage::kLocal: return local; case Storage::kGlobal: return global; case Storage::kUniform: ABORT("Trying to store to a uniform"); break; + case Storage::kChildFP: ABORT("Trying to store an FP"); break; } return local; } diff --git a/chromium/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp b/chromium/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp index 3042662cd21..66b020c4112 100644 --- a/chromium/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLCPPCodeGenerator.cpp @@ -23,11 +23,11 @@ static bool needs_uniform_var(const Variable& var) { CPPCodeGenerator::CPPCodeGenerator(const Context* context, const Program* program, ErrorReporter* errors, String name, OutputStream* out) -: INHERITED(context, program, errors, out) -, fName(std::move(name)) -, fFullName(String::printf("Gr%s", fName.c_str())) -, fSectionAndParameterHelper(program, *errors) { - fLineEnding = "\\n"; + : INHERITED(context, program, errors, out) + , fName(std::move(name)) + , fFullName(String::printf("Gr%s", fName.c_str())) + , fSectionAndParameterHelper(program, *errors) { + fLineEnding = "\n"; fTextureFunctionOverride = "sample"; } @@ -36,7 +36,7 @@ void CPPCodeGenerator::writef(const char* s, va_list va) { va_list copy; va_copy(copy, va); char buffer[BUFFER_SIZE]; - int length = vsnprintf(buffer, BUFFER_SIZE, s, va); + int length = std::vsnprintf(buffer, BUFFER_SIZE, s, va); if (length < BUFFER_SIZE) { fOut->write(buffer, length); } else { @@ -122,13 +122,17 @@ void CPPCodeGenerator::writeIndexExpression(const IndexExpression& i) { return; } int64_t index = ((IntLiteral&) *i.fIndex).fValue; + if (index != 0) { + fErrors.error(i.fIndex->fOffset, "Only sk_TransformedCoords2D[0] is allowed"); + return; + } String name = "sk_TransformedCoords2D_" + to_string(index); fFormatArgs.push_back(name + ".c_str()"); - if (fWrittenTransformedCoords.find(index) == fWrittenTransformedCoords.end()) { + if (!fAccessLocalCoordsDirectly) { + fAccessLocalCoordsDirectly = true; addExtraEmitCodeLine("SkString " + name + " = fragBuilder->ensureCoords2D(args.fTransformedCoords[" + to_string(index) + "].fVaryingPoint, _outer.sampleMatrix());"); - fWrittenTransformedCoords.insert(index); } return; } else if (SK_TEXTURESAMPLERS_BUILTIN == builtin) { @@ -431,18 +435,19 @@ void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) { // must be properly formatted with a prefixed comma when the parameter should be inserted // into the invokeChild() parameter list. String inputArg; + String inputColorName; if (c.fArguments.size() > 1 && c.fArguments[1]->fType.name() == "half4") { // Use the invokeChild() variant that accepts an input color, so convert the 2nd // argument's expression into C++ code that produces sksl stored in an SkString. - String inputName = "_input" + to_string(c.fOffset); - addExtraEmitCodeLine(convertSKSLExpressionToCPP(*c.fArguments[1], inputName)); + inputColorName = "_input" + to_string(c.fOffset); + addExtraEmitCodeLine(convertSKSLExpressionToCPP(*c.fArguments[1], inputColorName)); // invokeChild() needs a char* - inputArg = ", " + inputName + ".c_str()"; + inputArg = ", " + inputColorName + ".c_str()"; } bool hasCoords = c.fArguments.back()->fType.name() == "float2"; - SampleMatrix matrix = fSectionAndParameterHelper.getMatrix(child); + SampleMatrix matrix = SampleMatrix::Make(fProgram, child); // Write the output handling after the possible input handling String childName = "_sample" + to_string(c.fOffset); addExtraEmitCodeLine("SkString " + childName + ";"); @@ -481,14 +486,21 @@ void CPPCodeGenerator::writeFunctionCall(const FunctionCall& c) { if (c.fArguments[0]->fType.kind() == Type::kNullable_Kind) { // Null FPs are not emitted, but their output can still be referenced in dependent // expressions - thus we always fill the variable with something. - // Note: this is essentially dead code required to satisfy the compiler, because - // 'process' function calls should always be guarded at a higher level, in the .fp - // source. - addExtraEmitCodeLine( - "} else {" - " " + childName + " = \"half4(1)\";" - "}"); + // Sampling from a null fragment processor will provide in the input color as-is. This + // defaults to half4(1) if no color is specified. + if (!inputColorName.empty()) { + addExtraEmitCodeLine( + "} else {" + " " + childName + ".swap(" + inputColorName + ");" + "}"); + } else { + addExtraEmitCodeLine( + "} else {" + " " + childName + " = \"half4(1)\";" + "}"); + } } + this->write("%s"); fFormatArgs.push_back(childName + ".c_str()"); return; @@ -557,6 +569,9 @@ static const char* glsltype_string(const Context& context, const Type& type) { void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) { const FunctionDeclaration& decl = f.fDeclaration; + if (decl.fBuiltin) { + return; + } fFunctionHeader = ""; OutputStream* oldOut = fOut; StringStream buffer; @@ -594,7 +609,7 @@ void CPPCodeGenerator::writeFunction(const FunctionDefinition& f) { emit += ", \"" + decl.fName + "\""; emit += ", " + to_string((int64_t) decl.fParameters.size()); emit += ", " + decl.fName + "_args"; - emit += ", \"" + buffer.str() + "\""; + emit += ",\nR\"SkSL(" + buffer.str() + ")SkSL\""; emit += ", &" + decl.fName + "_name);"; this->addExtraEmitCodeLine(emit.c_str()); } @@ -815,46 +830,33 @@ void CPPCodeGenerator::flushEmittedCode() { } void CPPCodeGenerator::writeCodeAppend(const String& code) { - // codeAppendf can only handle appending 1024 bytes at a time, so we need to break the string - // into chunks. Unfortunately we can't tell exactly how long the string is going to end up, - // because printf escape sequences get replaced by strings of unknown length, but keeping the - // format string below 512 bytes is probably safe. - static constexpr size_t maxChunkSize = 512; - size_t start = 0; - size_t index = 0; - size_t argStart = 0; - size_t argCount; - while (index < code.size()) { - argCount = 0; - this->write(" fragBuilder->codeAppendf(\""); - while (index < code.size() && index < start + maxChunkSize) { + if (!code.empty()) { + // Count % format specifiers. + size_t argCount = 0; + for (size_t index = 0; index < code.size(); ++index) { if ('%' == code[index]) { - if (index == start + maxChunkSize - 1 || index == code.size() - 1) { + if (index == code.size() - 1) { break; } if (code[index + 1] != '%') { ++argCount; } - } else if ('\\' == code[index] && index == start + maxChunkSize - 1) { - // avoid splitting an escape sequence that happens to fall across a chunk boundary - break; } - ++index; } - fOut->write(code.c_str() + start, index - start); - this->write("\""); - for (size_t i = argStart; i < argStart + argCount; ++i) { + + // Emit the code string. + this->writef(" fragBuilder->codeAppendf(\n" + "R\"SkSL(%s)SkSL\"\n", code.c_str()); + for (size_t i = 0; i < argCount; ++i) { this->writef(", %s", fFormatArgs[i].c_str()); } this->write(");\n"); - argStart += argCount; - start = index; - } - // argStart is equal to the number of fFormatArgs that were consumed - // so they should be removed from the list - if (argStart > 0) { - fFormatArgs.erase(fFormatArgs.begin(), fFormatArgs.begin() + argStart); + // argCount is equal to the number of fFormatArgs that were consumed, so they should be + // removed from the list. + if (argCount > 0) { + fFormatArgs.erase(fFormatArgs.begin(), fFormatArgs.begin() + argCount); + } } } @@ -901,10 +903,14 @@ String CPPCodeGenerator::convertSKSLExpressionToCPP(const Expression& e, // Now build the final C++ code snippet from the format string and args String cppExpr; - if (newArgs.size() == 0) { + if (newArgs.empty()) { // This was a static expression, so we can simplify the input // color declaration in the emitted code to just a static string cppExpr = "SkString " + cppVar + "(\"" + exprFormat + "\");"; + } else if (newArgs.size() == 1 && exprFormat == "%s") { + // If the format expression is simply "%s", we can avoid an expensive call to printf. + // This happens fairly often in codegen so it is worth simplifying. + cppExpr = "SkString " + cppVar + "(" + newArgs[0] + ");"; } else { // String formatting must occur dynamically, so have the C++ declaration // use SkStringPrintf with the format args that were accumulated @@ -970,7 +976,7 @@ void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) { "const GrFragmentProcessor& _proc) override {\n", pdman); bool wroteProcessor = false; - for (const auto u : uniforms) { + for (const Variable* u : uniforms) { if (is_uniform_in(*u)) { if (!wroteProcessor) { this->writef(" const %s& _outer = _proc.cast<%s>();\n", fullName, fullName); @@ -1043,11 +1049,12 @@ void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) { for (const auto& p : fProgram) { if (ProgramElement::kVar_Kind == p.fKind) { const VarDeclarations& decls = (const VarDeclarations&) p; - for (const auto& raw : decls.fVars) { - VarDeclaration& decl = (VarDeclaration&) *raw; - String nameString(decl.fVar->fName); + for (const std::unique_ptr<Statement>& raw : decls.fVars) { + const VarDeclaration& decl = static_cast<VarDeclaration&>(*raw); + const Variable& variable = *decl.fVar; + String nameString(variable.fName); const char* name = nameString.c_str(); - if (decl.fVar->fType.kind() == Type::kSampler_Kind) { + if (variable.fType.kind() == Type::kSampler_Kind) { this->writef(" const GrSurfaceProxyView& %sView = " "_outer.textureSampler(%d).view();\n", name, samplerIndex); @@ -1055,20 +1062,23 @@ void CPPCodeGenerator::writeSetData(std::vector<const Variable*>& uniforms) { name, name); this->writef(" (void) %s;\n", name); ++samplerIndex; - } else if (needs_uniform_var(*decl.fVar)) { + } else if (needs_uniform_var(variable)) { this->writef(" UniformHandle& %s = %sVar;\n" " (void) %s;\n", name, HCodeGenerator::FieldName(name).c_str(), name); - } else if (SectionAndParameterHelper::IsParameter(*decl.fVar) && - decl.fVar->fType != *fContext.fFragmentProcessor_Type) { + } else if (SectionAndParameterHelper::IsParameter(variable) && + variable.fType != *fContext.fFragmentProcessor_Type) { if (!wroteProcessor) { this->writef(" const %s& _outer = _proc.cast<%s>();\n", fullName, fullName); wroteProcessor = true; } - this->writef(" auto %s = _outer.%s;\n" - " (void) %s;\n", - name, name, name); + + if (variable.fType.nonnullable() != *fContext.fFragmentProcessor_Type) { + this->writef(" auto %s = _outer.%s;\n" + " (void) %s;\n", + name, name, name); + } } } } @@ -1116,13 +1126,9 @@ void CPPCodeGenerator::writeClone() { String fieldName = HCodeGenerator::CoordTransformName(s.fArgument, i); this->writef("\n, %s(src.%s)", fieldName.c_str(), fieldName.c_str()); } - for (const auto& param : fSectionAndParameterHelper.getParameters()) { + for (const Variable* param : fSectionAndParameterHelper.getParameters()) { String fieldName = HCodeGenerator::FieldName(String(param->fName).c_str()); - if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) { - this->writef("\n, %s_index(src.%s_index)", - fieldName.c_str(), - fieldName.c_str()); - } else { + if (param->fType.nonnullable() != *fContext.fFragmentProcessor_Type) { this->writef("\n, %s(src.%s)", fieldName.c_str(), fieldName.c_str()); @@ -1136,18 +1142,14 @@ void CPPCodeGenerator::writeClone() { } else if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) { String fieldName = HCodeGenerator::FieldName(String(param->fName).c_str()); if (param->fType.kind() == Type::kNullable_Kind) { - this->writef(" if (%s_index >= 0) {\n", fieldName.c_str()); + this->writef(" if (src.%s_index >= 0) {\n", fieldName.c_str()); } else { this->write(" {\n"); } - this->writef( - " auto clone = src.childProcessor(%s_index).clone();\n" - " if (src.childProcessor(%s_index).isSampledWithExplicitCoords()) {\n" - " clone->setSampledWithExplicitCoords();\n" - " }" - " this->registerChildProcessor(std::move(clone));\n" - " }\n", - fieldName.c_str(), fieldName.c_str()); + this->writef(" %s_index = this->cloneAndRegisterChildProcessor(" + "src.childProcessor(src.%s_index));\n" + " }\n", + fieldName.c_str(), fieldName.c_str()); } } if (samplerCount) { diff --git a/chromium/third_party/skia/src/sksl/SkSLCPPCodeGenerator.h b/chromium/third_party/skia/src/sksl/SkSLCPPCodeGenerator.h index 803270cc575..357e7c1ef48 100644 --- a/chromium/third_party/skia/src/sksl/SkSLCPPCodeGenerator.h +++ b/chromium/third_party/skia/src/sksl/SkSLCPPCodeGenerator.h @@ -123,7 +123,9 @@ private: std::vector<String> fExtraEmitCodeBlocks; std::vector<String> fFormatArgs; - std::set<int> fWrittenTransformedCoords; + // true if the sksl referenced sk_TransformedCoords[0] + bool fAccessLocalCoordsDirectly = false; + // if true, we are writing a C++ expression instead of a GLSL expression bool fCPPMode = false; bool fInMain = false; diff --git a/chromium/third_party/skia/src/sksl/SkSLCPPUniformCTypes.cpp b/chromium/third_party/skia/src/sksl/SkSLCPPUniformCTypes.cpp index 061ad55c711..f18c410f2a1 100644 --- a/chromium/third_party/skia/src/sksl/SkSLCPPUniformCTypes.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLCPPUniformCTypes.cpp @@ -176,7 +176,7 @@ static const std::vector<UniformCTypeMapper>& get_mappers() { REGISTER(Layout::CType::kSkMatrix, { "half3x3", "float3x3", "double3x3" }, "${pdman}.setSkMatrix(${uniform}, ${var})", // to gpu - "SkMatrix::MakeScale(SK_FloatNaN)", // default value + "SkMatrix::Scale(SK_FloatNaN, SK_FloatNaN)", // default value "!${oldVar}.cheapEqualTo(${newVar})"), // dirty check REGISTER(Layout::CType::kSkM44, { "half4x4", "float4x4", "double4x4" }, diff --git a/chromium/third_party/skia/src/sksl/SkSLCompiler.cpp b/chromium/third_party/skia/src/sksl/SkSLCompiler.cpp index 9ac276a9e13..d5c1293f7fa 100644 --- a/chromium/third_party/skia/src/sksl/SkSLCompiler.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLCompiler.cpp @@ -78,14 +78,17 @@ static const char* SKSL_PIPELINE_INCLUDE = namespace SkSL { static void grab_intrinsics(std::vector<std::unique_ptr<ProgramElement>>* src, - std::map<StringFragment, std::pair<std::unique_ptr<ProgramElement>, bool>>* target) { - for (auto& element : *src) { + std::map<String, std::pair<std::unique_ptr<ProgramElement>, bool>>* target) { + for (auto iter = src->begin(); iter != src->end(); ) { + std::unique_ptr<ProgramElement>& element = *iter; switch (element->fKind) { case ProgramElement::kFunction_Kind: { FunctionDefinition& f = (FunctionDefinition&) *element; - StringFragment name = f.fDeclaration.fName; - SkASSERT(target->find(name) == target->end()); - (*target)[name] = std::make_pair(std::move(element), false); + SkASSERT(f.fDeclaration.fBuiltin); + String key = f.fDeclaration.declaration(); + SkASSERT(target->find(key) == target->end()); + (*target)[key] = std::make_pair(std::move(element), false); + iter = src->erase(iter); break; } case ProgramElement::kEnum_Kind: { @@ -93,6 +96,7 @@ static void grab_intrinsics(std::vector<std::unique_ptr<ProgramElement>>* src, StringFragment name = e.fTypeName; SkASSERT(target->find(name) == target->end()); (*target)[name] = std::make_pair(std::move(element), false); + iter = src->erase(iter); break; } default: @@ -122,10 +126,6 @@ Compiler::Compiler(Flags flags) ADD_TYPE(Half2); ADD_TYPE(Half3); ADD_TYPE(Half4); - ADD_TYPE(Double); - ADD_TYPE(Double2); - ADD_TYPE(Double3); - ADD_TYPE(Double4); ADD_TYPE(Int); ADD_TYPE(Int2); ADD_TYPE(Int3); @@ -172,18 +172,8 @@ Compiler::Compiler(Flags flags) ADD_TYPE(Half4x2); ADD_TYPE(Half4x3); ADD_TYPE(Half4x4); - ADD_TYPE(Double2x2); - ADD_TYPE(Double2x3); - ADD_TYPE(Double2x4); - ADD_TYPE(Double3x2); - ADD_TYPE(Double3x3); - ADD_TYPE(Double3x4); - ADD_TYPE(Double4x2); - ADD_TYPE(Double4x3); - ADD_TYPE(Double4x4); ADD_TYPE(GenType); ADD_TYPE(GenHType); - ADD_TYPE(GenDType); ADD_TYPE(GenIType); ADD_TYPE(GenUType); ADD_TYPE(GenBType); @@ -194,7 +184,6 @@ Compiler::Compiler(Flags flags) ADD_TYPE(GVec3); ADD_TYPE(GVec4); ADD_TYPE(HVec); - ADD_TYPE(DVec); ADD_TYPE(IVec); ADD_TYPE(UVec); ADD_TYPE(SVec); @@ -249,6 +238,9 @@ Compiler::Compiler(Flags flags) ADD_TYPE(Sampler); ADD_TYPE(Texture2D); + StringFragment fpAliasName("shader"); + fTypes->addWithoutOwnership(fpAliasName, fContext->fFragmentProcessor_Type.get()); + StringFragment skCapsName("sk_Caps"); Variable* skCaps = new Variable(-1, Modifiers(), skCapsName, *fContext->fSkCaps_Type, Variable::kGlobal_Storage); @@ -434,6 +426,7 @@ void Compiler::addDefinitions(const BasicBlock::Node& node, (std::unique_ptr<Expression>*) &fContext->fDefined_Expression, definitions); } + break; } default: break; @@ -1029,88 +1022,167 @@ void Compiler::simplifyExpression(DefinitionMap& definitions, return; } SkASSERT((*iter)->fKind == BasicBlock::Node::kExpression_Kind); - break; } + break; } default: break; } } -// returns true if this statement could potentially execute a break at the current level (we ignore -// nested loops and switches, since any breaks inside of them will merely break the loop / switch) -static bool contains_conditional_break(Statement& s, bool inConditional) { +// Implementation-detail recursive helper function for `contains_conditional_break`. +static bool contains_conditional_break_impl(Statement& s, bool inConditional) { switch (s.fKind) { case Statement::kBlock_Kind: - for (const auto& sub : ((Block&) s).fStatements) { - if (contains_conditional_break(*sub, inConditional)) { + for (const std::unique_ptr<Statement>& sub : static_cast<Block&>(s).fStatements) { + if (contains_conditional_break_impl(*sub, inConditional)) { return true; } } return false; + case Statement::kBreak_Kind: return inConditional; + case Statement::kIf_Kind: { - const IfStatement& i = (IfStatement&) s; - return contains_conditional_break(*i.fIfTrue, true) || - (i.fIfFalse && contains_conditional_break(*i.fIfFalse, true)); + const IfStatement& i = static_cast<IfStatement&>(s); + return contains_conditional_break_impl(*i.fIfTrue, /*inConditional=*/true) || + (i.fIfFalse && + contains_conditional_break_impl(*i.fIfFalse, /*inConditional=*/true)); } + default: return false; } } +// Returns true if this statement could potentially execute a break at the current level. We ignore +// nested loops and switches, since any breaks inside of them will merely break the loop / switch. +static bool contains_conditional_break(Statement& s) { + return contains_conditional_break_impl(s, /*inConditional=*/false); +} + // returns true if this statement definitely executes a break at the current level (we ignore // nested loops and switches, since any breaks inside of them will merely break the loop / switch) static bool contains_unconditional_break(Statement& s) { switch (s.fKind) { case Statement::kBlock_Kind: - for (const auto& sub : ((Block&) s).fStatements) { + for (const std::unique_ptr<Statement>& sub : static_cast<Block&>(s).fStatements) { if (contains_unconditional_break(*sub)) { return true; } } return false; + case Statement::kBreak_Kind: return true; + default: return false; } } +static void move_all_but_break(std::unique_ptr<Statement>& stmt, + std::vector<std::unique_ptr<Statement>>* target) { + switch (stmt->fKind) { + case Statement::kBlock_Kind: { + // Recurse into the block. + Block& block = static_cast<Block&>(*stmt); + + std::vector<std::unique_ptr<Statement>> blockStmts; + blockStmts.reserve(block.fStatements.size()); + for (std::unique_ptr<Statement>& statementInBlock : block.fStatements) { + move_all_but_break(statementInBlock, &blockStmts); + } + + target->push_back(std::make_unique<Block>(block.fOffset, std::move(blockStmts), + block.fSymbols, block.fIsScope)); + break; + } + + case Statement::kBreak_Kind: + // Do not append a break to the target. + break; + + default: + // Append normal statements to the target. + target->push_back(std::move(stmt)); + break; + } +} + // Returns a block containing all of the statements that will be run if the given case matches // (which, owing to the statements being owned by unique_ptrs, means the switch itself will be // broken by this call and must then be discarded). // Returns null (and leaves the switch unmodified) if no such simple reduction is possible, such as // when break statements appear inside conditionals. -static std::unique_ptr<Statement> block_for_case(SwitchStatement* s, SwitchCase* c) { - bool capturing = false; - std::vector<std::unique_ptr<Statement>*> statementPtrs; - for (const auto& current : s->fCases) { - if (current.get() == c) { - capturing = true; +static std::unique_ptr<Statement> block_for_case(SwitchStatement* switchStatement, + SwitchCase* caseToCapture) { + // We have to be careful to not move any of the pointers until after we're sure we're going to + // succeed, so before we make any changes at all, we check the switch-cases to decide on a plan + // of action. First, find the switch-case we are interested in. + auto iter = switchStatement->fCases.begin(); + for (; iter != switchStatement->fCases.end(); ++iter) { + if (iter->get() == caseToCapture) { + break; } - if (capturing) { - for (auto& stmt : current->fStatements) { - if (contains_conditional_break(*stmt, s->fKind == Statement::kIf_Kind)) { - return nullptr; - } - if (contains_unconditional_break(*stmt)) { - capturing = false; - break; - } - statementPtrs.push_back(&stmt); + } + + // Next, walk forward through the rest of the switch. If we find a conditional break, we're + // stuck and can't simplify at all. If we find an unconditional break, we have a range of + // statements that we can use for simplification. + auto startIter = iter; + Statement* unconditionalBreakStmt = nullptr; + for (; iter != switchStatement->fCases.end(); ++iter) { + for (std::unique_ptr<Statement>& stmt : (*iter)->fStatements) { + if (contains_conditional_break(*stmt)) { + // We can't reduce switch-cases to a block when they have conditional breaks. + return nullptr; } - if (!capturing) { + + if (contains_unconditional_break(*stmt)) { + // We found an unconditional break. We can use this block, but we need to strip + // out the break statement. + unconditionalBreakStmt = stmt.get(); break; } } + + if (unconditionalBreakStmt != nullptr) { + break; + } } - std::vector<std::unique_ptr<Statement>> statements; - for (const auto& s : statementPtrs) { - statements.push_back(std::move(*s)); + + // We fell off the bottom of the switch or encountered a break. We know the range of statements + // that we need to move over, and we know it's safe to do so. + std::vector<std::unique_ptr<Statement>> caseStmts; + + // We can move over most of the statements as-is. + while (startIter != iter) { + for (std::unique_ptr<Statement>& stmt : (*startIter)->fStatements) { + caseStmts.push_back(std::move(stmt)); + } + ++startIter; + } + + // If we found an unconditional break at the end, we need to move what we can while avoiding + // that break. + if (unconditionalBreakStmt != nullptr) { + for (std::unique_ptr<Statement>& stmt : (*startIter)->fStatements) { + if (stmt.get() == unconditionalBreakStmt) { + move_all_but_break(stmt, &caseStmts); + unconditionalBreakStmt = nullptr; + break; + } + + caseStmts.push_back(std::move(stmt)); + } } - return std::unique_ptr<Statement>(new Block(-1, std::move(statements), s->fSymbols)); + + SkASSERT(unconditionalBreakStmt == nullptr); // Verify that we fixed the unconditional break. + + // Return our newly-synthesized block. + return std::make_unique<Block>(/*offset=*/-1, std::move(caseStmts), switchStatement->fSymbols); } void Compiler::simplifyStatement(DefinitionMap& definitions, @@ -1262,6 +1334,14 @@ void Compiler::scanCFG(FunctionDefinition& f) { break; case BasicBlock::Node::kExpression_Kind: offset = (*cfg.fBlocks[i].fNodes[0].expression())->fOffset; + if ((*cfg.fBlocks[i].fNodes[0].expression())->fKind == + Expression::kBoolLiteral_Kind) { + // Function inlining can generate do { ... } while(false) loops which always + // break, so the boolean condition is considered unreachable. Since not + // being able to reach a literal is a non-issue in the first place, we + // don't report an error in this case. + continue; + } break; } this->error(offset, String("unreachable")); @@ -1283,7 +1363,22 @@ void Compiler::scanCFG(FunctionDefinition& f) { } updated = false; + bool first = true; for (BasicBlock& b : cfg.fBlocks) { + if (!first && b.fEntrances.empty()) { + // Block was reachable before optimization, but has since become unreachable. In + // addition to being dead code, it's broken - since control flow can't reach it, no + // prior variable definitions can reach it, and therefore variables might look to + // have not been properly assigned. Kill it. + for (BasicBlock::Node& node : b.fNodes) { + if (node.fKind == BasicBlock::Node::kStatement_Kind && + (*node.statement())->fKind != Statement::kNop_Kind) { + node.setStatement(std::unique_ptr<Statement>(new Nop())); + } + } + continue; + } + first = false; DefinitionMap definitions = b.fBefore; for (auto iter = b.fNodes.begin(); iter != b.fNodes.end() && !needsRescan; ++iter) { @@ -1448,6 +1543,20 @@ bool Compiler::optimize(Program& program) { this->scanCFG((FunctionDefinition&) element); } } + // we wait until after analysis to remove dead functions so that we still report errors + // even in unused code + if (program.fSettings.fRemoveDeadFunctions) { + for (auto iter = program.fElements.begin(); iter != program.fElements.end(); ) { + if ((*iter)->fKind == ProgramElement::kFunction_Kind) { + const FunctionDefinition& f = (const FunctionDefinition&) **iter; + if (!f.fDeclaration.fCallCount && f.fDeclaration.fName != "main") { + iter = program.fElements.erase(iter); + continue; + } + } + ++iter; + } + } if (program.fKind != Program::kFragmentProcessor_Kind) { for (auto iter = program.fElements.begin(); iter != program.fElements.end();) { if ((*iter)->fKind == ProgramElement::kVar_Kind) { diff --git a/chromium/third_party/skia/src/sksl/SkSLCompiler.h b/chromium/third_party/skia/src/sksl/SkSLCompiler.h index 65f7a70a371..31931977a1d 100644 --- a/chromium/third_party/skia/src/sksl/SkSLCompiler.h +++ b/chromium/third_party/skia/src/sksl/SkSLCompiler.h @@ -215,8 +215,8 @@ private: Position position(int offset); - std::map<StringFragment, std::pair<std::unique_ptr<ProgramElement>, bool>> fGPUIntrinsics; - std::map<StringFragment, std::pair<std::unique_ptr<ProgramElement>, bool>> fInterpreterIntrinsics; + std::map<String, std::pair<std::unique_ptr<ProgramElement>, bool>> fGPUIntrinsics; + std::map<String, std::pair<std::unique_ptr<ProgramElement>, bool>> fInterpreterIntrinsics; std::unique_ptr<ASTFile> fGpuIncludeSource; std::shared_ptr<SymbolTable> fGpuSymbolTable; std::vector<std::unique_ptr<ProgramElement>> fVertexInclude; diff --git a/chromium/third_party/skia/src/sksl/SkSLContext.h b/chromium/third_party/skia/src/sksl/SkSLContext.h index eb7659a072f..832413035a2 100644 --- a/chromium/third_party/skia/src/sksl/SkSLContext.h +++ b/chromium/third_party/skia/src/sksl/SkSLContext.h @@ -24,10 +24,6 @@ public: , fNull_Type(new Type("null")) , fFloatLiteral_Type(new Type("$floatLiteral", Type::kFloat_NumberKind, 3)) , fIntLiteral_Type(new Type("$intLiteral", Type::kSigned_NumberKind, 1)) - , fDouble_Type(new Type("double", Type::kFloat_NumberKind, 6, true)) - , fDouble2_Type(new Type("double2", *fDouble_Type, 2)) - , fDouble3_Type(new Type("double3", *fDouble_Type, 3)) - , fDouble4_Type(new Type("double4", *fDouble_Type, 4)) , fFloat_Type(new Type("float", Type::kFloat_NumberKind, 5, true)) , fFloat2_Type(new Type("float2", *fFloat_Type, 2)) , fFloat3_Type(new Type("float3", *fFloat_Type, 3)) @@ -82,15 +78,6 @@ public: , fHalf4x2_Type(new Type("half4x2", *fHalf_Type, 4, 2)) , fHalf4x3_Type(new Type("half4x3", *fHalf_Type, 4, 3)) , fHalf4x4_Type(new Type("half4x4", *fHalf_Type, 4, 4)) - , fDouble2x2_Type(new Type("double2x2", *fDouble_Type, 2, 2)) - , fDouble2x3_Type(new Type("double2x3", *fDouble_Type, 2, 3)) - , fDouble2x4_Type(new Type("double2x4", *fDouble_Type, 2, 4)) - , fDouble3x2_Type(new Type("double3x2", *fDouble_Type, 3, 2)) - , fDouble3x3_Type(new Type("double3x3", *fDouble_Type, 3, 3)) - , fDouble3x4_Type(new Type("double3x4", *fDouble_Type, 3, 4)) - , fDouble4x2_Type(new Type("double4x2", *fDouble_Type, 4, 2)) - , fDouble4x3_Type(new Type("double4x3", *fDouble_Type, 4, 3)) - , fDouble4x4_Type(new Type("double4x4", *fDouble_Type, 4, 4)) , fTexture1D_Type(new Type("texture1D", SpvDim1D, false, false, false, true)) , fTexture2D_Type(new Type("texture2D", SpvDim2D, false, false, false, true)) , fTexture3D_Type(new Type("texture3D", SpvDim3D, false, false, false, true)) @@ -158,8 +145,6 @@ public: fFloat3_Type.get(), fFloat4_Type.get() })) , fGenHType_Type(new Type("$genHType", { fHalf_Type.get(), fHalf2_Type.get(), fHalf3_Type.get(), fHalf4_Type.get() })) - , fGenDType_Type(new Type("$genDType", { fDouble_Type.get(), fDouble2_Type.get(), - fDouble3_Type.get(), fDouble4_Type.get() })) , fGenIType_Type(new Type("$genIType", { fInt_Type.get(), fInt2_Type.get(), fInt3_Type.get(), fInt4_Type.get() })) , fGenUType_Type(new Type("$genUType", { fUInt_Type.get(), fUInt2_Type.get(), @@ -188,8 +173,6 @@ public: , fGVec4_Type(new Type("$gfloat4", static_type(*fFloat4_Type))) , fHVec_Type(new Type("$hvec", { fInvalid_Type.get(), fHalf2_Type.get(), fHalf3_Type.get(), fHalf4_Type.get() })) - , fDVec_Type(new Type("$dvec", { fInvalid_Type.get(), fDouble2_Type.get(), - fDouble3_Type.get(), fDouble4_Type.get() })) , fIVec_Type(new Type("$ivec", { fInvalid_Type.get(), fInt2_Type.get(), fInt3_Type.get(), fInt4_Type.get() })) , fUVec_Type(new Type("$uvec", { fInvalid_Type.get(), fUInt2_Type.get(), @@ -219,11 +202,6 @@ public: const std::unique_ptr<Type> fFloatLiteral_Type; const std::unique_ptr<Type> fIntLiteral_Type; - const std::unique_ptr<Type> fDouble_Type; - const std::unique_ptr<Type> fDouble2_Type; - const std::unique_ptr<Type> fDouble3_Type; - const std::unique_ptr<Type> fDouble4_Type; - const std::unique_ptr<Type> fFloat_Type; const std::unique_ptr<Type> fFloat2_Type; const std::unique_ptr<Type> fFloat3_Type; @@ -353,7 +331,6 @@ public: const std::unique_ptr<Type> fGenType_Type; const std::unique_ptr<Type> fGenHType_Type; - const std::unique_ptr<Type> fGenDType_Type; const std::unique_ptr<Type> fGenIType_Type; const std::unique_ptr<Type> fGenUType_Type; const std::unique_ptr<Type> fGenBType_Type; @@ -400,6 +377,11 @@ private: return "<defined>"; } + int nodeCount() const override { + SkASSERT(false); + return 1; + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new Defined(fType)); } diff --git a/chromium/third_party/skia/src/sksl/SkSLDefines.h b/chromium/third_party/skia/src/sksl/SkSLDefines.h index d0ba9d7572e..1138c500633 100644 --- a/chromium/third_party/skia/src/sksl/SkSLDefines.h +++ b/chromium/third_party/skia/src/sksl/SkSLDefines.h @@ -22,6 +22,9 @@ #ifdef SKSL_STANDALONE #define SkASSERT(x) do { if (!(x)) abort(); } while (false) +#define SkASSERTF(x, __VA_ARGS__) do { if (!(x)) { printf(__VA_ARGS__); abort(); } } while (false) +#define SkDEBUGFAIL(x) do { printf("%s", x); abort(); } while (false) +#define SkDEBUGFAILF(fmt, ...) do { printf(__VA_ARGS__); abort(); } while (false) #define SkAssertResult(x) do { if (!(x)) abort(); } while (false) #define SkDEBUGCODE(...) __VA_ARGS__ #define SK_API diff --git a/chromium/third_party/skia/src/sksl/SkSLGLSLCodeGenerator.cpp b/chromium/third_party/skia/src/sksl/SkSLGLSLCodeGenerator.cpp index e21c32c2c22..127145a1921 100644 --- a/chromium/third_party/skia/src/sksl/SkSLGLSLCodeGenerator.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLGLSLCodeGenerator.cpp @@ -87,9 +87,6 @@ String GLSLCodeGenerator::getTypeName(const Type& type) { if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) { result = "vec"; } - else if (component == *fContext.fDouble_Type) { - result = "dvec"; - } else if (component.isSigned()) { result = "ivec"; } @@ -111,9 +108,6 @@ String GLSLCodeGenerator::getTypeName(const Type& type) { if (component == *fContext.fFloat_Type || component == *fContext.fHalf_Type) { result = "mat"; } - else if (component == *fContext.fDouble_Type) { - result = "dmat"; - } else { ABORT("unsupported matrix type"); } @@ -528,7 +522,7 @@ void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) { this->write("-dFdy"); nameWritten = true; } - // fallthru + [[fallthrough]]; case FunctionClass::kDFdx: case FunctionClass::kFwidth: if (!fFoundDerivatives && @@ -1521,11 +1515,15 @@ void GLSLCodeGenerator::writeStatements(const std::vector<std::unique_ptr<Statem } void GLSLCodeGenerator::writeBlock(const Block& b) { - this->writeLine("{"); - fIndentation++; + if (b.fIsScope) { + this->writeLine("{"); + fIndentation++; + } this->writeStatements(b.fStatements); - fIndentation--; - this->write("}"); + if (b.fIsScope) { + fIndentation--; + this->write("}"); + } } void GLSLCodeGenerator::writeIfStatement(const IfStatement& stmt) { diff --git a/chromium/third_party/skia/src/sksl/SkSLHCodeGenerator.cpp b/chromium/third_party/skia/src/sksl/SkSLHCodeGenerator.cpp index 8a6f3502d56..5d4195bcf81 100644 --- a/chromium/third_party/skia/src/sksl/SkSLHCodeGenerator.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLHCodeGenerator.cpp @@ -8,6 +8,7 @@ #include "src/sksl/SkSLHCodeGenerator.h" #include "src/sksl/SkSLParser.h" +#include "src/sksl/SkSLSampleMatrix.h" #include "src/sksl/SkSLUtil.h" #include "src/sksl/ir/SkSLEnum.h" #include "src/sksl/ir/SkSLFunctionDeclaration.h" @@ -272,7 +273,7 @@ void HCodeGenerator::writeConstructor() { this->writef(" {\n"); this->writeSection(CONSTRUCTOR_CODE_SECTION); int samplerCount = 0; - for (const auto& param : fSectionAndParameterHelper.getParameters()) { + for (const Variable* param : fSectionAndParameterHelper.getParameters()) { if (param->fType.kind() == Type::kSampler_Kind) { ++samplerCount; } else if (param->fType.nonnullable() == *fContext.fFragmentProcessor_Type) { @@ -281,36 +282,45 @@ void HCodeGenerator::writeConstructor() { } else { this->writef(" SkASSERT(%s);", String(param->fName).c_str()); } - this->writef(" %s_index = this->numChildProcessors();", - FieldName(String(param->fName).c_str()).c_str()); - if (fSectionAndParameterHelper.hasCoordOverrides(*param)) { - this->writef(" %s->setSampledWithExplicitCoords();", - String(param->fName).c_str()); - } - SampleMatrix matrix = fSectionAndParameterHelper.getMatrix(*param); - switch (matrix.fKind) { - case SampleMatrix::Kind::kVariable: - this->writef(" %s->setSampleMatrix(this, " - "SkSL::SampleMatrix::Kind::kVariable);", - String(param->fName).c_str()); - break; - case SampleMatrix::Kind::kConstantOrUniform: - this->writef(" %s->setSampleMatrix(SkSL::SampleMatrix(" - "SkSL::SampleMatrix::Kind::kConstantOrUniform, this, \"%s\"));", - String(param->fName).c_str(), - matrix.fExpression.c_str()); - break; - case SampleMatrix::Kind::kMixed: - this->writef(" %s->setSampleMatrix(SkSL::SampleMatrix(" - "SkSL::SampleMatrix::Kind::kMixed, this, \"%s\"));", - String(param->fName).c_str(), - matrix.fExpression.c_str()); - break; - case SampleMatrix::Kind::kNone: - break; + + bool explicitCoords = fSectionAndParameterHelper.hasCoordOverrides(*param); + SampleMatrix matrix = SampleMatrix::Make(fProgram, *param); + + String registerFunc; + String matrixArg; + String explicitArg; + + if (explicitCoords && matrix.fKind == SampleMatrix::Kind::kNone) { + registerFunc = "registerExplicitlySampledChild"; + } else { + registerFunc = "registerChild"; + if (explicitCoords) { + explicitArg = ", true"; + } + switch(matrix.fKind) { + case SampleMatrix::Kind::kVariable: + matrixArg.appendf(", SkSL::SampleMatrix::MakeVariable()"); + break; + case SampleMatrix::Kind::kConstantOrUniform: + matrixArg.appendf(", SkSL::SampleMatrix::MakeConstUniform(\"%s\")", + matrix.fExpression.c_str()); + break; + case SampleMatrix::Kind::kMixed: + // Mixed is only produced when combining FPs, not from analysis of sksl + SkASSERT(false); + break; + case SampleMatrix::Kind::kNone: + break; + } } - this->writef(" this->registerChildProcessor(std::move(%s));", - String(param->fName).c_str()); + + this->writef(" %s_index = this->%s(std::move(%s)%s%s);", + FieldName(String(param->fName).c_str()).c_str(), + registerFunc.c_str(), + String(param->fName).c_str(), + matrixArg.c_str(), + explicitArg.c_str()); + if (param->fType.kind() == Type::kNullable_Kind) { this->writef(" }"); } @@ -367,15 +377,18 @@ bool HCodeGenerator::generateCode() { this->writef("%s\n", GetHeader(fProgram, fErrors).c_str()); this->writef(kFragmentProcessorHeader, fFullName.c_str()); this->writef("#ifndef %s_DEFINED\n" - "#define %s_DEFINED\n", + "#define %s_DEFINED\n" + "\n", fFullName.c_str(), fFullName.c_str()); - this->writef("#include \"include/core/SkTypes.h\"\n"); - this->writef("#include \"include/core/SkM44.h\"\n"); + this->writef("#include \"include/core/SkM44.h\"\n" + "#include \"include/core/SkTypes.h\"\n" + "\n"); this->writeSection(HEADER_SECTION); this->writef("\n" "#include \"src/gpu/GrCoordTransform.h\"\n" - "#include \"src/gpu/GrFragmentProcessor.h\"\n"); + "#include \"src/gpu/GrFragmentProcessor.h\"\n" + "\n"); this->writef("class %s : public GrFragmentProcessor {\n" "public:\n", fFullName.c_str()); diff --git a/chromium/third_party/skia/src/sksl/SkSLIRGenerator.cpp b/chromium/third_party/skia/src/sksl/SkSLIRGenerator.cpp index 5ab04abbaaa..40b9128406a 100644 --- a/chromium/third_party/skia/src/sksl/SkSLIRGenerator.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLIRGenerator.cpp @@ -156,6 +156,7 @@ void IRGenerator::start(const Program::Settings* settings, fSkPerVertex = nullptr; fRTAdjust = nullptr; fRTAdjustInterfaceBlock = nullptr; + fInlineVarCounter = 0; if (inherited) { for (const auto& e : *inherited) { if (e->fKind == ProgramElement::kInterfaceBlock_Kind) { @@ -182,7 +183,7 @@ void IRGenerator::finish() { fSettings = nullptr; } -std::unique_ptr<Statement> IRGenerator::convertStatement(const ASTNode& statement) { +std::unique_ptr<Statement> IRGenerator::convertSingleStatement(const ASTNode& statement) { switch (statement.fKind) { case ASTNode::Kind::kBlock: return this->convertBlock(statement); @@ -228,6 +229,24 @@ std::unique_ptr<Statement> IRGenerator::convertStatement(const ASTNode& statemen } } +std::unique_ptr<Statement> IRGenerator::convertStatement(const ASTNode& statement) { + std::vector<std::unique_ptr<Statement>> oldExtraStatements = std::move(fExtraStatements); + std::unique_ptr<Statement> result = this->convertSingleStatement(statement); + if (!result) { + fExtraStatements = std::move(oldExtraStatements); + return nullptr; + } + if (fExtraStatements.size()) { + fExtraStatements.push_back(std::move(result)); + std::unique_ptr<Statement> block(new Block(-1, std::move(fExtraStatements), nullptr, + false)); + fExtraStatements = std::move(oldExtraStatements); + return block; + } + fExtraStatements = std::move(oldExtraStatements); + return result; +} + std::unique_ptr<Block> IRGenerator::convertBlock(const ASTNode& block) { SkASSERT(block.fKind == ASTNode::Kind::kBlock); AutoSymbolTable table(this); @@ -496,15 +515,22 @@ std::unique_ptr<Statement> IRGenerator::convertFor(const ASTNode& f) { ++iter; std::unique_ptr<Expression> test; if (*iter) { + bool oldCanInline = fCanInline; + fCanInline = false; test = this->coerce(this->convertExpression(*iter), *fContext.fBool_Type); + fCanInline = oldCanInline; if (!test) { return nullptr; } + } ++iter; std::unique_ptr<Expression> next; if (*iter) { + bool oldCanInline = fCanInline; + fCanInline = false; next = this->convertExpression(*iter); + fCanInline = oldCanInline; if (!next) { return nullptr; } @@ -524,8 +550,11 @@ std::unique_ptr<Statement> IRGenerator::convertWhile(const ASTNode& w) { SkASSERT(w.fKind == ASTNode::Kind::kWhile); AutoLoopLevel level(this); auto iter = w.begin(); + bool oldCanInline = fCanInline; + fCanInline = false; std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)), *fContext.fBool_Type); + fCanInline = oldCanInline; if (!test) { return nullptr; } @@ -545,8 +574,11 @@ std::unique_ptr<Statement> IRGenerator::convertDo(const ASTNode& d) { if (!statement) { return nullptr; } + bool oldCanInline = fCanInline; + fCanInline = false; std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*(iter++)), *fContext.fBool_Type); + fCanInline = oldCanInline; if (!test) { return nullptr; } @@ -884,7 +916,7 @@ void IRGenerator::convertFunction(const ASTNode& f) { return; } } - if (other->fDefined && !other->fBuiltin) { + if (other->fDefinition && !other->fBuiltin) { fErrors.error(f.fOffset, "duplicate definition of " + other->declaration()); } @@ -907,7 +939,6 @@ void IRGenerator::convertFunction(const ASTNode& f) { // compile body SkASSERT(!fCurrentFunction); fCurrentFunction = decl; - decl->fDefined = true; std::shared_ptr<SymbolTable> old = fSymbolTable; AutoSymbolTable table(this); if (fd.fName == "main" && fKind == Program::kPipelineStage_Kind) { @@ -940,6 +971,7 @@ void IRGenerator::convertFunction(const ASTNode& f) { } std::unique_ptr<FunctionDefinition> result(new FunctionDefinition(f.fOffset, *decl, std::move(body))); + decl->fDefinition = result.get(); result->fSource = &f; fProgramElements->push_back(std::move(result)); } @@ -1398,7 +1430,7 @@ static bool determine_binary_type(const Context& context, *outResultType = &left; return right.canCoerceTo(left); } - // fall through + [[fallthrough]]; case Token::Kind::TK_STAR: if (is_matrix_multiply(left, right)) { // determine final component type @@ -1451,7 +1483,7 @@ static bool determine_binary_type(const Context& context, *outResultType = &left; return right.canCoerceTo(left); } - // fall through + [[fallthrough]]; case Token::Kind::TK_PLUS: // fall through case Token::Kind::TK_MINUS: // fall through case Token::Kind::TK_SLASH: // fall through @@ -1715,7 +1747,15 @@ std::unique_ptr<Expression> IRGenerator::convertBinaryExpression(const ASTNode& if (!left) { return nullptr; } + Token::Kind op = expression.getToken().fKind; + bool oldCanInline = fCanInline; + if (op == Token::Kind::TK_LOGICALAND || op == Token::Kind::TK_LOGICALOR) { + // can't inline the right side of a short-circuiting boolean, because our inlining + // approach runs things out of order + fCanInline = false; + } std::unique_ptr<Expression> right = this->convertExpression(*(iter++)); + fCanInline = oldCanInline; if (!right) { return nullptr; } @@ -1734,7 +1774,6 @@ std::unique_ptr<Expression> IRGenerator::convertBinaryExpression(const ASTNode& } else { rawRightType = &right->fType; } - Token::Kind op = expression.getToken().fKind; if (!determine_binary_type(fContext, op, *rawLeftType, *rawRightType, &leftType, &rightType, &resultType, !Compiler::IsAssignment(op))) { fErrors.error(expression.fOffset, String("type mismatch: '") + @@ -1811,11 +1850,432 @@ std::unique_ptr<Expression> IRGenerator::convertTernaryExpression(const ASTNode& std::move(ifFalse))); } +std::unique_ptr<Expression> IRGenerator::inlineExpression(int offset, + std::map<const Variable*, + const Variable*>* varMap, + const Expression& expression) { + auto expr = [&](const std::unique_ptr<Expression>& e) { + if (e) { + return this->inlineExpression(offset, varMap, *e); + } + return std::unique_ptr<Expression>(nullptr); + }; + switch (expression.fKind) { + case Expression::kBinary_Kind: { + const BinaryExpression& b = (const BinaryExpression&) expression; + return std::unique_ptr<Expression>(new BinaryExpression(offset, + expr(b.fLeft), + b.fOperator, + expr(b.fRight), + b.fType)); + } + case Expression::kBoolLiteral_Kind: + case Expression::kIntLiteral_Kind: + case Expression::kFloatLiteral_Kind: + case Expression::kNullLiteral_Kind: + return expression.clone(); + case Expression::kConstructor_Kind: { + const Constructor& c = (const Constructor&) expression; + std::vector<std::unique_ptr<Expression>> args; + for (const auto& arg : c.fArguments) { + args.push_back(expr(arg)); + } + return std::unique_ptr<Expression>(new Constructor(offset, c.fType, std::move(args))); + } + case Expression::kExternalFunctionCall_Kind: { + const ExternalFunctionCall& e = (const ExternalFunctionCall&) expression; + std::vector<std::unique_ptr<Expression>> args; + for (const auto& arg : e.fArguments) { + args.push_back(expr(arg)); + } + return std::unique_ptr<Expression>(new ExternalFunctionCall(offset, e.fType, + e.fFunction, + std::move(args))); + } + case Expression::kExternalValue_Kind: + return expression.clone(); + case Expression::kFieldAccess_Kind: { + const FieldAccess& f = (const FieldAccess&) expression; + return std::unique_ptr<Expression>(new FieldAccess(expr(f.fBase), f.fFieldIndex, + f.fOwnerKind)); + } + case Expression::kFunctionCall_Kind: { + const FunctionCall& c = (const FunctionCall&) expression; + std::vector<std::unique_ptr<Expression>> args; + for (const auto& arg : c.fArguments) { + args.push_back(expr(arg)); + } + return std::unique_ptr<Expression>(new FunctionCall(offset, c.fType, c.fFunction, + std::move(args))); + } + case Expression::kIndex_Kind: { + const IndexExpression& idx = (const IndexExpression&) expression; + return std::unique_ptr<Expression>(new IndexExpression(fContext, expr(idx.fBase), + expr(idx.fIndex))); + } + case Expression::kPrefix_Kind: { + const PrefixExpression& p = (const PrefixExpression&) expression; + return std::unique_ptr<Expression>(new PrefixExpression(p.fOperator, expr(p.fOperand))); + } + case Expression::kPostfix_Kind: { + const PostfixExpression& p = (const PostfixExpression&) expression; + return std::unique_ptr<Expression>(new PostfixExpression(expr(p.fOperand), + p.fOperator)); + } + case Expression::kSetting_Kind: + return expression.clone(); + case Expression::kSwizzle_Kind: { + const Swizzle& s = (const Swizzle&) expression; + return std::unique_ptr<Expression>(new Swizzle(fContext, expr(s.fBase), s.fComponents)); + } + case Expression::kTernary_Kind: { + const TernaryExpression& t = (const TernaryExpression&) expression; + return std::unique_ptr<Expression>(new TernaryExpression(offset, expr(t.fTest), + expr(t.fIfTrue), + expr(t.fIfFalse))); + } + case Expression::kVariableReference_Kind: { + const VariableReference& v = (const VariableReference&) expression; + auto found = varMap->find(&v.fVariable); + if (found != varMap->end()) { + return std::unique_ptr<Expression>(new VariableReference(offset, + *found->second, + v.fRefKind)); + } + return v.clone(); + } + default: + SkASSERT(false); + return nullptr; + } +} + +std::unique_ptr<Statement> IRGenerator::inlineStatement(int offset, + std::map<const Variable*, + const Variable*>* varMap, + const Variable* returnVar, + bool haveEarlyReturns, + const Statement& statement) { + auto stmt = [&](const std::unique_ptr<Statement>& s) { + if (s) { + return this->inlineStatement(offset, varMap, returnVar, haveEarlyReturns, *s); + } + return std::unique_ptr<Statement>(nullptr); + }; + auto stmts = [&](const std::vector<std::unique_ptr<Statement>>& ss) { + std::vector<std::unique_ptr<Statement>> result; + for (const auto& s : ss) { + result.push_back(stmt(s)); + } + return result; + }; + auto expr = [&](const std::unique_ptr<Expression>& e) { + if (e) { + return this->inlineExpression(offset, varMap, *e); + } + return std::unique_ptr<Expression>(nullptr); + }; + switch (statement.fKind) { + case Statement::kBlock_Kind: { + const Block& b = (const Block&) statement; + return std::unique_ptr<Statement>(new Block(offset, stmts(b.fStatements), b.fSymbols, + b.fIsScope)); + } + + case Statement::kBreak_Kind: + case Statement::kContinue_Kind: + case Statement::kDiscard_Kind: + return statement.clone(); + + case Statement::kDo_Kind: { + const DoStatement& d = (const DoStatement&) statement; + return std::unique_ptr<Statement>(new DoStatement(offset, + stmt(d.fStatement), + expr(d.fTest))); + } + case Statement::kExpression_Kind: { + const ExpressionStatement& e = (const ExpressionStatement&) statement; + return std::unique_ptr<Statement>(new ExpressionStatement(expr(e.fExpression))); + } + case Statement::kFor_Kind: { + const ForStatement& f = (const ForStatement&) statement; + // need to ensure initializer is evaluated first so that we've already remapped its + // declarations by the time we evaluate test & next + std::unique_ptr<Statement> initializer = stmt(f.fInitializer); + return std::unique_ptr<Statement>(new ForStatement(offset, std::move(initializer), + expr(f.fTest), expr(f.fNext), + stmt(f.fStatement), f.fSymbols)); + } + case Statement::kIf_Kind: { + const IfStatement& i = (const IfStatement&) statement; + return std::unique_ptr<Statement>(new IfStatement(offset, i.fIsStatic, expr(i.fTest), + stmt(i.fIfTrue), stmt(i.fIfFalse))); + } + case Statement::kNop_Kind: + return statement.clone(); + case Statement::kReturn_Kind: { + const ReturnStatement& r = (const ReturnStatement&) statement; + if (r.fExpression) { + std::unique_ptr<Statement> assignment(new ExpressionStatement( + std::unique_ptr<Expression>(new BinaryExpression(offset, + std::unique_ptr<Expression>(new VariableReference( + offset, + *returnVar, + VariableReference::kWrite_RefKind)), + Token::Kind::TK_EQ, + expr(r.fExpression), + returnVar->fType)))); + if (haveEarlyReturns) { + std::vector<std::unique_ptr<Statement>> block; + block.push_back(std::move(assignment)); + block.emplace_back(new BreakStatement(offset)); + return std::unique_ptr<Statement>(new Block(offset, std::move(block), nullptr, + false)); + } else { + return assignment; + } + } else { + if (haveEarlyReturns) { + return std::unique_ptr<Statement>(new BreakStatement(offset)); + } else { + return std::unique_ptr<Statement>(new Nop()); + } + } + } + case Statement::kSwitch_Kind: { + const SwitchStatement& ss = (const SwitchStatement&) statement; + std::vector<std::unique_ptr<SwitchCase>> cases; + for (const auto& sc : ss.fCases) { + cases.emplace_back(new SwitchCase(offset, expr(sc->fValue), + stmts(sc->fStatements))); + } + return std::unique_ptr<Statement>(new SwitchStatement(offset, ss.fIsStatic, + expr(ss.fValue), + std::move(cases), + ss.fSymbols)); + } + case Statement::kVarDeclaration_Kind: { + const VarDeclaration& decl = (const VarDeclaration&) statement; + std::vector<std::unique_ptr<Expression>> sizes; + for (const auto& size : decl.fSizes) { + sizes.push_back(expr(size)); + } + std::unique_ptr<Expression> initialValue = expr(decl.fValue); + const Variable* old = decl.fVar; + // need to copy the var name in case the originating function is discarded and we lose + // its symbols + std::unique_ptr<String> name(new String(old->fName)); + String* namePtr = (String*) fSymbolTable->takeOwnership(std::move(name)); + std::unique_ptr<Symbol> type(new Type(old->fType)); + Type* typePtr = (Type*) fSymbolTable->takeOwnership(std::move(type)); + Variable* clone = (Variable*) fSymbolTable->takeOwnership(std::unique_ptr<Symbol>( + new Variable(offset, old->fModifiers, + namePtr->c_str(), *typePtr, + old->fStorage, + initialValue.get()))); + (*varMap)[old] = clone; + return std::unique_ptr<Statement>(new VarDeclaration(clone, std::move(sizes), + std::move(initialValue))); + } + case Statement::kVarDeclarations_Kind: { + const VarDeclarations& decls = *((VarDeclarationsStatement&) statement).fDeclaration; + std::vector<std::unique_ptr<VarDeclaration>> vars; + for (const auto& var : decls.fVars) { + vars.emplace_back((VarDeclaration*) stmt(var).release()); + } + std::unique_ptr<Symbol> type(new Type(decls.fBaseType)); + Type* typePtr = (Type*) fSymbolTable->takeOwnership(std::move(type)); + return std::unique_ptr<Statement>(new VarDeclarationsStatement( + std::unique_ptr<VarDeclarations>(new VarDeclarations(offset, typePtr, + std::move(vars))))); + } + case Statement::kWhile_Kind: { + const WhileStatement& w = (const WhileStatement&) statement; + return std::unique_ptr<Statement>(new WhileStatement(offset, + expr(w.fTest), + stmt(w.fStatement))); + } + default: + SkASSERT(false); + return nullptr; + } +} + +int return_count(const Statement& statement) { + switch (statement.fKind) { + case Statement::kBlock_Kind: { + const Block& b = (const Block&) statement; + int result = 0; + for (const auto& s : b.fStatements) { + result += return_count(*s); + } + return result; + } + case Statement::kDo_Kind: { + const DoStatement& d = (const DoStatement&) statement; + return return_count(*d.fStatement); + } + case Statement::kFor_Kind: { + const ForStatement& f = (const ForStatement&) statement; + return return_count(*f.fStatement); + } + case Statement::kIf_Kind: { + const IfStatement& i = (const IfStatement&) statement; + int result = return_count(*i.fIfTrue); + if (i.fIfFalse) { + result += return_count(*i.fIfFalse); + } + return result; + } + case Statement::kReturn_Kind: + return 1; + case Statement::kSwitch_Kind: { + const SwitchStatement& ss = (const SwitchStatement&) statement; + int result = 0; + for (const auto& sc : ss.fCases) { + for (const auto& s : ((SwitchCase&) *sc).fStatements) { + result += return_count(*s); + } + } + return result; + } + case Statement::kWhile_Kind: { + const WhileStatement& w = (const WhileStatement&) statement; + return return_count(*w.fStatement); + } + case Statement::kBreak_Kind: + case Statement::kContinue_Kind: + case Statement::kDiscard_Kind: + case Statement::kExpression_Kind: + case Statement::kNop_Kind: + case Statement::kVarDeclaration_Kind: + case Statement::kVarDeclarations_Kind: + return 0; + default: + SkASSERT(false); + return 0; + } +} + +bool has_early_return(const FunctionDefinition& f) { + int returnCount = return_count(*f.fBody); + if (returnCount == 0) { + return false; + } + if (returnCount > 1) { + return true; + } + SkASSERT(f.fBody->fKind == Statement::kBlock_Kind); + return ((Block&) *f.fBody).fStatements.back()->fKind != Statement::kReturn_Kind; +} + +std::unique_ptr<Expression> IRGenerator::inlineCall( + int offset, + const FunctionDefinition& function, + std::vector<std::unique_ptr<Expression>> arguments) { + // Inlining is more complicated here than in a typical compiler, because we have to have a + // high-level IR and can't just drop statements into the middle of an expression or even use + // gotos. + // + // Since we can't insert statements into an expression, we run the inline function as extra + // statements before the statement we're currently processing, relying on a lack of execution + // order guarantees. Since we can't use gotos (which are normally used to replace return + // statements), we wrap the whole function in a loop and use break statements to jump to the + // end. + Variable* resultVar; + if (function.fDeclaration.fReturnType != *fContext.fVoid_Type) { + std::unique_ptr<String> name(new String()); + int varIndex = fInlineVarCounter++; + name->appendf("inlineResult%d", varIndex); + String* namePtr = (String*) fSymbolTable->takeOwnership(std::move(name)); + resultVar = (Variable*) fSymbolTable->takeOwnership(std::unique_ptr<Symbol>( + new Variable(-1, Modifiers(), namePtr->c_str(), + function.fDeclaration.fReturnType, + Variable::kLocal_Storage, + nullptr))); + std::vector<std::unique_ptr<VarDeclaration>> variables; + variables.emplace_back(new VarDeclaration(resultVar, {}, nullptr)); + fExtraStatements.emplace_back(new VarDeclarationsStatement( + std::unique_ptr<VarDeclarations>(new VarDeclarations(offset, + &resultVar->fType, + std::move(variables))))); + + } else { + resultVar = nullptr; + } + std::map<const Variable*, const Variable*> varMap; + // create variables to hold the arguments and assign the arguments to them + int argIndex = fInlineVarCounter++; + for (int i = 0; i < (int) arguments.size(); ++i) { + std::unique_ptr<String> argName(new String()); + argName->appendf("inlineArg%d_%d", argIndex, i); + String* argNamePtr = (String*) fSymbolTable->takeOwnership(std::move(argName)); + Variable* argVar = (Variable*) fSymbolTable->takeOwnership(std::unique_ptr<Symbol>( + new Variable(-1, Modifiers(), + argNamePtr->c_str(), + arguments[i]->fType, + Variable::kLocal_Storage, + arguments[i].get()))); + varMap[function.fDeclaration.fParameters[i]] = argVar; + std::vector<std::unique_ptr<VarDeclaration>> vars; + if (function.fDeclaration.fParameters[i]->fModifiers.fFlags & Modifiers::kOut_Flag) { + vars.emplace_back(new VarDeclaration(argVar, {}, arguments[i]->clone())); + } else { + vars.emplace_back(new VarDeclaration(argVar, {}, std::move(arguments[i]))); + } + fExtraStatements.emplace_back(new VarDeclarationsStatement( + std::unique_ptr<VarDeclarations>(new VarDeclarations(offset, + &argVar->fType, + std::move(vars))))); + } + SkASSERT(function.fBody->fKind == Statement::kBlock_Kind); + const Block& body = (Block&) *function.fBody; + bool hasEarlyReturn = has_early_return(function); + std::vector<std::unique_ptr<Statement>> inlined; + for (const auto& s : body.fStatements) { + inlined.push_back(this->inlineStatement(offset, &varMap, resultVar, hasEarlyReturn, *s)); + } + if (hasEarlyReturn) { + // Since we output to backends that don't have a goto statement (which would normally be + // used to perform an early return), we fake it by wrapping the function in a + // do { } while (false); and then use break statements to jump to the end in order to + // emulate a goto. + fExtraStatements.emplace_back(new DoStatement(-1, + std::unique_ptr<Statement>(new Block(-1, std::move(inlined))), + std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, false)))); + } else { + // No early returns, so we can just dump the code in. We need to use a block so we don't get + // name conflicts with locals. + fExtraStatements.emplace_back(std::unique_ptr<Statement>(new Block(-1, + std::move(inlined)))); + } + // copy the values of out parameters into their destinations + for (size_t i = 0; i < arguments.size(); ++i) { + const Variable* p = function.fDeclaration.fParameters[i]; + if (p->fModifiers.fFlags & Modifiers::kOut_Flag) { + std::unique_ptr<Expression> varRef(new VariableReference(offset, *varMap[p])); + fExtraStatements.emplace_back(new ExpressionStatement( + std::unique_ptr<Expression>(new BinaryExpression(offset, + arguments[i]->clone(), + Token::Kind::TK_EQ, + std::move(varRef), + arguments[i]->fType)))); + } + } + if (function.fDeclaration.fReturnType != *fContext.fVoid_Type) { + return std::unique_ptr<Expression>(new VariableReference(-1, *resultVar)); + } else { + // it's a void function, so it doesn't actually result in anything, but we have to return + // something non-null as a standin + return std::unique_ptr<Expression>(new BoolLiteral(fContext, -1, false)); + } +} + std::unique_ptr<Expression> IRGenerator::call(int offset, const FunctionDeclaration& function, std::vector<std::unique_ptr<Expression>> arguments) { if (function.fBuiltin) { - auto found = fIntrinsics->find(function.fName); + auto found = fIntrinsics->find(function.declaration()); if (found != fIntrinsics->end() && !found->second.second) { found->second.second = true; const FunctionDeclaration* old = fCurrentFunction; @@ -1835,7 +2295,7 @@ std::unique_ptr<Expression> IRGenerator::call(int offset, fErrors.error(offset, msg); return nullptr; } - if (fKind == Program::kPipelineStage_Kind && !function.fDefined && !function.fBuiltin) { + if (fKind == Program::kPipelineStage_Kind && !function.fDefinition && !function.fBuiltin) { String msg = "call to undefined function '" + function.fName + "'"; fErrors.error(offset, msg); return nullptr; @@ -1866,6 +2326,11 @@ std::unique_ptr<Expression> IRGenerator::call(int offset, VariableReference::kPointer_RefKind); } } + if (fCanInline && function.fDefinition && function.fDefinition->canBeInlined() && + ((fSettings->fCaps && fSettings->fCaps->canUseDoLoops()) || + !has_early_return(*function.fDefinition))) { + return this->inlineCall(offset, *function.fDefinition, std::move(arguments)); + } return std::unique_ptr<FunctionCall>(new FunctionCall(offset, *returnType, function, std::move(arguments))); } @@ -2264,7 +2729,7 @@ std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expressi swizzleComponents.push_back(1); break; } - // fall through + [[fallthrough]]; case 'z': case 'b': case 'p': @@ -2273,7 +2738,7 @@ std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expressi swizzleComponents.push_back(2); break; } - // fall through + [[fallthrough]]; case 'w': case 'a': case 'q': @@ -2282,7 +2747,7 @@ std::unique_ptr<Expression> IRGenerator::convertSwizzle(std::unique_ptr<Expressi swizzleComponents.push_back(3); break; } - // fall through + [[fallthrough]]; default: fErrors.error(base->fOffset, String::printf("invalid swizzle component '%c'", fields[i])); diff --git a/chromium/third_party/skia/src/sksl/SkSLIRGenerator.h b/chromium/third_party/skia/src/sksl/SkSLIRGenerator.h index 51381e0c3a9..e13e320fe7e 100644 --- a/chromium/third_party/skia/src/sksl/SkSLIRGenerator.h +++ b/chromium/third_party/skia/src/sksl/SkSLIRGenerator.h @@ -83,11 +83,22 @@ private: std::unique_ptr<VarDeclarations> convertVarDeclarations(const ASTNode& decl, Variable::Storage storage); void convertFunction(const ASTNode& f); + std::unique_ptr<Statement> convertSingleStatement(const ASTNode& statement); std::unique_ptr<Statement> convertStatement(const ASTNode& statement); std::unique_ptr<Expression> convertExpression(const ASTNode& expression); std::unique_ptr<ModifiersDeclaration> convertModifiersDeclaration(const ASTNode& m); const Type* convertType(const ASTNode& type); + std::unique_ptr<Expression> inlineExpression(int offset, + std::map<const Variable*, const Variable*>* varMap, + const Expression& expression); + std::unique_ptr<Statement> inlineStatement(int offset, + std::map<const Variable*, const Variable*>* varMap, + const Variable* returnVar, + bool haveEarlyReturns, + const Statement& statement); + std::unique_ptr<Expression> inlineCall(int offset, const FunctionDefinition& function, + std::vector<std::unique_ptr<Expression>> arguments); std::unique_ptr<Expression> call(int offset, const FunctionDeclaration& function, std::vector<std::unique_ptr<Expression>> arguments); @@ -156,9 +167,12 @@ private: std::unordered_map<String, Program::Settings::Value> fCapsMap; std::shared_ptr<SymbolTable> fRootSymbolTable; std::shared_ptr<SymbolTable> fSymbolTable; + // additional statements that need to be inserted before the one that convertStatement is + // currently working on + std::vector<std::unique_ptr<Statement>> fExtraStatements; // Symbols which have definitions in the include files. The bool tells us whether this // intrinsic has been included already. - std::map<StringFragment, std::pair<std::unique_ptr<ProgramElement>, bool>>* fIntrinsics = nullptr; + std::map<String, std::pair<std::unique_ptr<ProgramElement>, bool>>* fIntrinsics = nullptr; int fLoopLevel; int fSwitchLevel; ErrorReporter& fErrors; @@ -168,6 +182,8 @@ private: Variable* fRTAdjust; Variable* fRTAdjustInterfaceBlock; int fRTAdjustFieldIndex; + int fInlineVarCounter; + bool fCanInline = true; friend class AutoSymbolTable; friend class AutoLoopLevel; diff --git a/chromium/third_party/skia/src/sksl/SkSLMetalCodeGenerator.cpp b/chromium/third_party/skia/src/sksl/SkSLMetalCodeGenerator.cpp index b8d700abb59..21fb47f6ea9 100644 --- a/chromium/third_party/skia/src/sksl/SkSLMetalCodeGenerator.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLMetalCodeGenerator.cpp @@ -379,82 +379,94 @@ void MetalCodeGenerator::writeSpecialIntrinsic(const FunctionCall & c, SpecialIn } } -// If it hasn't already been written, writes a constructor for 'matrix' which takes a single value -// of type 'arg'. -String MetalCodeGenerator::getMatrixConstructHelper(const Type& matrix, const Type& arg) { - String key = matrix.name() + arg.name(); - auto found = fHelpers.find(key); - if (found != fHelpers.end()) { - return found->second; - } - String name; +// Generates a constructor for 'matrix' which reorganizes the input arguments into the proper shape. +// Keeps track of previously generated constructors so that we won't generate more than one +// constructor for any given permutation of input argument types. Returns the name of the +// generated constructor method. +String MetalCodeGenerator::getMatrixConstructHelper(const Constructor& c) { + const Type& matrix = c.fType; int columns = matrix.columns(); int rows = matrix.rows(); - if (arg.isNumber()) { - // creating a matrix from a single scalar value - name = "float" + to_string(columns) + "x" + to_string(rows) + "_from_float"; - fExtraFunctions.printf("float%dx%d %s(float x) {\n", - columns, rows, name.c_str()); - fExtraFunctions.printf(" return float%dx%d(", columns, rows); - for (int i = 0; i < columns; ++i) { - if (i > 0) { - fExtraFunctions.writeText(", "); - } - fExtraFunctions.printf("float%d(", rows); - for (int j = 0; j < rows; ++j) { - if (j > 0) { - fExtraFunctions.writeText(", "); + const std::vector<std::unique_ptr<Expression>>& args = c.fArguments; + + // Create the helper-method name and use it as our lookup key. + String name; + name.appendf("float%dx%d_from", columns, rows); + for (const std::unique_ptr<Expression>& expr : args) { + name.appendf("_%s", expr->fType.displayName().c_str()); + } + + // If a helper-method has already been synthesized, we don't need to synthesize it again. + auto [iter, newlyCreated] = fHelpers.insert(name); + if (!newlyCreated) { + return name; + } + + // Unlike GLSL, Metal requires that matrices are initialized with exactly R vectors of C + // components apiece. (In Metal 2.0, you can also supply R*C scalars, but you still cannot + // supply a mixture of scalars and vectors.) + fExtraFunctions.printf("float%dx%d %s(", columns, rows, name.c_str()); + + size_t argIndex = 0; + const char* argSeparator = ""; + for (const std::unique_ptr<Expression>& expr : c.fArguments) { + fExtraFunctions.printf("%s%s x%zu", argSeparator, + expr->fType.displayName().c_str(), argIndex++); + argSeparator = ", "; + } + + fExtraFunctions.printf(") {\n return float%dx%d(", columns, rows); + + argIndex = 0; + int argPosition = 0; + + const char* columnSeparator = ""; + for (int c = 0; c < columns; ++c) { + fExtraFunctions.printf("%sfloat%d(", columnSeparator, rows); + columnSeparator = "), "; + + const char* rowSeparator = ""; + for (int r = 0; r < rows; ++r) { + fExtraFunctions.printf("%s", rowSeparator); + rowSeparator = ", "; + + const Type& argType = args[argIndex]->fType; + switch (argType.kind()) { + case Type::kScalar_Kind: { + fExtraFunctions.printf("x%zu", argIndex); + break; } - if (i == j) { - fExtraFunctions.writeText("x"); - } else { - fExtraFunctions.writeText("0"); + case Type::kVector_Kind: { + fExtraFunctions.printf("x%zu[%d]", argIndex, argPosition); + break; } - } - fExtraFunctions.writeText(")"); - } - fExtraFunctions.writeText(");\n}\n"); - } else if (arg.kind() == Type::kMatrix_Kind) { - // creating a matrix from another matrix - int argColumns = arg.columns(); - int argRows = arg.rows(); - name = "float" + to_string(columns) + "x" + to_string(rows) + "_from_float" + - to_string(argColumns) + "x" + to_string(argRows); - fExtraFunctions.printf("float%dx%d %s(float%dx%d m) {\n", - columns, rows, name.c_str(), argColumns, argRows); - fExtraFunctions.printf(" return float%dx%d(", columns, rows); - for (int i = 0; i < columns; ++i) { - if (i > 0) { - fExtraFunctions.writeText(", "); - } - fExtraFunctions.printf("float%d(", rows); - for (int j = 0; j < rows; ++j) { - if (j > 0) { - fExtraFunctions.writeText(", "); + case Type::kMatrix_Kind: { + fExtraFunctions.printf("x%zu[%d][%d]", argIndex, + argPosition / argType.rows(), + argPosition % argType.rows()); + break; } - if (i < argColumns && j < argRows) { - fExtraFunctions.printf("m[%d][%d]", i, j); - } else { - fExtraFunctions.writeText("0"); + default: { + SkDEBUGFAIL("incorrect type of argument for matrix constructor"); + fExtraFunctions.printf("<error>"); + break; } } - fExtraFunctions.writeText(")"); - } - fExtraFunctions.writeText(");\n}\n"); - } else if (matrix.rows() == 2 && matrix.columns() == 2 && arg == *fContext.fFloat4_Type) { - // float2x2(float4) doesn't work, need to split it into float2x2(float2, float2) - name = "float2x2_from_float4"; - fExtraFunctions.printf( - "float2x2 %s(float4 v) {\n" - " return float2x2(float2(v[0], v[1]), float2(v[2], v[3]));\n" - "}\n", - name.c_str() - ); - } else { - SkASSERT(false); + + ++argPosition; + if (argPosition >= argType.columns() * argType.rows()) { + ++argIndex; + argPosition = 0; + } + } + } + + if (argPosition != 0 || argIndex != args.size()) { + SkDEBUGFAIL("incorrect number of arguments for matrix constructor"); name = "<error>"; } - fHelpers[key] = name; + + fExtraFunctions.printf("));\n}\n"); return name; } @@ -468,43 +480,116 @@ bool MetalCodeGenerator::canCoerce(const Type& t1, const Type& t2) { return t1.isFloat() && t2.isFloat(); } +bool MetalCodeGenerator::matrixConstructHelperIsNeeded(const Constructor& c) { + // A matrix construct helper is only necessary if we are, in fact, constructing a matrix. + if (c.fType.kind() != Type::kMatrix_Kind) { + return false; + } + + // GLSL is fairly free-form about inputs to its matrix constructors, but Metal is not; it + // expects exactly R vectors of C components apiece. (Metal 2.0 also allows a list of R*C + // scalars.) Some cases are simple to translate and so we handle those inline--e.g. a list of + // scalars can be constructed trivially. In more complex cases, we generate a helper function + // that converts our inputs into a properly-shaped matrix. + // A matrix construct helper method is always used if any input argument is a matrix. + // Helper methods are also necessary when any argument would span multiple rows. For instance: + // + // float2 x = (1, 2); + // float3x2(x, 3, 4, 5, 6) = | 1 3 5 | = no helper needed; conversion can be done inline + // | 2 4 6 | + // + // float2 x = (2, 3); + // float3x2(1, x, 4, 5, 6) = | 1 3 5 | = x spans multiple rows; a helper method will be used + // | 2 4 6 | + // + // float4 x = (1, 2, 3, 4); + // float2x2(x) = | 1 3 | = x spans multiple rows; a helper method will be used + // | 2 4 | + // + + int position = 0; + for (const std::unique_ptr<Expression>& expr : c.fArguments) { + // If an input argument is a matrix, we need a helper function. + if (expr->fType.kind() == Type::kMatrix_Kind) { + return true; + } + position += expr->fType.columns(); + if (position > c.fType.rows()) { + // An input argument would span multiple rows; a helper function is required. + return true; + } + if (position == c.fType.rows()) { + // We've advanced to the end of a row. Wrap to the start of the next row. + position = 0; + } + } + + return false; +} + void MetalCodeGenerator::writeConstructor(const Constructor& c, Precedence parentPrecedence) { - if (c.fArguments.size() == 1 && this->canCoerce(c.fType, c.fArguments[0]->fType)) { - this->writeExpression(*c.fArguments[0], parentPrecedence); - return; + // Handle special cases for single-argument constructors. + if (c.fArguments.size() == 1) { + // If the type is coercible, emit it directly. + const Expression& arg = *c.fArguments.front(); + if (this->canCoerce(c.fType, arg.fType)) { + this->writeExpression(arg, parentPrecedence); + return; + } + + // Metal supports creating matrices with a scalar on the diagonal via the single-argument + // matrix constructor. + if (c.fType.kind() == Type::kMatrix_Kind && arg.fType.isNumber()) { + const Type& matrix = c.fType; + this->write("float"); + this->write(to_string(matrix.columns())); + this->write("x"); + this->write(to_string(matrix.rows())); + this->write("("); + this->writeExpression(arg, parentPrecedence); + this->write(")"); + return; + } } - if (c.fType.kind() == Type::kMatrix_Kind && c.fArguments.size() == 1) { - const Expression& arg = *c.fArguments[0]; - String name = this->getMatrixConstructHelper(c.fType, arg.fType); - this->write(name); - this->write("("); - this->writeExpression(arg, kSequence_Precedence); - this->write(")"); - } else { - this->writeType(c.fType); + + // Emit and invoke a matrix-constructor helper method if one is necessary. + if (this->matrixConstructHelperIsNeeded(c)) { + this->write(this->getMatrixConstructHelper(c)); this->write("("); const char* separator = ""; - int scalarCount = 0; - for (const auto& arg : c.fArguments) { + for (const std::unique_ptr<Expression>& expr : c.fArguments) { this->write(separator); separator = ", "; - if (Type::kMatrix_Kind == c.fType.kind() && arg->fType.columns() != c.fType.rows()) { - // merge scalars and smaller vectors together - if (!scalarCount) { - this->writeType(c.fType.componentType()); - this->write(to_string(c.fType.rows())); - this->write("("); - } - scalarCount += arg->fType.columns(); - } - this->writeExpression(*arg, kSequence_Precedence); - if (scalarCount && scalarCount == c.fType.rows()) { - this->write(")"); - scalarCount = 0; - } + this->writeExpression(*expr, kSequence_Precedence); } this->write(")"); + return; + } + + // Explicitly invoke the constructor, passing in the necessary arguments. + this->writeType(c.fType); + this->write("("); + const char* separator = ""; + int scalarCount = 0; + for (const std::unique_ptr<Expression>& arg : c.fArguments) { + this->write(separator); + separator = ", "; + if (Type::kMatrix_Kind == c.fType.kind() && arg->fType.columns() < c.fType.rows()) { + // Merge scalars and smaller vectors together. + if (!scalarCount) { + this->writeType(c.fType.componentType()); + this->write(to_string(c.fType.rows())); + this->write("("); + } + scalarCount += arg->fType.columns(); + } + this->writeExpression(*arg, kSequence_Precedence); + if (scalarCount && scalarCount == c.fType.rows()) { + this->write(")"); + scalarCount = 0; + } } + this->write(")"); } void MetalCodeGenerator::writeFragCoord() { @@ -791,7 +876,7 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) { this->write("vertex Outputs vertexMain"); break; default: - SkASSERT(false); + SkDEBUGFAIL("unsupported kind of program"); } this->write("(Inputs _in [[stage_in]]"); if (-1 != fUniformBuffer) { @@ -906,35 +991,42 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) { if ("main" == f.fDeclaration.fName) { if (fNeedsGlobalStructInit) { - this->writeLine(" Globals globalStruct{"); - const char* separator = ""; - for (const auto& intf: fInterfaceBlockNameMap) { - const auto& intfName = intf.second; - this->write(separator); - separator = ", "; - this->write("&"); - this->writeName(intfName); + this->writeLine(" Globals globalStruct;"); + for (const auto& [interfaceBlock, interfaceName] : fInterfaceBlockNameMap) { + this->write(" globalStruct."); + this->writeName(interfaceName); + this->write(" = &"); + this->writeName(interfaceName); + this->writeLine(";"); } - for (const auto& var: fInitNonConstGlobalVars) { - this->write(separator); - separator = ", "; + for (const VarDeclaration* var : fInitNonConstGlobalVars) { + this->write(" globalStruct."); + this->writeName(var->fVar->fName); + this->write(" = "); this->writeVarInitializer(*var->fVar, *var->fValue); + this->writeLine(";"); } - for (const auto& texture: fTextures) { - this->write(separator); - separator = ", "; + for (const Variable* texture : fTextures) { + this->write(" globalStruct."); this->writeName(texture->fName); - this->write(separator); + this->write(" = "); this->writeName(texture->fName); - this->write(SAMPLER_SUFFIX); + this->writeLine(";"); + + String samplerName = String(texture->fName) + SAMPLER_SUFFIX; + this->write(" globalStruct."); + this->writeName(samplerName); + this->write(" = "); + this->writeName(samplerName); + this->writeLine(";"); } - this->writeLine("};"); this->writeLine(" thread Globals* _globals = &globalStruct;"); this->writeLine(" (void)_globals;"); } this->writeLine(" Outputs _outputStruct;"); this->writeLine(" thread Outputs* _out = &_outputStruct;"); } + fFunctionHeader = ""; OutputStream* oldOut = fOut; StringStream buffer; @@ -951,7 +1043,7 @@ void MetalCodeGenerator::writeFunction(const FunctionDefinition& f) { this->writeLine("return *_out;"); // FIXME - detect if function already has return break; default: - SkASSERT(false); + SkDEBUGFAIL("unsupported kind of program"); } } fIndentation--; @@ -1164,11 +1256,15 @@ void MetalCodeGenerator::writeStatements(const std::vector<std::unique_ptr<State } void MetalCodeGenerator::writeBlock(const Block& b) { - this->writeLine("{"); - fIndentation++; + if (b.fIsScope) { + this->writeLine("{"); + fIndentation++; + } this->writeStatements(b.fStatements); - fIndentation--; - this->write("}"); + if (b.fIsScope) { + fIndentation--; + this->write("}"); + } } void MetalCodeGenerator::writeIfStatement(const IfStatement& stmt) { @@ -1388,11 +1484,15 @@ void MetalCodeGenerator::writeInterfaceBlocks() { void MetalCodeGenerator::writeGlobalStruct() { bool wroteStructDecl = false; - for (const auto& intf : fInterfaceBlockNameMap) { + auto WriteStructDecl = [&] { if (!wroteStructDecl) { this->write("struct Globals {\n"); wroteStructDecl = true; } + }; + + for (const auto& intf : fInterfaceBlockNameMap) { + WriteStructDecl(); fNeedsGlobalStructInit = true; const auto& intfType = intf.first; const auto& intfName = intf.second; @@ -1411,10 +1511,7 @@ void MetalCodeGenerator::writeGlobalStruct() { const Variable& first = *((VarDeclaration&) *decls.fVars[0]).fVar; if ((!first.fModifiers.fFlags && -1 == first.fModifiers.fLayout.fBuiltin) || first.fType.kind() == Type::kSampler_Kind) { - if (!wroteStructDecl) { - this->write("struct Globals {\n"); - wroteStructDecl = true; - } + WriteStructDecl(); fNeedsGlobalStructInit = true; this->write(" "); this->writeType(first.fType); @@ -1478,52 +1575,55 @@ void MetalCodeGenerator::writeProgramElement(const ProgramElement& e) { } } -MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Expression& e) { - switch (e.fKind) { +MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Expression* e) { + if (!e) { + return kNo_Requirements; + } + switch (e->fKind) { case Expression::kFunctionCall_Kind: { - const FunctionCall& f = (const FunctionCall&) e; + const FunctionCall& f = (const FunctionCall&) *e; Requirements result = this->requirements(f.fFunction); - for (const auto& e : f.fArguments) { - result |= this->requirements(*e); + for (const auto& arg : f.fArguments) { + result |= this->requirements(arg.get()); } return result; } case Expression::kConstructor_Kind: { - const Constructor& c = (const Constructor&) e; + const Constructor& c = (const Constructor&) *e; Requirements result = kNo_Requirements; - for (const auto& e : c.fArguments) { - result |= this->requirements(*e); + for (const auto& arg : c.fArguments) { + result |= this->requirements(arg.get()); } return result; } case Expression::kFieldAccess_Kind: { - const FieldAccess& f = (const FieldAccess&) e; + const FieldAccess& f = (const FieldAccess&) *e; if (FieldAccess::kAnonymousInterfaceBlock_OwnerKind == f.fOwnerKind) { return kGlobals_Requirement; } - return this->requirements(*((const FieldAccess&) e).fBase); + return this->requirements(f.fBase.get()); } case Expression::kSwizzle_Kind: - return this->requirements(*((const Swizzle&) e).fBase); + return this->requirements(((const Swizzle&) *e).fBase.get()); case Expression::kBinary_Kind: { - const BinaryExpression& b = (const BinaryExpression&) e; - return this->requirements(*b.fLeft) | this->requirements(*b.fRight); + const BinaryExpression& b = (const BinaryExpression&) *e; + return this->requirements(b.fLeft.get()) | this->requirements(b.fRight.get()); } case Expression::kIndex_Kind: { - const IndexExpression& idx = (const IndexExpression&) e; - return this->requirements(*idx.fBase) | this->requirements(*idx.fIndex); + const IndexExpression& idx = (const IndexExpression&) *e; + return this->requirements(idx.fBase.get()) | this->requirements(idx.fIndex.get()); } case Expression::kPrefix_Kind: - return this->requirements(*((const PrefixExpression&) e).fOperand); + return this->requirements(((const PrefixExpression&) *e).fOperand.get()); case Expression::kPostfix_Kind: - return this->requirements(*((const PostfixExpression&) e).fOperand); + return this->requirements(((const PostfixExpression&) *e).fOperand.get()); case Expression::kTernary_Kind: { - const TernaryExpression& t = (const TernaryExpression&) e; - return this->requirements(*t.fTest) | this->requirements(*t.fIfTrue) | - this->requirements(*t.fIfFalse); + const TernaryExpression& t = (const TernaryExpression&) *e; + return this->requirements(t.fTest.get()) | this->requirements(t.fIfTrue.get()) | + this->requirements(t.fIfFalse.get()); } case Expression::kVariableReference_Kind: { - const VariableReference& v = (const VariableReference&) e; + const VariableReference& v = (const VariableReference&) *e; Requirements result = kNo_Requirements; if (v.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN) { result = kGlobals_Requirement | kFragCoord_Requirement; @@ -1546,69 +1646,65 @@ MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Expressi } } -MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Statement& s) { - switch (s.fKind) { +MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Statement* s) { + if (!s) { + return kNo_Requirements; + } + switch (s->fKind) { case Statement::kBlock_Kind: { Requirements result = kNo_Requirements; - for (const auto& child : ((const Block&) s).fStatements) { - result |= this->requirements(*child); + for (const auto& child : ((const Block*) s)->fStatements) { + result |= this->requirements(child.get()); } return result; } case Statement::kVarDeclaration_Kind: { - Requirements result = kNo_Requirements; - const VarDeclaration& var = (const VarDeclaration&) s; - if (var.fValue) { - result = this->requirements(*var.fValue); - } - return result; + const VarDeclaration& var = (const VarDeclaration&) *s; + return this->requirements(var.fValue.get()); } case Statement::kVarDeclarations_Kind: { Requirements result = kNo_Requirements; - const VarDeclarations& decls = *((const VarDeclarationsStatement&) s).fDeclaration; + const VarDeclarations& decls = *((const VarDeclarationsStatement&) *s).fDeclaration; for (const auto& stmt : decls.fVars) { - result |= this->requirements(*stmt); + result |= this->requirements(stmt.get()); } return result; } case Statement::kExpression_Kind: - return this->requirements(*((const ExpressionStatement&) s).fExpression); + return this->requirements(((const ExpressionStatement&) *s).fExpression.get()); case Statement::kReturn_Kind: { - const ReturnStatement& r = (const ReturnStatement&) s; - if (r.fExpression) { - return this->requirements(*r.fExpression); - } - return kNo_Requirements; + const ReturnStatement& r = (const ReturnStatement&) *s; + return this->requirements(r.fExpression.get()); } case Statement::kIf_Kind: { - const IfStatement& i = (const IfStatement&) s; - return this->requirements(*i.fTest) | - this->requirements(*i.fIfTrue) | - (i.fIfFalse ? this->requirements(*i.fIfFalse) : 0); + const IfStatement& i = (const IfStatement&) *s; + return this->requirements(i.fTest.get()) | + this->requirements(i.fIfTrue.get()) | + this->requirements(i.fIfFalse.get()); } case Statement::kFor_Kind: { - const ForStatement& f = (const ForStatement&) s; - return this->requirements(*f.fInitializer) | - this->requirements(*f.fTest) | - this->requirements(*f.fNext) | - this->requirements(*f.fStatement); + const ForStatement& f = (const ForStatement&) *s; + return this->requirements(f.fInitializer.get()) | + this->requirements(f.fTest.get()) | + this->requirements(f.fNext.get()) | + this->requirements(f.fStatement.get()); } case Statement::kWhile_Kind: { - const WhileStatement& w = (const WhileStatement&) s; - return this->requirements(*w.fTest) | - this->requirements(*w.fStatement); + const WhileStatement& w = (const WhileStatement&) *s; + return this->requirements(w.fTest.get()) | + this->requirements(w.fStatement.get()); } case Statement::kDo_Kind: { - const DoStatement& d = (const DoStatement&) s; - return this->requirements(*d.fTest) | - this->requirements(*d.fStatement); + const DoStatement& d = (const DoStatement&) *s; + return this->requirements(d.fTest.get()) | + this->requirements(d.fStatement.get()); } case Statement::kSwitch_Kind: { - const SwitchStatement& sw = (const SwitchStatement&) s; - Requirements result = this->requirements(*sw.fValue); + const SwitchStatement& sw = (const SwitchStatement&) *s; + Requirements result = this->requirements(sw.fValue.get()); for (const auto& c : sw.fCases) { for (const auto& st : c->fStatements) { - result |= this->requirements(*st); + result |= this->requirements(st.get()); } } return result; @@ -1629,7 +1725,7 @@ MetalCodeGenerator::Requirements MetalCodeGenerator::requirements(const Function if (ProgramElement::kFunction_Kind == e.fKind) { const FunctionDefinition& def = (const FunctionDefinition&) e; if (&def.fDeclaration == &f) { - Requirements reqs = this->requirements(*def.fBody); + Requirements reqs = this->requirements(def.fBody.get()); fRequirements[&f] = reqs; return reqs; } diff --git a/chromium/third_party/skia/src/sksl/SkSLMetalCodeGenerator.h b/chromium/third_party/skia/src/sksl/SkSLMetalCodeGenerator.h index 1b750629c4d..65216dc3aa2 100644 --- a/chromium/third_party/skia/src/sksl/SkSLMetalCodeGenerator.h +++ b/chromium/third_party/skia/src/sksl/SkSLMetalCodeGenerator.h @@ -11,6 +11,7 @@ #include <stack> #include <tuple> #include <unordered_map> +#include <unordered_set> #include "src/sksl/SkSLCodeGenerator.h" #include "src/sksl/SkSLMemoryLayout.h" @@ -189,7 +190,8 @@ protected: void writeInverseHack(const Expression& mat); - String getMatrixConstructHelper(const Type& matrix, const Type& arg); + bool matrixConstructHelperIsNeeded(const Constructor& c); + String getMatrixConstructHelper(const Constructor& c); void writeMatrixTimesEqualHelper(const Type& left, const Type& right, const Type& result); @@ -245,9 +247,9 @@ protected: Requirements requirements(const FunctionDeclaration& f); - Requirements requirements(const Expression& e); + Requirements requirements(const Expression* e); - Requirements requirements(const Statement& e); + Requirements requirements(const Statement* s); typedef std::pair<IntrinsicKind, int32_t> Intrinsic; std::unordered_map<String, Intrinsic> fIntrinsicMap; @@ -278,7 +280,7 @@ protected: std::unordered_map<const FunctionDeclaration*, Requirements> fRequirements; bool fSetupFragPositionGlobal = false; bool fSetupFragPositionLocal = false; - std::unordered_map<String, String> fHelpers; + std::unordered_set<String> fHelpers; int fUniformBuffer = -1; String fRTHeightName; diff --git a/chromium/third_party/skia/src/sksl/SkSLParser.cpp b/chromium/third_party/skia/src/sksl/SkSLParser.cpp index 3f7df7997fd..afa9e3dab1b 100644 --- a/chromium/third_party/skia/src/sksl/SkSLParser.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLParser.cpp @@ -1069,7 +1069,7 @@ ASTNode::ID Parser::statement() { if (this->isType(this->text(start))) { return this->varDeclarations(); } - // fall through + [[fallthrough]]; default: return this->expressionStatement(); } @@ -1370,7 +1370,8 @@ ASTNode::ID Parser::forStatement() { getNode(result).addChild(initializer); break; } - } // fall through + [[fallthrough]]; + } default: initializer = this->expressionStatement(); if (!initializer) { @@ -1960,7 +1961,7 @@ ASTNode::ID Parser::postfixExpression() { if (this->text(t)[0] != '.') { return result; } - // fall through + [[fallthrough]]; case Token::Kind::TK_LBRACKET: case Token::Kind::TK_DOT: case Token::Kind::TK_LPAREN: @@ -2016,6 +2017,7 @@ ASTNode::ID Parser::suffix(ASTNode::ID base) { getNode(result).addChild(base); return result; } + [[fallthrough]]; // FIXME(ethannicholas) } case Token::Kind::TK_FLOAT_LITERAL: { // Swizzles that start with a constant number, e.g. '.000r', will be tokenized as @@ -2082,6 +2084,7 @@ ASTNode::ID Parser::term() { if (this->identifier(&text)) { RETURN_NODE(t.fOffset, ASTNode::Kind::kIdentifier, std::move(text)); } + break; } case Token::Kind::TK_INT_LITERAL: { SKSL_INT i; diff --git a/chromium/third_party/skia/src/sksl/SkSLSPIRVCodeGenerator.cpp b/chromium/third_party/skia/src/sksl/SkSLSPIRVCodeGenerator.cpp index b01bd95c38c..4103592581e 100644 --- a/chromium/third_party/skia/src/sksl/SkSLSPIRVCodeGenerator.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLSPIRVCodeGenerator.cpp @@ -152,8 +152,7 @@ static bool is_float(const Context& context, const Type& type) { if (type.columns() > 1) { return is_float(context, type.componentType()); } - return type == *context.fFloat_Type || type == *context.fHalf_Type || - type == *context.fDouble_Type; + return type == *context.fFloat_Type || type == *context.fHalf_Type; } static bool is_signed(const Context& context, const Type& type) { @@ -254,10 +253,10 @@ void SPIRVCodeGenerator::writeString(const char* string, size_t length, OutputSt switch (length % 4) { case 1: out.write8(0); - // fall through + [[fallthrough]]; case 2: out.write8(0); - // fall through + [[fallthrough]]; case 3: out.write8(0); break; @@ -491,8 +490,6 @@ SpvId SPIRVCodeGenerator::getType(const Type& rawType, const MemoryLayout& layou } else if (type == *fContext.fFloat_Type || type == *fContext.fHalf_Type || type == *fContext.fFloatLiteral_Type) { this->writeInstruction(SpvOpTypeFloat, result, 32, fConstantBuffer); - } else if (type == *fContext.fDouble_Type) { - this->writeInstruction(SpvOpTypeFloat, result, 64, fConstantBuffer); } else { SkASSERT(false); } @@ -1813,77 +1810,111 @@ SpvId SPIRVCodeGenerator::writeVariableReference(const VariableReference& ref, O this->writeInstruction(SpvOpLoad, this->getType(ref.fVariable.fType), result, var, out); this->writePrecisionModifier(ref.fVariable.fType, result); if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOORD_BUILTIN && - fProgram.fSettings.fFlipY) { - // need to remap to a top-left coordinate system - if (fRTHeightStructId == (SpvId) -1) { - // height variable hasn't been written yet - std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors)); - SkASSERT(fRTHeightFieldIndex == (SpvId) -1); - std::vector<Type::Field> fields; - SkASSERT(fProgram.fSettings.fRTHeightOffset >= 0); - fields.emplace_back(Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, - -1, -1, -1, -1, Layout::Format::kUnspecified, - Layout::kUnspecified_Primitive, -1, -1, "", "", - Layout::kNo_Key, Layout::CType::kDefault), 0), - SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get()); - StringFragment name("sksl_synthetic_uniforms"); - Type intfStruct(-1, name, fields); - - int binding = fProgram.fSettings.fRTHeightBinding; - int set = fProgram.fSettings.fRTHeightSet; - SkASSERT(binding != -1 && set != -1); - - Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified, - Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key, - Layout::CType::kDefault); - Variable* intfVar = (Variable*) fSynthetics.takeOwnership(std::unique_ptr<Symbol>( - new Variable(-1, - Modifiers(layout, Modifiers::kUniform_Flag), - name, - intfStruct, - Variable::kGlobal_Storage))); - InterfaceBlock intf(-1, intfVar, name, String(""), - std::vector<std::unique_ptr<Expression>>(), st); - fRTHeightStructId = this->writeInterfaceBlock(intf); - fRTHeightFieldIndex = 0; - } - SkASSERT(fRTHeightFieldIndex != (SpvId) -1); - // write float4(gl_FragCoord.x, u_skRTHeight - gl_FragCoord.y, 0.0, gl_FragCoord.w) + (fProgram.fSettings.fFlipY || fProgram.fSettings.fInverseW)) { + // The x component never changes, so just grab it SpvId xId = this->nextId(); this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), xId, result, 0, out); - IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex); - SpvId fieldIndexId = this->writeIntLiteral(fieldIndex); - SpvId heightPtr = this->nextId(); - this->writeOpCode(SpvOpAccessChain, 5, out); - this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), out); - this->writeWord(heightPtr, out); - this->writeWord(fRTHeightStructId, out); - this->writeWord(fieldIndexId, out); - SpvId heightRead = this->nextId(); - this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead, - heightPtr, out); + + // Calculate the y component which may need to be flipped SpvId rawYId = this->nextId(); this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawYId, result, 1, out); - SpvId flippedYId = this->nextId(); - this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId, - heightRead, rawYId, out); + SpvId flippedYId = 0; + if (fProgram.fSettings.fFlipY) { + // need to remap to a top-left coordinate system + if (fRTHeightStructId == (SpvId)-1) { + // height variable hasn't been written yet + std::shared_ptr<SymbolTable> st(new SymbolTable(&fErrors)); + SkASSERT(fRTHeightFieldIndex == (SpvId)-1); + std::vector<Type::Field> fields; + SkASSERT(fProgram.fSettings.fRTHeightOffset >= 0); + fields.emplace_back( + Modifiers(Layout(0, -1, fProgram.fSettings.fRTHeightOffset, -1, -1, -1, -1, + -1, Layout::Format::kUnspecified, + Layout::kUnspecified_Primitive, 1, -1, "", "", + Layout::kNo_Key, Layout::CType::kDefault), + 0), + SKSL_RTHEIGHT_NAME, fContext.fFloat_Type.get()); + StringFragment name("sksl_synthetic_uniforms"); + Type intfStruct(-1, name, fields); + + int binding = fProgram.fSettings.fRTHeightBinding; + int set = fProgram.fSettings.fRTHeightSet; + SkASSERT(binding != -1 && set != -1); + + Layout layout(0, -1, -1, binding, -1, set, -1, -1, Layout::Format::kUnspecified, + Layout::kUnspecified_Primitive, -1, -1, "", "", Layout::kNo_Key, + Layout::CType::kDefault); + Variable* intfVar = (Variable*)fSynthetics.takeOwnership(std::unique_ptr<Symbol>( + new Variable(-1, + Modifiers(layout, Modifiers::kUniform_Flag), + name, + intfStruct, + Variable::kGlobal_Storage))); + InterfaceBlock intf(-1, intfVar, name, String(""), + std::vector<std::unique_ptr<Expression>>(), st); + + fRTHeightStructId = this->writeInterfaceBlock(intf, false); + fRTHeightFieldIndex = 0; + } + SkASSERT(fRTHeightFieldIndex != (SpvId)-1); + + IntLiteral fieldIndex(fContext, -1, fRTHeightFieldIndex); + SpvId fieldIndexId = this->writeIntLiteral(fieldIndex); + SpvId heightPtr = this->nextId(); + this->writeOpCode(SpvOpAccessChain, 5, out); + this->writeWord(this->getPointerType(*fContext.fFloat_Type, SpvStorageClassUniform), + out); + this->writeWord(heightPtr, out); + this->writeWord(fRTHeightStructId, out); + this->writeWord(fieldIndexId, out); + SpvId heightRead = this->nextId(); + this->writeInstruction(SpvOpLoad, this->getType(*fContext.fFloat_Type), heightRead, + heightPtr, out); + + flippedYId = this->nextId(); + this->writeInstruction(SpvOpFSub, this->getType(*fContext.fFloat_Type), flippedYId, + heightRead, rawYId, out); + } + + // The z component will always be zero so we just get an id to the 0 literal FloatLiteral zero(fContext, -1, 0.0); SpvId zeroId = writeFloatLiteral(zero); - FloatLiteral one(fContext, -1, 1.0); - SpvId wId = this->nextId(); - this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), wId, + + // Calculate the w component which may need to be inverted + SpvId rawWId = this->nextId(); + this->writeInstruction(SpvOpCompositeExtract, this->getType(*fContext.fFloat_Type), rawWId, result, 3, out); - SpvId flipped = this->nextId(); + SpvId invWId = 0; + if (fProgram.fSettings.fInverseW) { + // We need to invert w + FloatLiteral one(fContext, -1, 1.0); + SpvId oneId = writeFloatLiteral(one); + invWId = this->nextId(); + this->writeInstruction(SpvOpFDiv, this->getType(*fContext.fFloat_Type), invWId, oneId, + rawWId, out); + } + + // Fill in the new fragcoord with the components from above + SpvId adjusted = this->nextId(); this->writeOpCode(SpvOpCompositeConstruct, 7, out); this->writeWord(this->getType(*fContext.fFloat4_Type), out); - this->writeWord(flipped, out); + this->writeWord(adjusted, out); this->writeWord(xId, out); - this->writeWord(flippedYId, out); + if (fProgram.fSettings.fFlipY) { + this->writeWord(flippedYId, out); + } else { + this->writeWord(rawYId, out); + } this->writeWord(zeroId, out); - this->writeWord(wId, out); - return flipped; + if (fProgram.fSettings.fInverseW) { + this->writeWord(invWId, out); + } else { + this->writeWord(rawWId, out); + } + + return adjusted; } if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_CLOCKWISE_BUILTIN && !fProgram.fSettings.fFlipY) { @@ -2510,42 +2541,26 @@ SpvId SPIRVCodeGenerator::writeIntLiteral(const IntLiteral& i) { } SpvId SPIRVCodeGenerator::writeFloatLiteral(const FloatLiteral& f) { - if (f.fType != *fContext.fDouble_Type) { - ConstantType type; - if (f.fType == *fContext.fHalf_Type) { - type = ConstantType::kHalf; - } else { - type = ConstantType::kFloat; - } - float value = (float) f.fValue; - std::pair<ConstantValue, ConstantType> key(f.fValue, type); - auto entry = fNumberConstants.find(key); - if (entry == fNumberConstants.end()) { - SpvId result = this->nextId(); - uint32_t bits; - SkASSERT(sizeof(bits) == sizeof(value)); - memcpy(&bits, &value, sizeof(bits)); - this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits, - fConstantBuffer); - fNumberConstants[key] = result; - return result; - } - return entry->second; + ConstantType type; + if (f.fType == *fContext.fHalf_Type) { + type = ConstantType::kHalf; } else { - std::pair<ConstantValue, ConstantType> key(f.fValue, ConstantType::kDouble); - auto entry = fNumberConstants.find(key); - if (entry == fNumberConstants.end()) { - SpvId result = this->nextId(); - uint64_t bits; - SkASSERT(sizeof(bits) == sizeof(f.fValue)); - memcpy(&bits, &f.fValue, sizeof(bits)); - this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, - bits & 0xffffffff, bits >> 32, fConstantBuffer); - fNumberConstants[key] = result; - return result; - } - return entry->second; + type = ConstantType::kFloat; } + float value = (float) f.fValue; + std::pair<ConstantValue, ConstantType> key(f.fValue, type); + auto entry = fNumberConstants.find(key); + if (entry == fNumberConstants.end()) { + SpvId result = this->nextId(); + uint32_t bits; + SkASSERT(sizeof(bits) == sizeof(value)); + memcpy(&bits, &value, sizeof(bits)); + this->writeInstruction(SpvOpConstant, this->getType(f.fType), result, bits, + fConstantBuffer); + fNumberConstants[key] = result; + return result; + } + return entry->second; } SpvId SPIRVCodeGenerator::writeFunctionStart(const FunctionDeclaration& f, OutputStream& out) { @@ -2663,7 +2678,7 @@ static void update_sk_in_count(const Modifiers& m, int* outSkInCount) { } } -SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) { +SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight) { bool isBuffer = (0 != (intf.fVariable.fModifiers.fFlags & Modifiers::kBuffer_Flag)); bool pushConstant = (0 != (intf.fVariable.fModifiers.fLayout.fFlags & Layout::kPushConstant_Flag)); @@ -2672,7 +2687,7 @@ SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) { fDefaultLayout; SpvId result = this->nextId(); const Type* type = &intf.fVariable.fType; - if (fProgram.fInputs.fRTHeight) { + if (fProgram.fInputs.fRTHeight && appendRTHeight) { SkASSERT(fRTHeightStructId == (SpvId) -1); SkASSERT(fRTHeightFieldIndex == (SpvId) -1); std::vector<Type::Field> fields = type->fields(); @@ -2709,7 +2724,7 @@ SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) { } this->writeLayout(layout, result); fVariableMap[&intf.fVariable] = result; - if (fProgram.fInputs.fRTHeight) { + if (fProgram.fInputs.fRTHeight && appendRTHeight) { delete type; } return result; @@ -2987,14 +3002,6 @@ void SPIRVCodeGenerator::writeWhileStatement(const WhileStatement& w, OutputStre } void SPIRVCodeGenerator::writeDoStatement(const DoStatement& d, OutputStream& out) { - // We believe the do loop code below will work, but Skia doesn't actually use them and - // adequately testing this code in the absence of Skia exercising it isn't straightforward. For - // the time being, we just fail with an error due to the lack of testing. If you encounter this - // message, simply remove the error call below to see whether our do loop support actually - // works. - fErrors.error(d.fOffset, "internal error: do loop support has been disabled in SPIR-V, see " - "SkSLSPIRVCodeGenerator.cpp for details"); - SpvId header = this->nextId(); SpvId start = this->nextId(); SpvId next = this->nextId(); diff --git a/chromium/third_party/skia/src/sksl/SkSLSPIRVCodeGenerator.h b/chromium/third_party/skia/src/sksl/SkSLSPIRVCodeGenerator.h index 8f14b46fb57..efb89a5dca9 100644 --- a/chromium/third_party/skia/src/sksl/SkSLSPIRVCodeGenerator.h +++ b/chromium/third_party/skia/src/sksl/SkSLSPIRVCodeGenerator.h @@ -177,7 +177,7 @@ private: void writeProgramElement(const ProgramElement& pe, OutputStream& out); - SpvId writeInterfaceBlock(const InterfaceBlock& intf); + SpvId writeInterfaceBlock(const InterfaceBlock& intf, bool appendRTHeight = true); SpvId writeFunctionStart(const FunctionDeclaration& f, OutputStream& out); diff --git a/chromium/third_party/skia/src/sksl/SkSLSampleMatrix.cpp b/chromium/third_party/skia/src/sksl/SkSLSampleMatrix.cpp index 4593702c0e8..9b07f5948e8 100644 --- a/chromium/third_party/skia/src/sksl/SkSLSampleMatrix.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLSampleMatrix.cpp @@ -7,13 +7,32 @@ #include "src/sksl/SkSLSampleMatrix.h" +#include "src/sksl/ir/SkSLBinaryExpression.h" +#include "src/sksl/ir/SkSLConstructor.h" +#include "src/sksl/ir/SkSLDoStatement.h" #include "src/sksl/ir/SkSLExpression.h" +#include "src/sksl/ir/SkSLExpressionStatement.h" +#include "src/sksl/ir/SkSLFieldAccess.h" +#include "src/sksl/ir/SkSLForStatement.h" +#include "src/sksl/ir/SkSLFunctionCall.h" +#include "src/sksl/ir/SkSLIfStatement.h" +#include "src/sksl/ir/SkSLIndexExpression.h" +#include "src/sksl/ir/SkSLPostfixExpression.h" +#include "src/sksl/ir/SkSLPrefixExpression.h" +#include "src/sksl/ir/SkSLProgram.h" +#include "src/sksl/ir/SkSLReturnStatement.h" +#include "src/sksl/ir/SkSLSwitchStatement.h" +#include "src/sksl/ir/SkSLSwizzle.h" +#include "src/sksl/ir/SkSLTernaryExpression.h" +#include "src/sksl/ir/SkSLVarDeclarationsStatement.h" +#include "src/sksl/ir/SkSLVariable.h" +#include "src/sksl/ir/SkSLWhileStatement.h" namespace SkSL { SampleMatrix SampleMatrix::merge(const SampleMatrix& other) { if (fKind == Kind::kVariable || other.fKind == Kind::kVariable) { - *this = SampleMatrix(Kind::kVariable); + *this = SampleMatrix::MakeVariable(); return *this; } if (other.fKind == Kind::kConstantOrUniform) { @@ -21,7 +40,7 @@ SampleMatrix SampleMatrix::merge(const SampleMatrix& other) { if (fExpression == other.fExpression) { return *this; } - *this = SampleMatrix(Kind::kVariable); + *this = SampleMatrix::MakeVariable(); return *this; } SkASSERT(fKind == Kind::kNone); @@ -31,4 +50,175 @@ SampleMatrix SampleMatrix::merge(const SampleMatrix& other) { return *this; } +struct SampleMatrixExtractor { + SampleMatrixExtractor(const Program& program, const Variable& fp) + : fProgram(program), fFP(fp) {} + + SampleMatrix getMatrix(const Expression&) const; + SampleMatrix getMatrix(const Statement&) const; + + SampleMatrix getMatrix(const Expression* e) const { + return e ? this->getMatrix(*e) : SampleMatrix(); + } + SampleMatrix getMatrix(const Statement* s) const { + return s ? this->getMatrix(*s) : SampleMatrix(); + } + + SampleMatrix getMatrix(const ProgramElement& pe) const { + if (pe.fKind == ProgramElement::kFunction_Kind) { + return this->getMatrix(*((const FunctionDefinition&) pe).fBody); + } + return SampleMatrix(); + } + + const Program& fProgram; + const Variable& fFP; +}; + +SampleMatrix SampleMatrix::Make(const Program& program, const Variable& fp) { + SampleMatrix result; + SampleMatrixExtractor extractor(program, fp); + for (const auto& pe : program) { + result.merge(extractor.getMatrix(pe)); + } + return result; +} + +SampleMatrix SampleMatrixExtractor::getMatrix(const Expression& e) const { + switch (e.fKind) { + case Expression::kFunctionCall_Kind: { + const FunctionCall& fc = (const FunctionCall&) e; + const FunctionDeclaration& f = fc.fFunction; + if (f.fBuiltin && f.fName == "sample" && fc.fArguments.size() >= 2 && + fc.fArguments.back()->fType == *fProgram.fContext->fFloat3x3_Type && + fc.fArguments[0]->fKind == Expression::kVariableReference_Kind && + &((VariableReference&) *fc.fArguments[0]).fVariable == &fFP) { + if (fc.fArguments.back()->isConstantOrUniform()) { + return SampleMatrix::MakeConstUniform(fc.fArguments.back()->description()); + } else { + return SampleMatrix::MakeVariable(); + } + } + SampleMatrix result; + for (const auto& e : fc.fArguments) { + result.merge(this->getMatrix(*e)); + } + return result; + } + case Expression::kConstructor_Kind: { + SampleMatrix result; + const Constructor& c = (const Constructor&) e; + for (const auto& e : c.fArguments) { + result.merge(this->getMatrix(*e)); + } + return result; + } + case Expression::kFieldAccess_Kind: + return this->getMatrix(*((const FieldAccess&) e).fBase); + case Expression::kSwizzle_Kind: + return this->getMatrix(*((const Swizzle&) e).fBase); + case Expression::kBinary_Kind: { + const BinaryExpression& b = (const BinaryExpression&) e; + return this->getMatrix(*b.fLeft).merge( + this->getMatrix(*b.fRight)); + } + case Expression::kIndex_Kind: { + const IndexExpression& idx = (const IndexExpression&) e; + return this->getMatrix(*idx.fBase).merge( + this->getMatrix(*idx.fIndex)); + } + case Expression::kPrefix_Kind: + return this->getMatrix(*((const PrefixExpression&) e).fOperand); + case Expression::kPostfix_Kind: + return this->getMatrix(*((const PostfixExpression&) e).fOperand); + case Expression::kTernary_Kind: { + const TernaryExpression& t = (const TernaryExpression&) e; + return this->getMatrix(*t.fTest).merge( + this->getMatrix(*t.fIfTrue)).merge( + this->getMatrix(*t.fIfFalse)); + } + case Expression::kVariableReference_Kind: + return SampleMatrix(); + case Expression::kBoolLiteral_Kind: + case Expression::kDefined_Kind: + case Expression::kExternalFunctionCall_Kind: + case Expression::kExternalValue_Kind: + case Expression::kFloatLiteral_Kind: + case Expression::kFunctionReference_Kind: + case Expression::kIntLiteral_Kind: + case Expression::kNullLiteral_Kind: + case Expression::kSetting_Kind: + case Expression::kTypeReference_Kind: + return SampleMatrix(); + } + SkASSERT(false); + return SampleMatrix(); +} + +SampleMatrix SampleMatrixExtractor::getMatrix(const Statement& s) const { + switch (s.fKind) { + case Statement::kBlock_Kind: { + SampleMatrix result; + for (const auto& child : ((const Block&) s).fStatements) { + result.merge(this->getMatrix(*child)); + } + return result; + } + case Statement::kVarDeclaration_Kind: + return this->getMatrix(((const VarDeclaration&) s).fValue.get()); + case Statement::kVarDeclarations_Kind: { + const VarDeclarations& decls = *((const VarDeclarationsStatement&) s).fDeclaration; + SampleMatrix result; + for (const auto& stmt : decls.fVars) { + result.merge(this->getMatrix(*stmt)); + } + return result; + } + case Statement::kExpression_Kind: + return this->getMatrix(*((const ExpressionStatement&) s).fExpression); + case Statement::kReturn_Kind: + return this->getMatrix(((const ReturnStatement&) s).fExpression.get()); + case Statement::kIf_Kind: { + const IfStatement& i = (const IfStatement&) s; + return this->getMatrix(*i.fTest).merge( + this->getMatrix(*i.fIfTrue)).merge( + this->getMatrix(i.fIfFalse.get())); + } + case Statement::kFor_Kind: { + const ForStatement& f = (const ForStatement&) s; + return this->getMatrix(f.fInitializer.get()).merge( + this->getMatrix(f.fTest.get()).merge( + this->getMatrix(f.fNext.get()).merge( + this->getMatrix(*f.fStatement)))); + } + case Statement::kWhile_Kind: { + const WhileStatement& w = (const WhileStatement&) s; + return this->getMatrix(*w.fTest).merge( + this->getMatrix(*w.fStatement)); + } + case Statement::kDo_Kind: { + const DoStatement& d = (const DoStatement&) s; + return this->getMatrix(*d.fTest).merge( + this->getMatrix(*d.fStatement)); + } + case Statement::kSwitch_Kind: { + SampleMatrix result; + const SwitchStatement& sw = (const SwitchStatement&) s; + for (const auto& c : sw.fCases) { + for (const auto& st : c->fStatements) { + result.merge(this->getMatrix(*st)); + } + } + return result.merge(this->getMatrix(*sw.fValue)); + } + case Statement::kBreak_Kind: + case Statement::kContinue_Kind: + case Statement::kDiscard_Kind: + case Statement::kNop_Kind: + return SampleMatrix(); + } + SkASSERT(false); + return SampleMatrix(); +} + } // namespace diff --git a/chromium/third_party/skia/src/sksl/SkSLSampleMatrix.h b/chromium/third_party/skia/src/sksl/SkSLSampleMatrix.h index 7f121b07c03..41c0cb68ee5 100644 --- a/chromium/third_party/skia/src/sksl/SkSLSampleMatrix.h +++ b/chromium/third_party/skia/src/sksl/SkSLSampleMatrix.h @@ -16,6 +16,8 @@ class GrFragmentProcessor; namespace SkSL { struct Expression; +struct Program; +struct Variable; /** * Represents the matrix applied to a fragment processor by its parent's sample(child, matrix) call. @@ -25,7 +27,8 @@ struct SampleMatrix { // No sample(child, matrix) call affects the FP. kNone, // The FP is sampled with a matrix whose value is fixed and based only on constants or - // uniforms, and thus the transform can be hoisted to the vertex shader. + // uniforms, and thus the transform can be hoisted to the vertex shader (assuming that + // its parent can also be hoisted, i.e. not sampled explicitly). kConstantOrUniform, // The FP is sampled with a non-constant/uniform value, or sampled multiple times, and // thus the transform cannot be hoisted to the vertex shader. @@ -36,25 +39,25 @@ struct SampleMatrix { kMixed, }; + // Make a SampleMatrix with kNone for its kind. Will not have an expression or have perspective. SampleMatrix() - : fOwner(nullptr) - , fKind(Kind::kNone) {} + : fOwner(nullptr) + , fKind(Kind::kNone) {} - SampleMatrix(Kind kind) - : fOwner(nullptr) - , fKind(kind) { - SkASSERT(kind == Kind::kNone || kind == Kind::kVariable); + static SampleMatrix MakeConstUniform(String expression) { + return SampleMatrix(Kind::kConstantOrUniform, expression); } - SampleMatrix(Kind kind, GrFragmentProcessor* owner, String expression) - : fOwner(owner) - , fKind(kind) - , fExpression(expression) {} + static SampleMatrix MakeVariable() { + return SampleMatrix(Kind::kVariable, ""); + } + + static SampleMatrix Make(const Program& program, const Variable& fp); SampleMatrix merge(const SampleMatrix& other); bool operator==(const SampleMatrix& other) const { - return fKind == other.fKind && fExpression == other.fExpression; + return fKind == other.fKind && fExpression == other.fExpression && fOwner == other.fOwner; } #ifdef SK_DEBUG @@ -72,11 +75,20 @@ struct SampleMatrix { } #endif + // TODO(michaelludwig): fOwner and fBase are going away; owner is filled in automatically when + // a matrix-sampled FP is registered as a child. GrFragmentProcessor* fOwner; Kind fKind; // The constant or uniform expression representing the matrix (will be the empty string when // kind == kNone or kVariable) String fExpression; + const GrFragmentProcessor* fBase = nullptr; + +private: + SampleMatrix(Kind kind, String expression) + : fOwner(nullptr) + , fKind(kind) + , fExpression(expression) {} }; } // namespace diff --git a/chromium/third_party/skia/src/sksl/SkSLSectionAndParameterHelper.cpp b/chromium/third_party/skia/src/sksl/SkSLSectionAndParameterHelper.cpp index a8973868110..e05c5087883 100644 --- a/chromium/third_party/skia/src/sksl/SkSLSectionAndParameterHelper.cpp +++ b/chromium/third_party/skia/src/sksl/SkSLSectionAndParameterHelper.cpp @@ -199,9 +199,9 @@ bool SectionAndParameterHelper::hasCoordOverrides(const Statement& s, const Vari } case Statement::kFor_Kind: { const ForStatement& f = (const ForStatement&) s; - return this->hasCoordOverrides(*f.fInitializer, fp) || - this->hasCoordOverrides(*f.fTest, fp) || - this->hasCoordOverrides(*f.fNext, fp) || + return (f.fInitializer ? this->hasCoordOverrides(*f.fInitializer, fp) : 0) || + (f.fTest ? this->hasCoordOverrides(*f.fTest, fp) : 0) || + (f.fNext ? this->hasCoordOverrides(*f.fNext, fp) : 0) || this->hasCoordOverrides(*f.fStatement, fp); } case Statement::kWhile_Kind: { @@ -228,7 +228,6 @@ bool SectionAndParameterHelper::hasCoordOverrides(const Statement& s, const Vari case Statement::kBreak_Kind: case Statement::kContinue_Kind: case Statement::kDiscard_Kind: - case Statement::kGroup_Kind: case Statement::kNop_Kind: return false; } @@ -236,163 +235,4 @@ bool SectionAndParameterHelper::hasCoordOverrides(const Statement& s, const Vari return false; } -SampleMatrix SectionAndParameterHelper::getMatrix(const Variable& fp) { - SampleMatrix result; - for (const auto& pe : fProgram) { - result.merge(this->getMatrix(pe, fp)); - } - return result; -} - -SampleMatrix SectionAndParameterHelper::getMatrix(const ProgramElement& pe, const Variable& fp) { - if (pe.fKind == ProgramElement::kFunction_Kind) { - return this->getMatrix(*((const FunctionDefinition&) pe).fBody, fp); - } - return SampleMatrix(); -} - -SampleMatrix SectionAndParameterHelper::getMatrix(const Expression& e, const Variable& fp) { - switch (e.fKind) { - case Expression::kFunctionCall_Kind: { - const FunctionCall& fc = (const FunctionCall&) e; - const FunctionDeclaration& f = fc.fFunction; - if (f.fBuiltin && f.fName == "sample" && fc.fArguments.size() >= 2 && - fc.fArguments.back()->fType == *fProgram.fContext->fFloat3x3_Type && - fc.fArguments[0]->fKind == Expression::kVariableReference_Kind && - &((VariableReference&) *fc.fArguments[0]).fVariable == &fp) { - if (fc.fArguments.back()->isConstantOrUniform()) { - return SampleMatrix(SampleMatrix::Kind::kConstantOrUniform, nullptr, - fc.fArguments.back()->description()); - } else { - return SampleMatrix(SampleMatrix::Kind::kVariable); - } - } - SampleMatrix result; - for (const auto& e : fc.fArguments) { - result.merge(this->getMatrix(*e, fp)); - } - return result; - } - case Expression::kConstructor_Kind: { - SampleMatrix result; - const Constructor& c = (const Constructor&) e; - for (const auto& e : c.fArguments) { - result.merge(this->getMatrix(*e, fp)); - } - return result; - } - case Expression::kFieldAccess_Kind: { - return this->getMatrix(*((const FieldAccess&) e).fBase, fp); - } - case Expression::kSwizzle_Kind: - return this->getMatrix(*((const Swizzle&) e).fBase, fp); - case Expression::kBinary_Kind: { - const BinaryExpression& b = (const BinaryExpression&) e; - return this->getMatrix(*b.fLeft, fp).merge(this->getMatrix(*b.fRight, fp)); - } - case Expression::kIndex_Kind: { - const IndexExpression& idx = (const IndexExpression&) e; - return this->getMatrix(*idx.fBase, fp).merge(this->getMatrix(*idx.fIndex, fp)); - } - case Expression::kPrefix_Kind: - return this->getMatrix(*((const PrefixExpression&) e).fOperand, fp); - case Expression::kPostfix_Kind: - return this->getMatrix(*((const PostfixExpression&) e).fOperand, fp); - case Expression::kTernary_Kind: { - const TernaryExpression& t = (const TernaryExpression&) e; - return this->getMatrix(*t.fTest, fp).merge(this->getMatrix(*t.fIfTrue, fp)).merge( - this->getMatrix(*t.fIfFalse, fp)); - } - case Expression::kVariableReference_Kind: - return SampleMatrix(); - case Expression::kBoolLiteral_Kind: - case Expression::kDefined_Kind: - case Expression::kExternalFunctionCall_Kind: - case Expression::kExternalValue_Kind: - case Expression::kFloatLiteral_Kind: - case Expression::kFunctionReference_Kind: - case Expression::kIntLiteral_Kind: - case Expression::kNullLiteral_Kind: - case Expression::kSetting_Kind: - case Expression::kTypeReference_Kind: - return SampleMatrix(); - } - SkASSERT(false); - return SampleMatrix(); -} - -SampleMatrix SectionAndParameterHelper::getMatrix(const Statement& s, const Variable& fp) { - switch (s.fKind) { - case Statement::kBlock_Kind: { - SampleMatrix result; - for (const auto& child : ((const Block&) s).fStatements) { - result.merge(this->getMatrix(*child, fp)); - } - return result; - } - case Statement::kVarDeclaration_Kind: { - const VarDeclaration& var = (const VarDeclaration&) s; - if (var.fValue) { - return this->getMatrix(*var.fValue, fp); - } - return SampleMatrix(); - } - case Statement::kVarDeclarations_Kind: { - const VarDeclarations& decls = *((const VarDeclarationsStatement&) s).fDeclaration; - SampleMatrix result; - for (const auto& stmt : decls.fVars) { - result.merge(this->getMatrix(*stmt, fp)); - } - return result; - } - case Statement::kExpression_Kind: - return this->getMatrix(*((const ExpressionStatement&) s).fExpression, fp); - case Statement::kReturn_Kind: { - const ReturnStatement& r = (const ReturnStatement&) s; - if (r.fExpression) { - return this->getMatrix(*r.fExpression, fp); - } - return SampleMatrix(); - } - case Statement::kIf_Kind: { - const IfStatement& i = (const IfStatement&) s; - return this->getMatrix(*i.fTest, fp).merge(this->getMatrix(*i.fIfTrue, fp)).merge( - (i.fIfFalse ? this->getMatrix(*i.fIfFalse, fp) : SampleMatrix())); - } - case Statement::kFor_Kind: { - const ForStatement& f = (const ForStatement&) s; - return this->getMatrix(*f.fInitializer, fp).merge( - this->getMatrix(*f.fTest, fp).merge( - this->getMatrix(*f.fNext, fp).merge( - this->getMatrix(*f.fStatement, fp)))); - } - case Statement::kWhile_Kind: { - const WhileStatement& w = (const WhileStatement&) s; - return this->getMatrix(*w.fTest, fp).merge(this->getMatrix(*w.fStatement, fp)); - } - case Statement::kDo_Kind: { - const DoStatement& d = (const DoStatement&) s; - return this->getMatrix(*d.fTest, fp).merge(this->getMatrix(*d.fStatement, fp)); - } - case Statement::kSwitch_Kind: { - SampleMatrix result; - const SwitchStatement& sw = (const SwitchStatement&) s; - for (const auto& c : sw.fCases) { - for (const auto& st : c->fStatements) { - result.merge(this->getMatrix(*st, fp)); - } - } - return result.merge(this->getMatrix(*sw.fValue, fp)); - } - case Statement::kBreak_Kind: - case Statement::kContinue_Kind: - case Statement::kDiscard_Kind: - case Statement::kGroup_Kind: - case Statement::kNop_Kind: - return SampleMatrix(); - } - SkASSERT(false); - return SampleMatrix(); -} - } diff --git a/chromium/third_party/skia/src/sksl/SkSLSectionAndParameterHelper.h b/chromium/third_party/skia/src/sksl/SkSLSectionAndParameterHelper.h index d52302aabde..3251024f2ea 100644 --- a/chromium/third_party/skia/src/sksl/SkSLSectionAndParameterHelper.h +++ b/chromium/third_party/skia/src/sksl/SkSLSectionAndParameterHelper.h @@ -9,7 +9,6 @@ #define SKSL_SECTIONANDPARAMETERHELPER #include "src/sksl/SkSLErrorReporter.h" -#include "src/sksl/SkSLSampleMatrix.h" #include "src/sksl/ir/SkSLProgram.h" #include "src/sksl/ir/SkSLSection.h" #include "src/sksl/ir/SkSLVarDeclarations.h" @@ -65,8 +64,6 @@ public: bool hasCoordOverrides(const Variable& fp); - SampleMatrix getMatrix(const Variable& fp); - static bool IsParameter(const Variable& var) { return (var.fModifiers.fFlags & Modifiers::kIn_Flag) && -1 == var.fModifiers.fLayout.fBuiltin; @@ -118,12 +115,6 @@ private: bool hasCoordOverrides(const ProgramElement& p, const Variable& fp); - SampleMatrix getMatrix(const Statement& s, const Variable& fp); - - SampleMatrix getMatrix(const Expression& e, const Variable& fp); - - SampleMatrix getMatrix(const ProgramElement& p, const Variable& fp); - const Program& fProgram; std::vector<const Variable*> fParameters; std::unordered_map<String, std::vector<const Section*>> fSections; diff --git a/chromium/third_party/skia/src/sksl/SkSLUtil.h b/chromium/third_party/skia/src/sksl/SkSLUtil.h index 08f2842b624..552a99b444f 100644 --- a/chromium/third_party/skia/src/sksl/SkSLUtil.h +++ b/chromium/third_party/skia/src/sksl/SkSLUtil.h @@ -144,6 +144,13 @@ public: return true; } + bool canUseDoLoops() const { + // we define this to false in standalone so we don't use do loops while inlining in FP files + // (which would then, being baked in, end up being used even in contexts where do loops are + // not allowed) + return false; + } + const char* shaderDerivativeExtensionString() const { return nullptr; } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLBinaryExpression.h b/chromium/third_party/skia/src/sksl/ir/SkSLBinaryExpression.h index 9fc8683e954..f4a48e94df6 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLBinaryExpression.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLBinaryExpression.h @@ -45,6 +45,10 @@ struct BinaryExpression : public Expression { return fLeft->hasProperty(property) || fRight->hasProperty(property); } + int nodeCount() const override { + return 1 + fLeft->nodeCount() + fRight->nodeCount(); + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new BinaryExpression(fOffset, fLeft->clone(), fOperator, fRight->clone(), fType)); diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLBlock.h b/chromium/third_party/skia/src/sksl/ir/SkSLBlock.h index 8a4449a01c6..b9fdf290724 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLBlock.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLBlock.h @@ -18,10 +18,11 @@ namespace SkSL { */ struct Block : public Statement { Block(int offset, std::vector<std::unique_ptr<Statement>> statements, - const std::shared_ptr<SymbolTable> symbols = nullptr) + const std::shared_ptr<SymbolTable> symbols = nullptr, bool isScope = true) : INHERITED(offset, kBlock_Kind) , fSymbols(std::move(symbols)) - , fStatements(std::move(statements)) {} + , fStatements(std::move(statements)) + , fIsScope(isScope) {} bool isEmpty() const override { for (const auto& s : fStatements) { @@ -32,12 +33,21 @@ struct Block : public Statement { return true; } + int nodeCount() const override { + int result = 1; + for (const auto& s : fStatements) { + result += s->nodeCount(); + } + return result; + } + std::unique_ptr<Statement> clone() const override { std::vector<std::unique_ptr<Statement>> cloned; for (const auto& s : fStatements) { cloned.push_back(s->clone()); } - return std::unique_ptr<Statement>(new Block(fOffset, std::move(cloned), fSymbols)); + return std::unique_ptr<Statement>(new Block(fOffset, std::move(cloned), fSymbols, + fIsScope)); } String description() const override { @@ -54,6 +64,10 @@ struct Block : public Statement { // because destroying statements can modify reference counts in symbols const std::shared_ptr<SymbolTable> fSymbols; std::vector<std::unique_ptr<Statement>> fStatements; + // if isScope is false, this is just a group of statements rather than an actual language-level + // block. This allows us to pass around multiple statements as if they were a single unit, with + // no semantic impact. + bool fIsScope; typedef Statement INHERITED; }; diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLBoolLiteral.h b/chromium/third_party/skia/src/sksl/ir/SkSLBoolLiteral.h index 74f48ad9b30..85dd8c5d0b7 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLBoolLiteral.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLBoolLiteral.h @@ -38,6 +38,10 @@ struct BoolLiteral : public Expression { return fValue == b.fValue; } + int nodeCount() const override { + return 1; + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new BoolLiteral(fOffset, fValue, &fType)); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLBreakStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLBreakStatement.h index ae0c1987e94..daedece915e 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLBreakStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLBreakStatement.h @@ -20,6 +20,10 @@ struct BreakStatement : public Statement { BreakStatement(int offset) : INHERITED(offset, kBreak_Kind) {} + int nodeCount() const override { + return 1; + } + std::unique_ptr<Statement> clone() const override { return std::unique_ptr<Statement>(new BreakStatement(fOffset)); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLConstructor.h b/chromium/third_party/skia/src/sksl/ir/SkSLConstructor.h index 524a6ad643c..cdd6f84a94b 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLConstructor.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLConstructor.h @@ -59,6 +59,14 @@ struct Constructor : public Expression { return false; } + int nodeCount() const override { + int result = 1; + for (const auto& a : fArguments) { + result += a->nodeCount(); + } + return result; + } + std::unique_ptr<Expression> clone() const override { std::vector<std::unique_ptr<Expression>> cloned; for (const auto& arg : fArguments) { diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLContinueStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLContinueStatement.h index ecd9c3f4976..1e01ac8e0e7 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLContinueStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLContinueStatement.h @@ -20,6 +20,10 @@ struct ContinueStatement : public Statement { ContinueStatement(int offset) : INHERITED(offset, kContinue_Kind) {} + int nodeCount() const override { + return 1; + } + std::unique_ptr<Statement> clone() const override { return std::unique_ptr<Statement>(new ContinueStatement(fOffset)); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLDiscardStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLDiscardStatement.h index 40f625c178d..8cc7e3feec2 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLDiscardStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLDiscardStatement.h @@ -20,6 +20,10 @@ struct DiscardStatement : public Statement { DiscardStatement(int offset) : INHERITED(offset, kDiscard_Kind) {} + int nodeCount() const override { + return 1; + } + std::unique_ptr<Statement> clone() const override { return std::unique_ptr<Statement>(new DiscardStatement(fOffset)); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLDoStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLDoStatement.h index 5cab5c8bcd6..474aac7839f 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLDoStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLDoStatement.h @@ -23,6 +23,10 @@ struct DoStatement : public Statement { , fStatement(std::move(statement)) , fTest(std::move(test)) {} + int nodeCount() const override { + return 1 + fStatement->nodeCount() + fTest->nodeCount(); + } + std::unique_ptr<Statement> clone() const override { return std::unique_ptr<Statement>(new DoStatement(fOffset, fStatement->clone(), fTest->clone())); diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLExpressionStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLExpressionStatement.h index 80a8d316c7e..1732bbbcdba 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLExpressionStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLExpressionStatement.h @@ -21,6 +21,10 @@ struct ExpressionStatement : public Statement { : INHERITED(expression->fOffset, kExpression_Kind) , fExpression(std::move(expression)) {} + int nodeCount() const override { + return 1 + fExpression->nodeCount(); + } + std::unique_ptr<Statement> clone() const override { return std::unique_ptr<Statement>(new ExpressionStatement(fExpression->clone())); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLExternalFunctionCall.h b/chromium/third_party/skia/src/sksl/ir/SkSLExternalFunctionCall.h index deb1f4d5cd6..bf70561a5dc 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLExternalFunctionCall.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLExternalFunctionCall.h @@ -36,6 +36,14 @@ struct ExternalFunctionCall : public Expression { return false; } + int nodeCount() const override { + int result = 1; + for (const auto& a : fArguments) { + result += a->nodeCount(); + } + return result; + } + std::unique_ptr<Expression> clone() const override { std::vector<std::unique_ptr<Expression>> cloned; for (const auto& arg : fArguments) { diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLExternalValueReference.h b/chromium/third_party/skia/src/sksl/ir/SkSLExternalValueReference.h index aa0ec181ed5..868c6c9baef 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLExternalValueReference.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLExternalValueReference.h @@ -25,6 +25,10 @@ struct ExternalValueReference : public Expression { return property == Property::kSideEffects; } + int nodeCount() const override { + return 1; + } + String description() const override { return String(fValue->fName); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLFieldAccess.h b/chromium/third_party/skia/src/sksl/ir/SkSLFieldAccess.h index 59f4c166a17..6cba5663404 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLFieldAccess.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLFieldAccess.h @@ -35,6 +35,10 @@ struct FieldAccess : public Expression { return fBase->hasProperty(property); } + int nodeCount() const override { + return 1 + fBase->nodeCount(); + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new FieldAccess(fBase->clone(), fFieldIndex, fOwnerKind)); diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLFloatLiteral.h b/chromium/third_party/skia/src/sksl/ir/SkSLFloatLiteral.h index 79f5dcf7010..9d817719946 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLFloatLiteral.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLFloatLiteral.h @@ -53,6 +53,10 @@ struct FloatLiteral : public Expression { return fValue; } + int nodeCount() const override { + return 1; + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new FloatLiteral(fOffset, fValue, &fType)); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLForStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLForStatement.h index 4906e192a69..29c61bffa7b 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLForStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLForStatement.h @@ -28,16 +28,36 @@ struct ForStatement : public Statement { , fNext(std::move(next)) , fStatement(std::move(statement)) {} + int nodeCount() const override { + int result = 1; + if (fInitializer) { + result += fInitializer->nodeCount(); + } + if (fTest) { + result += fTest->nodeCount(); + } + if (fNext) { + result += fNext->nodeCount(); + } + result += fStatement->nodeCount(); + return result; + } + std::unique_ptr<Statement> clone() const override { - return std::unique_ptr<Statement>(new ForStatement(fOffset, fInitializer->clone(), - fTest->clone(), fNext->clone(), - fStatement->clone(), fSymbols)); + return std::unique_ptr<Statement>(new ForStatement(fOffset, + fInitializer ? fInitializer->clone() : nullptr, + fTest ? fTest->clone() : nullptr, + fNext ? fNext->clone() : nullptr, + fStatement->clone(), + fSymbols)); } String description() const override { String result("for ("); if (fInitializer) { result += fInitializer->description(); + } else { + result += ";"; } result += " "; if (fTest) { diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLFunctionCall.h b/chromium/third_party/skia/src/sksl/ir/SkSLFunctionCall.h index 296aa0b3efe..7f7e7c5f373 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLFunctionCall.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLFunctionCall.h @@ -21,7 +21,13 @@ struct FunctionCall : public Expression { std::vector<std::unique_ptr<Expression>> arguments) : INHERITED(offset, kFunctionCall_Kind, type) , fFunction(std::move(function)) - , fArguments(std::move(arguments)) {} + , fArguments(std::move(arguments)) { + ++fFunction.fCallCount; + } + + ~FunctionCall() override { + --fFunction.fCallCount; + } bool hasProperty(Property property) const override { if (property == Property::kSideEffects && (fFunction.fModifiers.fFlags & @@ -36,6 +42,14 @@ struct FunctionCall : public Expression { return false; } + int nodeCount() const override { + int result = 1; + for (const auto& a : fArguments) { + result += a->nodeCount(); + } + return result; + } + std::unique_ptr<Expression> clone() const override { std::vector<std::unique_ptr<Expression>> cloned; for (const auto& arg : fArguments) { diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLFunctionDeclaration.h b/chromium/third_party/skia/src/sksl/ir/SkSLFunctionDeclaration.h index dffb9a3c981..8436460c24b 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLFunctionDeclaration.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLFunctionDeclaration.h @@ -15,8 +15,12 @@ #include "src/sksl/ir/SkSLType.h" #include "src/sksl/ir/SkSLVariable.h" +#include <atomic> + namespace SkSL { +struct FunctionDefinition; + /** * A function declaration (not a definition -- does not contain a body). */ @@ -24,7 +28,7 @@ struct FunctionDeclaration : public Symbol { FunctionDeclaration(int offset, Modifiers modifiers, StringFragment name, std::vector<const Variable*> parameters, const Type& returnType) : INHERITED(offset, kFunctionDeclaration_Kind, std::move(name)) - , fDefined(false) + , fDefinition(nullptr) , fBuiltin(false) , fModifiers(modifiers) , fParameters(std::move(parameters)) @@ -36,7 +40,7 @@ struct FunctionDeclaration : public Symbol { for (auto p : fParameters) { result += separator; separator = ", "; - result += p->fName; + result += p->fType.displayName(); } result += ")"; return result; @@ -107,11 +111,12 @@ struct FunctionDeclaration : public Symbol { return true; } - mutable bool fDefined; + mutable FunctionDefinition* fDefinition; bool fBuiltin; Modifiers fModifiers; const std::vector<const Variable*> fParameters; const Type& fReturnType; + mutable std::atomic<int> fCallCount = 0; typedef Symbol INHERITED; }; diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLFunctionDefinition.h b/chromium/third_party/skia/src/sksl/ir/SkSLFunctionDefinition.h index 511a0f8c200..4bcadcf57d1 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLFunctionDefinition.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLFunctionDefinition.h @@ -26,6 +26,11 @@ struct FunctionDefinition : public ProgramElement { , fDeclaration(declaration) , fBody(std::move(body)) {} + bool canBeInlined() const { + static const int INLINE_THRESHOLD = 50; // chosen arbitrarily, feel free to adjust + return fBody->nodeCount() < INLINE_THRESHOLD; + } + std::unique_ptr<ProgramElement> clone() const override { return std::unique_ptr<ProgramElement>(new FunctionDefinition(fOffset, fDeclaration, fBody->clone())); diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLIRNode.h b/chromium/third_party/skia/src/sksl/ir/SkSLIRNode.h index ca9ea999989..cace825fe74 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLIRNode.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLIRNode.h @@ -23,6 +23,12 @@ struct IRNode { virtual ~IRNode() {} + virtual int nodeCount() const { + SkASSERT(false); + return 1; + } + + virtual String description() const = 0; // character offset of this element within the program being compiled, for error reporting diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLIfStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLIfStatement.h index 5d0a22b647a..6af6740b0f2 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLIfStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLIfStatement.h @@ -25,6 +25,11 @@ struct IfStatement : public Statement { , fIfTrue(std::move(ifTrue)) , fIfFalse(std::move(ifFalse)) {} + int nodeCount() const override { + return 1 + fTest->nodeCount() + fIfTrue->nodeCount() + + (fIfFalse ? fIfFalse->nodeCount() : 0); + } + std::unique_ptr<Statement> clone() const override { return std::unique_ptr<Statement>(new IfStatement(fOffset, fIsStatic, fTest->clone(), fIfTrue->clone(), fIfFalse ? fIfFalse->clone() : nullptr)); diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLIndexExpression.h b/chromium/third_party/skia/src/sksl/ir/SkSLIndexExpression.h index 2b3a3a93d5b..5e7a011937f 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLIndexExpression.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLIndexExpression.h @@ -33,14 +33,6 @@ static const Type& index_type(const Context& context, const Type& type) { case 4: return *context.fHalf4_Type; default: SkASSERT(false); } - } else { - SkASSERT(type.componentType() == *context.fDouble_Type); - switch (type.rows()) { - case 2: return *context.fDouble2_Type; - case 3: return *context.fDouble3_Type; - case 4: return *context.fDouble4_Type; - default: SkASSERT(false); - } } } return type.componentType(); @@ -62,6 +54,10 @@ struct IndexExpression : public Expression { return fBase->hasProperty(property) || fIndex->hasProperty(property); } + int nodeCount() const override { + return 1 + fBase->nodeCount() + fIndex->nodeCount(); + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new IndexExpression(fBase->clone(), fIndex->clone(), &fType)); diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLIntLiteral.h b/chromium/third_party/skia/src/sksl/ir/SkSLIntLiteral.h index 6c686e135ba..4977fbf0b8a 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLIntLiteral.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLIntLiteral.h @@ -56,6 +56,10 @@ struct IntLiteral : public Expression { return fValue; } + int nodeCount() const override { + return 1; + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new IntLiteral(fOffset, fValue, &fType)); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLNop.h b/chromium/third_party/skia/src/sksl/ir/SkSLNop.h index 2ead371f876..787060d8b45 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLNop.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLNop.h @@ -28,6 +28,10 @@ struct Nop : public Statement { return String(";"); } + int nodeCount() const override { + return 0; + } + std::unique_ptr<Statement> clone() const override { return std::unique_ptr<Statement>(new Nop()); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLNullLiteral.h b/chromium/third_party/skia/src/sksl/ir/SkSLNullLiteral.h index d04fc5cb209..0d04b77e227 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLNullLiteral.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLNullLiteral.h @@ -39,6 +39,10 @@ struct NullLiteral : public Expression { return true; } + int nodeCount() const override { + return 1; + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new NullLiteral(fOffset, fType)); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLPostfixExpression.h b/chromium/third_party/skia/src/sksl/ir/SkSLPostfixExpression.h index d95f687e378..c6f89eb2d61 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLPostfixExpression.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLPostfixExpression.h @@ -30,6 +30,10 @@ struct PostfixExpression : public Expression { return fOperand->hasProperty(property); } + int nodeCount() const override { + return 1 + fOperand->nodeCount(); + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new PostfixExpression(fOperand->clone(), fOperator)); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLPrefixExpression.h b/chromium/third_party/skia/src/sksl/ir/SkSLPrefixExpression.h index 76f144b7fb8..ab0363ec661 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLPrefixExpression.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLPrefixExpression.h @@ -64,6 +64,10 @@ struct PrefixExpression : public Expression { return -fOperand->getMatComponent(col, row); } + int nodeCount() const override { + return 1 + fOperand->nodeCount(); + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new PrefixExpression(fOperator, fOperand->clone())); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLProgram.h b/chromium/third_party/skia/src/sksl/ir/SkSLProgram.h index c7694b5f917..cf16d1fd460 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLProgram.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLProgram.h @@ -53,7 +53,7 @@ struct Program { Value(float f) : fKind(kFloat_Kind) - , fValue(f) {} + , fValueF(f) {} std::unique_ptr<Expression> literal(const Context& context, int offset) const { switch (fKind) { @@ -67,8 +67,8 @@ struct Program { fValue)); case Program::Settings::Value::kFloat_Kind: return std::unique_ptr<Expression>(new FloatLiteral(context, - offset, - fValue)); + offset, + fValueF)); default: SkASSERT(false); return nullptr; @@ -81,7 +81,10 @@ struct Program { kFloat_Kind, } fKind; - int fValue; + union { + int fValue; // for kBool_Kind and kInt_Kind + float fValueF; // for kFloat_Kind + }; }; #if defined(SKSL_STANDALONE) || !SK_SUPPORT_GPU @@ -92,6 +95,9 @@ struct Program { // if false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the y coordinate // must be flipped. bool fFlipY = false; + // if false, sk_FragCoord is exactly the same as gl_FragCoord. If true, the w coordinate + // must be inversed. + bool fInverseW = false; // If true the destination fragment color is read sk_FragColor. It must be declared inout. bool fFragColorIsInOut = false; // if true, Setting objects (e.g. sk_Caps.fbFetchSupport) should be replaced with their @@ -108,6 +114,9 @@ struct Program { // binding and set number of the uniform buffer. int fRTHeightBinding = -1; int fRTHeightSet = -1; + // If true, remove any uncalled functions other than main(). Note that a function which + // starts out being used may end up being uncalled after optimization. + bool fRemoveDeadFunctions = true; std::unordered_map<String, Value> fArgs; }; diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLReturnStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLReturnStatement.h index e61fa36c742..82b46781061 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLReturnStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLReturnStatement.h @@ -24,6 +24,10 @@ struct ReturnStatement : public Statement { : INHERITED(expression->fOffset, kReturn_Kind) , fExpression(std::move(expression)) {} + int nodeCount() const override { + return 1 + fExpression->nodeCount(); + } + std::unique_ptr<Statement> clone() const override { if (fExpression) { return std::unique_ptr<Statement>(new ReturnStatement(fExpression->clone())); diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLSetting.h b/chromium/third_party/skia/src/sksl/ir/SkSLSetting.h index a47b42be914..9a69802b575 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLSetting.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLSetting.h @@ -28,6 +28,10 @@ struct Setting : public Expression { std::unique_ptr<Expression> constantPropagate(const IRGenerator& irGenerator, const DefinitionMap& definitions) override; + int nodeCount() const override { + return 1; + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new Setting(fOffset, fName, fValue->clone())); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLStatement.h index ed8d33b1422..2260cdd5a4d 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLStatement.h @@ -25,7 +25,6 @@ struct Statement : public IRNode { kDo_Kind, kExpression_Kind, kFor_Kind, - kGroup_Kind, kIf_Kind, kNop_Kind, kReturn_Kind, diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLSwitchCase.h b/chromium/third_party/skia/src/sksl/ir/SkSLSwitchCase.h index b1ddb012ec4..dcfe9564268 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLSwitchCase.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLSwitchCase.h @@ -23,6 +23,17 @@ struct SwitchCase : public Statement { , fValue(std::move(value)) , fStatements(std::move(statements)) {} + int nodeCount() const override { + int result = 1; + if (fValue) { + result += fValue->nodeCount(); + } + for (const auto& s : fStatements) { + result += s->nodeCount(); + } + return result; + } + std::unique_ptr<Statement> clone() const override { std::vector<std::unique_ptr<Statement>> cloned; for (const auto& s : fStatements) { diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLSwitchStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLSwitchStatement.h index 0777c5c5c61..a85420a6959 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLSwitchStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLSwitchStatement.h @@ -28,6 +28,14 @@ struct SwitchStatement : public Statement { , fSymbols(std::move(symbols)) , fCases(std::move(cases)) {} + int nodeCount() const override { + int result = 1 + fValue->nodeCount(); + for (const auto& c : fCases) { + result += c->nodeCount(); + } + return result; + } + std::unique_ptr<Statement> clone() const override { std::vector<std::unique_ptr<SwitchCase>> cloned; for (const auto& s : fCases) { diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLSwizzle.h b/chromium/third_party/skia/src/sksl/ir/SkSLSwizzle.h index 3428f287fa2..040af8491aa 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLSwizzle.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLSwizzle.h @@ -44,12 +44,6 @@ static const Type& get_type(const Context& context, Expression& value, size_t co case 3: return *context.fHalf3_Type; case 4: return *context.fHalf4_Type; } - } else if (base == *context.fDouble_Type) { - switch (count) { - case 2: return *context.fDouble2_Type; - case 3: return *context.fDouble3_Type; - case 4: return *context.fDouble4_Type; - } } else if (base == *context.fInt_Type) { switch (count) { case 2: return *context.fInt2_Type; @@ -136,6 +130,10 @@ struct Swizzle : public Expression { return fBase->hasProperty(property); } + int nodeCount() const override { + return 1 + fBase->nodeCount(); + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new Swizzle(fType, fBase->clone(), fComponents)); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLSymbol.h b/chromium/third_party/skia/src/sksl/ir/SkSLSymbol.h index 4ee4d3d90dd..df606b88c47 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLSymbol.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLSymbol.h @@ -30,7 +30,7 @@ struct Symbol : public IRNode { , fKind(kind) , fName(name) {} - virtual ~Symbol() {} + virtual ~Symbol() override {} Kind fKind; StringFragment fName; diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLSymbolTable.cpp b/chromium/third_party/skia/src/sksl/ir/SkSLSymbolTable.cpp index ed2cb4d565b..b0a2a56e08d 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLSymbolTable.cpp +++ b/chromium/third_party/skia/src/sksl/ir/SkSLSymbolTable.cpp @@ -72,6 +72,12 @@ IRNode* SymbolTable::takeOwnership(std::unique_ptr<IRNode> n) { return result; } +String* SymbolTable::takeOwnership(std::unique_ptr<String> n) { + String* result = n.get(); + fOwnedStrings.push_back(std::move(n)); + return result; +} + void SymbolTable::add(StringFragment name, std::unique_ptr<Symbol> symbol) { this->addWithoutOwnership(name, symbol.get()); this->takeOwnership(std::move(symbol)); @@ -114,9 +120,7 @@ void SymbolTable::markAllFunctionsBuiltin() { break; case Symbol::kUnresolvedFunction_Kind: for (auto& f : ((UnresolvedFunction&) *pair.second).fFunctions) { - if (!((FunctionDeclaration*)f)->fDefined) { - ((FunctionDeclaration*)f)->fBuiltin = true; - } + ((FunctionDeclaration*)f)->fBuiltin = true; } break; default: diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLSymbolTable.h b/chromium/third_party/skia/src/sksl/ir/SkSLSymbolTable.h index 6969ba5e08c..a3f89e2288f 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLSymbolTable.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLSymbolTable.h @@ -41,6 +41,8 @@ public: IRNode* takeOwnership(std::unique_ptr<IRNode> n); + String* takeOwnership(std::unique_ptr<String> n); + void markAllFunctionsBuiltin(); std::unordered_map<StringFragment, const Symbol*>::iterator begin(); @@ -56,6 +58,8 @@ private: std::vector<std::unique_ptr<IRNode>> fOwnedNodes; + std::vector<std::unique_ptr<String>> fOwnedStrings; + std::unordered_map<StringFragment, const Symbol*> fSymbols; ErrorReporter& fErrorReporter; diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLTernaryExpression.h b/chromium/third_party/skia/src/sksl/ir/SkSLTernaryExpression.h index 80dcb8fada6..cb4c0047209 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLTernaryExpression.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLTernaryExpression.h @@ -36,6 +36,10 @@ struct TernaryExpression : public Expression { fIfFalse->isConstantOrUniform(); } + int nodeCount() const override { + return 1 + fTest->nodeCount() + fIfTrue->nodeCount() + fIfFalse->nodeCount(); + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new TernaryExpression(fOffset, fTest->clone(), fIfTrue->clone(), diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLType.cpp b/chromium/third_party/skia/src/sksl/ir/SkSLType.cpp index cd18e8ed910..edff101dc9d 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLType.cpp +++ b/chromium/third_party/skia/src/sksl/ir/SkSLType.cpp @@ -116,38 +116,6 @@ const Type& Type::toCompound(const Context& context, int columns, int rows) cons } default: ABORT("unsupported row count (%d)", rows); } - } else if (*this == *context.fDouble_Type) { - switch (rows) { - case 1: - switch (columns) { - case 2: return *context.fDouble2_Type; - case 3: return *context.fDouble3_Type; - case 4: return *context.fDouble4_Type; - default: ABORT("unsupported vector column count (%d)", columns); - } - case 2: - switch (columns) { - case 2: return *context.fDouble2x2_Type; - case 3: return *context.fDouble3x2_Type; - case 4: return *context.fDouble4x2_Type; - default: ABORT("unsupported matrix column count (%d)", columns); - } - case 3: - switch (columns) { - case 2: return *context.fDouble2x3_Type; - case 3: return *context.fDouble3x3_Type; - case 4: return *context.fDouble4x3_Type; - default: ABORT("unsupported matrix column count (%d)", columns); - } - case 4: - switch (columns) { - case 2: return *context.fDouble2x4_Type; - case 3: return *context.fDouble3x4_Type; - case 4: return *context.fDouble4x4_Type; - default: ABORT("unsupported matrix column count (%d)", columns); - } - default: ABORT("unsupported row count (%d)", rows); - } } else if (*this == *context.fInt_Type || *this == *context.fIntLiteral_Type) { switch (rows) { case 1: diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLType.h b/chromium/third_party/skia/src/sksl/ir/SkSLType.h index 37303cbee9c..e8c6a653cf4 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLType.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLType.h @@ -269,7 +269,7 @@ public: } /** - * Returns true if this is a floating-point scalar type (float, half, or double). + * Returns true if this is a floating-point scalar type (float or half). */ bool isFloat() const { return fNumberKind == kFloat_NumberKind; @@ -297,7 +297,7 @@ public: } /** - * Returns the "priority" of a number type, in order of double > float > half > int > short. + * Returns the "priority" of a number type, in order of float > half > int > short. * When operating on two number types, the result is the higher-priority type. */ int priority() const { diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLVarDeclarations.h b/chromium/third_party/skia/src/sksl/ir/SkSLVarDeclarations.h index 82dbd8616d8..86aafdb3db3 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLVarDeclarations.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLVarDeclarations.h @@ -29,6 +29,19 @@ struct VarDeclaration : public Statement { , fSizes(std::move(sizes)) , fValue(std::move(value)) {} + int nodeCount() const override { + int result = 1; + for (const auto& s : fSizes) { + if (s) { + result += s->nodeCount(); + } + } + if (fValue) { + result += fValue->nodeCount(); + } + return result; + } + std::unique_ptr<Statement> clone() const override { std::vector<std::unique_ptr<Expression>> sizesClone; for (const auto& s : fSizes) { @@ -77,6 +90,14 @@ struct VarDeclarations : public ProgramElement { } } + int nodeCount() const override { + int result = 1; + for (const auto& v : fVars) { + result += v->nodeCount(); + } + return result; + } + std::unique_ptr<ProgramElement> clone() const override { std::vector<std::unique_ptr<VarDeclaration>> cloned; for (const auto& v : fVars) { @@ -91,8 +112,15 @@ struct VarDeclarations : public ProgramElement { if (!fVars.size()) { return String(); } - String result = ((VarDeclaration&) *fVars[0]).fVar->fModifiers.description() + - fBaseType.description() + " "; + String result; + for (const auto& var : fVars) { + if (var->fKind != Statement::kNop_Kind) { + SkASSERT(var->fKind == Statement::kVarDeclaration_Kind); + result = ((const VarDeclaration&) *var).fVar->fModifiers.description(); + break; + } + } + result += fBaseType.description() + " "; String separator; for (const auto& var : fVars) { result += separator; diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLVarDeclarationsStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLVarDeclarationsStatement.h index 465b6919361..eb7880f310c 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLVarDeclarationsStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLVarDeclarationsStatement.h @@ -30,6 +30,10 @@ struct VarDeclarationsStatement : public Statement { return true; } + int nodeCount() const override { + return 1 + fDeclaration->nodeCount(); + } + std::unique_ptr<Statement> clone() const override { std::unique_ptr<VarDeclarations> cloned((VarDeclarations*) fDeclaration->clone().release()); return std::unique_ptr<Statement>(new VarDeclarationsStatement(std::move(cloned))); diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLVariableReference.h b/chromium/third_party/skia/src/sksl/ir/SkSLVariableReference.h index 5d962b9ff25..c6751441ddb 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLVariableReference.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLVariableReference.h @@ -62,6 +62,10 @@ struct VariableReference : public Expression { return (fVariable.fModifiers.fFlags & Modifiers::kUniform_Flag) != 0; } + int nodeCount() const override { + return 1; + } + std::unique_ptr<Expression> clone() const override { return std::unique_ptr<Expression>(new VariableReference(fOffset, fVariable, fRefKind)); } diff --git a/chromium/third_party/skia/src/sksl/ir/SkSLWhileStatement.h b/chromium/third_party/skia/src/sksl/ir/SkSLWhileStatement.h index 8e311a090a4..0782a018994 100644 --- a/chromium/third_party/skia/src/sksl/ir/SkSLWhileStatement.h +++ b/chromium/third_party/skia/src/sksl/ir/SkSLWhileStatement.h @@ -23,6 +23,10 @@ struct WhileStatement : public Statement { , fTest(std::move(test)) , fStatement(std::move(statement)) {} + int nodeCount() const override { + return 1 + fTest->nodeCount() + fStatement->nodeCount(); + } + std::unique_ptr<Statement> clone() const override { return std::unique_ptr<Statement>(new WhileStatement(fOffset, fTest->clone(), fStatement->clone())); diff --git a/chromium/third_party/skia/src/sksl/lex/RegexParser.cpp b/chromium/third_party/skia/src/sksl/lex/RegexParser.cpp index 9b5445e1a3d..be7d09a1063 100644 --- a/chromium/third_party/skia/src/sksl/lex/RegexParser.cpp +++ b/chromium/third_party/skia/src/sksl/lex/RegexParser.cpp @@ -63,8 +63,8 @@ void RegexParser::sequence() { this->quantifiedTerm(); for (;;) { switch (this->peek()) { - case END: // fall through - case '|': // fall through + case END: [[fallthrough]]; + case '|': [[fallthrough]]; case ')': return; default: this->sequence(); diff --git a/chromium/third_party/skia/src/sksl/sksl_blend.inc b/chromium/third_party/skia/src/sksl/sksl_blend.inc index 9094aedfb0d..ab6dcb8922d 100644 --- a/chromium/third_party/skia/src/sksl/sksl_blend.inc +++ b/chromium/third_party/skia/src/sksl/sksl_blend.inc @@ -69,8 +69,9 @@ half4 blend_lighten(half4 src, half4 dst) { half _guarded_divide(half n, half d) { @if (sk_Caps.mustGuardDivisionEvenAfterExplicitZeroCheck) { return n/(d + 0.00000001); + } else { + return n/d; } - return n/d; } half _color_dodge_component(half sc, half sa, half dc, half da) { @@ -298,4 +299,8 @@ half4 blend(SkBlendMode mode, half4 src, half4 dst) { } return half4(0); // Avoids "'blend' can exit without returning a value." } + +// The max() guards against division by zero when the incoming color is transparent black +half4 unpremul(half4 color) { return half4(color.rgb / max(color.a, 0.0001), color.a); } +float4 unpremul_float(float4 color) { return float4(color.rgb / max(color.a, 0.0001), color.a); } )SKSL" diff --git a/chromium/third_party/skia/src/sksl/sksl_enums.inc b/chromium/third_party/skia/src/sksl/sksl_enums.inc index eb60b3b0c5b..b29daf93da5 100644 --- a/chromium/third_party/skia/src/sksl/sksl_enums.inc +++ b/chromium/third_party/skia/src/sksl/sksl_enums.inc @@ -13,17 +13,15 @@ R"(/* /** * We have coverage effects that clip rendering to the edge of some geometric primitive. * This enum specifies how that clipping is performed. Not all factories that take a - * GrProcessorEdgeType will succeed with all values and it is up to the caller to check for - * a NULL return. + * GrProcessorEdgeType will succeed with all values and it is up to the caller to verify success. */ enum class GrClipEdgeType { kFillBW, kFillAA, kInverseFillBW, kInverseFillAA, - kHairlineAA, - kLast = kHairlineAA + kLast = kInverseFillAA }; enum class PMConversion { diff --git a/chromium/third_party/skia/src/sksl/sksl_gpu.inc b/chromium/third_party/skia/src/sksl/sksl_gpu.inc index 1bacef0d091..6122e48dd22 100644 --- a/chromium/third_party/skia/src/sksl/sksl_gpu.inc +++ b/chromium/third_party/skia/src/sksl/sksl_gpu.inc @@ -104,15 +104,12 @@ $genType smoothstep(float edge0, float edge1, $genType x); $genHType smoothstep($genHType edge0, $genHType edge1, $genHType x); $genHType smoothstep(half edge0, half edge1, $genHType x); $genBType isnan($genType x); -$genBType isnan($genDType x); $genBType isinf($genType x); -$genBType isinf($genDType x); $genIType floatBitsToInt($genType value); $genType intBitsTofloat($genIType value); $genType uintBitsTofloat($genUType value); $genType fma($genType a, $genType b, $genType c); $genHType fma($genHType a, $genHType b, $genHType c); -$genDType fma($genDType a, $genDType b, $genDType c); sk_has_side_effects $genType frexp($genType x, out $genIType exp); $genType ldexp($genType x, in $genIType exp); uint packUnorm2x16(float2 v); @@ -123,34 +120,25 @@ float2 unpackUnorm2x16(uint p); float2 unpackSnorm2x16(uint p); float4 unpackUnorm4x8(uint p); float4 unpackSnorm4x8(uint p); -uint2 unpackDouble2x32(double v); uint packHalf2x16(float2 v); float2 unpackHalf2x16(uint v); float length($genType x); half length($genHType x); -double length($genDType x); float distance($genType p0, $genType p1); half distance($genHType p0, $genHType p1); -double distance($genDType p0, $genDType p1); float dot($genType x, $genType y); half dot($genHType x, $genHType y); -double dot($genDType x, $genDType y); float3 cross(float3 x, float3 y); half3 cross(half3 x, half3 y); -double3 cross(double3 x, double3 y); $genType normalize($genType x); $genHType normalize($genHType x); -$genDType normalize($genDType x); float4 ftransform(); $genType faceforward($genType N, $genType I, $genType Nref); $genHType faceforward($genHType N, $genHType I, $genHType Nref); -$genDType faceforward($genDType N, $genDType I, $genDType Nref); $genType reflect($genType I, $genType N); $genHType reflect($genHType I, $genHType N); -$genDType reflect($genDType I, $genDType N); $genType refract($genType I, $genType N, float eta); $genHType refract($genHType I, $genHType N, float eta); -$genDType refract($genDType I, $genDType N, float eta); $mat matrixCompMult($mat x, $mat y); float2x2 outerProduct(float2 c, float2 r); float3x3 outerProduct(float3 c, float3 r); @@ -202,35 +190,30 @@ half3x3 inverse(half3x3 m); half4x4 inverse(half4x4 m); $bvec lessThan($vec x, $vec y); $bvec lessThan($hvec x, $hvec y); -$bvec lessThan($dvec x, $dvec y); $bvec lessThan($ivec x, $ivec y); $bvec lessThan($svec x, $svec y); $bvec lessThan($usvec x, $usvec y); $bvec lessThan($uvec x, $uvec y); $bvec lessThanEqual($vec x, $vec y); $bvec lessThanEqual($hvec x, $hvec y); -$bvec lessThanEqual($dvec x, $dvec y); $bvec lessThanEqual($ivec x, $ivec y); $bvec lessThanEqual($uvec x, $uvec y); $bvec lessThanEqual($svec x, $svec y); $bvec lessThanEqual($usvec x, $usvec y); $bvec greaterThan($vec x, $vec y); $bvec greaterThan($hvec x, $hvec y); -$bvec greaterThan($dvec x, $dvec y); $bvec greaterThan($ivec x, $ivec y); $bvec greaterThan($uvec x, $uvec y); $bvec greaterThan($svec x, $svec y); $bvec greaterThan($usvec x, $usvec y); $bvec greaterThanEqual($vec x, $vec y); $bvec greaterThanEqual($hvec x, $hvec y); -$bvec greaterThanEqual($dvec x, $dvec y); $bvec greaterThanEqual($ivec x, $ivec y); $bvec greaterThanEqual($uvec x, $uvec y); $bvec greaterThanEqual($svec x, $svec y); $bvec greaterThanEqual($usvec x, $usvec y); $bvec equal($vec x, $vec y); $bvec equal($hvec x, $hvec y); -$bvec equal($dvec x, $dvec y); $bvec equal($ivec x, $ivec y); $bvec equal($uvec x, $uvec y); $bvec equal($svec x, $svec y); @@ -238,7 +221,6 @@ $bvec equal($usvec x, $usvec y); $bvec equal($bvec x, $bvec y); $bvec notEqual($vec x, $vec y); $bvec notEqual($hvec x, $hvec y); -$bvec notEqual($dvec x, $dvec y); $bvec notEqual($ivec x, $ivec y); $bvec notEqual($uvec x, $uvec y); $bvec notEqual($svec x, $svec y); diff --git a/chromium/third_party/skia/src/sksl/sksl_interp.inc b/chromium/third_party/skia/src/sksl/sksl_interp.inc index 894df0883df..c6644ca39d9 100644 --- a/chromium/third_party/skia/src/sksl/sksl_interp.inc +++ b/chromium/third_party/skia/src/sksl/sksl_interp.inc @@ -16,6 +16,8 @@ half3x3 inverse(half3x3 m); half4x4 inverse(half4x4 m); float length($genType x); half length($genHType x); +$genType normalize($genType x); +$genHType normalize($genHType x); $genType pow($genType x, $genType y); $genHType pow($genHType x, $genHType y); $genType sin($genType x); @@ -101,10 +103,6 @@ float distance(float2 a, float2 b) { return length(a - b); } float distance(float3 a, float3 b) { return length(a - b); } float distance(float4 a, float4 b) { return length(a - b); } -float2 normalize(float2 v) { return v / length(v); } -float3 normalize(float3 v) { return v / length(v); } -float4 normalize(float4 v) { return v / length(v); } - float3 cross(float3 a, float3 b) { return float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, diff --git a/chromium/third_party/skia/src/sksl/sksl_pipeline.inc b/chromium/third_party/skia/src/sksl/sksl_pipeline.inc index 99e4e303f5a..2f319513c0b 100644 --- a/chromium/third_party/skia/src/sksl/sksl_pipeline.inc +++ b/chromium/third_party/skia/src/sksl/sksl_pipeline.inc @@ -1,4 +1,5 @@ STRINGIFY( + layout(builtin=15) float4 sk_FragCoord; half4 sample(fragmentProcessor fp, float2 coords); half4 sample(fragmentProcessor fp, float3x3 transform); ) diff --git a/chromium/third_party/skia/src/svg/SkSVGDevice.cpp b/chromium/third_party/skia/src/svg/SkSVGDevice.cpp index a6cb77d1911..3fbe4122ea5 100644 --- a/chromium/third_party/skia/src/svg/SkSVGDevice.cpp +++ b/chromium/third_party/skia/src/svg/SkSVGDevice.cpp @@ -760,6 +760,9 @@ void SkSVGDevice::syncClipStack(const SkClipStack& cs) { path.addAttribute("clip-rule", "evenodd"); } } break; + case SkClipStack::Element::DeviceSpaceType::kShader: + // TODO: handle shader clipping, perhaps rasterize and apply as a mask image? + break; } return cid; diff --git a/chromium/third_party/skia/src/utils/SkCamera.cpp b/chromium/third_party/skia/src/utils/SkCamera.cpp index 63d1c804fa4..45e216edb27 100644 --- a/chromium/third_party/skia/src/utils/SkCamera.cpp +++ b/chromium/third_party/skia/src/utils/SkCamera.cpp @@ -19,48 +19,6 @@ static SkScalar SkScalarDotDiv(int count, const SkScalar a[], int step_a, return prod / denom; } -static SkScalar SkScalarDot(int count, const SkScalar a[], int step_a, - const SkScalar b[], int step_b) { - SkScalar prod = 0; - for (int i = 0; i < count; i++) { - prod += a[0] * b[0]; - a += step_a; - b += step_b; - } - return prod; -} - -/////////////////////////////////////////////////////////////////////////////// - -SkScalar SkPoint3D::normalize(SkUnit3D* unit) const { - SkScalar mag = SkScalarSqrt(fX*fX + fY*fY + fZ*fZ); - if (mag) { - SkScalar scale = SkScalarInvert(mag); - unit->fX = fX * scale; - unit->fY = fY * scale; - unit->fZ = fZ * scale; - } else { - unit->fX = unit->fY = unit->fZ = 0; - } - return mag; -} - -SkScalar SkUnit3D::Dot(const SkUnit3D& a, const SkUnit3D& b) { - return a.fX * b.fX + a.fY * b.fY + a.fZ * b.fZ; -} - -void SkUnit3D::Cross(const SkUnit3D& a, const SkUnit3D& b, SkUnit3D* cross) { - SkASSERT(cross); - - // use x,y,z, in case &a == cross or &b == cross - - SkScalar x = a.fY * b.fZ - a.fZ * b.fY; - SkScalar y = a.fZ * b.fX - a.fX * b.fY; - SkScalar z = a.fX * b.fY - a.fY * b.fX; - - cross->set(x, y, z); -} - /////////////////////////////////////////////////////////////////////////////// SkPatch3D::SkPatch3D() { @@ -68,141 +26,41 @@ SkPatch3D::SkPatch3D() { } void SkPatch3D::reset() { - fOrigin.set(0, 0, 0); - fU.set(SK_Scalar1, 0, 0); - fV.set(0, -SK_Scalar1, 0); + fOrigin = {0, 0, 0}; + fU = {SK_Scalar1, 0, 0}; + fV = {0, -SK_Scalar1, 0}; } -void SkPatch3D::transform(const SkMatrix3D& m, SkPatch3D* dst) const { +void SkPatch3D::transform(const SkM44& m, SkPatch3D* dst) const { if (dst == nullptr) { dst = (SkPatch3D*)this; } - m.mapVector(fU, &dst->fU); - m.mapVector(fV, &dst->fV); - m.mapPoint(fOrigin, &dst->fOrigin); + dst->fU = m * fU; + dst->fV = m * fV; + auto [x,y,z,_] = m.map(fOrigin.x, fOrigin.y, fOrigin.z, 1); + dst->fOrigin = {x, y, z}; } SkScalar SkPatch3D::dotWith(SkScalar dx, SkScalar dy, SkScalar dz) const { - SkScalar cx = fU.fY * fV.fZ - fU.fZ * fV.fY; - SkScalar cy = fU.fZ * fV.fX - fU.fX * fV.fY; - SkScalar cz = fU.fX * fV.fY - fU.fY * fV.fX; + SkScalar cx = fU.y * fV.z - fU.z * fV.y; + SkScalar cy = fU.z * fV.x - fU.x * fV.y; + SkScalar cz = fU.x * fV.y - fU.y * fV.x; return cx * dx + cy * dy + cz * dz; } /////////////////////////////////////////////////////////////////////////////// -void SkMatrix3D::reset() { - memset(fMat, 0, sizeof(fMat)); - fMat[0][0] = fMat[1][1] = fMat[2][2] = SK_Scalar1; -} - -void SkMatrix3D::setTranslate(SkScalar x, SkScalar y, SkScalar z) { - memset(fMat, 0, sizeof(fMat)); - fMat[0][0] = x; - fMat[1][1] = y; - fMat[2][2] = z; -} - -void SkMatrix3D::setRotateX(SkScalar degX) { - SkScalar r = SkDegreesToRadians(degX), - s = SkScalarSin(r), - c = SkScalarCos(r); - this->setRow(0, SK_Scalar1, 0, 0); - this->setRow(1, 0, c, -s); - this->setRow(2, 0, s, c); -} - -void SkMatrix3D::setRotateY(SkScalar degY) { - SkScalar r = SkDegreesToRadians(degY), - s = SkScalarSin(r), - c = SkScalarCos(r); - this->setRow(0, c, 0, -s); - this->setRow(1, 0, SK_Scalar1, 0); - this->setRow(2, s, 0, c); -} - -void SkMatrix3D::setRotateZ(SkScalar degZ) { - SkScalar r = SkDegreesToRadians(degZ), - s = SkScalarSin(r), - c = SkScalarCos(r); - this->setRow(0, c, -s, 0); - this->setRow(1, s, c, 0); - this->setRow(2, 0, 0, SK_Scalar1); -} - -void SkMatrix3D::preTranslate(SkScalar x, SkScalar y, SkScalar z) { - SkScalar col[3] = { x, y, z}; - - for (int i = 0; i < 3; i++) { - fMat[i][3] += SkScalarDot(3, &fMat[i][0], 1, col, 1); - } -} - -void SkMatrix3D::preRotateX(SkScalar degX) { - SkMatrix3D m; - m.setRotateX(degX); - this->setConcat(*this, m); -} - -void SkMatrix3D::preRotateY(SkScalar degY) { - SkMatrix3D m; - m.setRotateY(degY); - this->setConcat(*this, m); -} - -void SkMatrix3D::preRotateZ(SkScalar degZ) { - SkMatrix3D m; - m.setRotateZ(degZ); - this->setConcat(*this, m); -} - -void SkMatrix3D::setConcat(const SkMatrix3D& a, const SkMatrix3D& b) { - SkMatrix3D tmp; - SkMatrix3D* c = this; - - if (this == &a || this == &b) { - c = &tmp; - } - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - c->fMat[i][j] = SkScalarDot(3, &a.fMat[i][0], 1, &b.fMat[0][j], 4); - } - c->fMat[i][3] = SkScalarDot(3, &a.fMat[i][0], 1, - &b.fMat[0][3], 4) + a.fMat[i][3]; - } - - if (c == &tmp) { - *this = tmp; - } -} - -void SkMatrix3D::mapPoint(const SkPoint3D& src, SkPoint3D* dst) const { - SkScalar x = SkScalarDot(3, &fMat[0][0], 1, &src.fX, 1) + fMat[0][3]; - SkScalar y = SkScalarDot(3, &fMat[1][0], 1, &src.fX, 1) + fMat[1][3]; - SkScalar z = SkScalarDot(3, &fMat[2][0], 1, &src.fX, 1) + fMat[2][3]; - dst->set(x, y, z); -} - -void SkMatrix3D::mapVector(const SkVector3D& src, SkVector3D* dst) const { - SkScalar x = SkScalarDot(3, &fMat[0][0], 1, &src.fX, 1); - SkScalar y = SkScalarDot(3, &fMat[1][0], 1, &src.fX, 1); - SkScalar z = SkScalarDot(3, &fMat[2][0], 1, &src.fX, 1); - dst->set(x, y, z); -} - -/////////////////////////////////////////////////////////////////////////////// - SkCamera3D::SkCamera3D() { this->reset(); } void SkCamera3D::reset() { - fLocation.set(0, 0, -SkIntToScalar(576)); // 8 inches backward - fAxis.set(0, 0, SK_Scalar1); // forward - fZenith.set(0, -SK_Scalar1, 0); // up + fLocation = {0, 0, -SkIntToScalar(576)}; // 8 inches backward + fAxis = {0, 0, SK_Scalar1}; // forward + fZenith = {0, -SK_Scalar1, 0}; // up - fObserver.set(0, 0, fLocation.fZ); + fObserver = {0, 0, fLocation.z}; fNeedToUpdate = true; } @@ -212,28 +70,19 @@ void SkCamera3D::update() { } void SkCamera3D::doUpdate() const { - SkUnit3D axis, zenith, cross; + SkV3 axis, zenith, cross; // construct a orthonormal basis of cross (x), zenith (y), and axis (z) - fAxis.normalize(&axis); + axis = fAxis.normalize(); - { - SkScalar dot = SkUnit3D::Dot(SkUnit3D{fZenith.fX, fZenith.fY, fZenith.fZ}, axis); + zenith = fZenith - (axis * fZenith) * axis; + zenith = zenith.normalize(); - zenith.fX = fZenith.fX - dot * axis.fX; - zenith.fY = fZenith.fY - dot * axis.fY; - zenith.fZ = fZenith.fZ - dot * axis.fZ; - - SkPoint3D{zenith.fX, zenith.fY, zenith.fZ}.normalize(&zenith); - } - - SkUnit3D::Cross(axis, zenith, &cross); + cross = axis.cross(zenith); { SkMatrix* orien = &fOrientation; - SkScalar x = fObserver.fX; - SkScalar y = fObserver.fY; - SkScalar z = fObserver.fZ; + auto [x, y, z] = fObserver; // Looking along the view axis we have: // @@ -249,15 +98,15 @@ void SkCamera3D::doUpdate() const { // and scales in x and y relative to the negative of the observer's z value // (the observer is in the negative z direction). - orien->set(SkMatrix::kMScaleX, x * axis.fX - z * cross.fX); - orien->set(SkMatrix::kMSkewX, x * axis.fY - z * cross.fY); - orien->set(SkMatrix::kMTransX, x * axis.fZ - z * cross.fZ); - orien->set(SkMatrix::kMSkewY, y * axis.fX - z * zenith.fX); - orien->set(SkMatrix::kMScaleY, y * axis.fY - z * zenith.fY); - orien->set(SkMatrix::kMTransY, y * axis.fZ - z * zenith.fZ); - orien->set(SkMatrix::kMPersp0, axis.fX); - orien->set(SkMatrix::kMPersp1, axis.fY); - orien->set(SkMatrix::kMPersp2, axis.fZ); + orien->set(SkMatrix::kMScaleX, x * axis.x - z * cross.x); + orien->set(SkMatrix::kMSkewX, x * axis.y - z * cross.y); + orien->set(SkMatrix::kMTransX, x * axis.z - z * cross.z); + orien->set(SkMatrix::kMSkewY, y * axis.x - z * zenith.x); + orien->set(SkMatrix::kMScaleY, y * axis.y - z * zenith.y); + orien->set(SkMatrix::kMTransY, y * axis.z - z * zenith.z); + orien->set(SkMatrix::kMPersp0, axis.x); + orien->set(SkMatrix::kMPersp1, axis.y); + orien->set(SkMatrix::kMPersp2, axis.z); } } @@ -269,15 +118,9 @@ void SkCamera3D::patchToMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const { const SkScalar* mapPtr = (const SkScalar*)(const void*)&fOrientation; const SkScalar* patchPtr; - SkPoint3D diff; - SkScalar dot; - - diff.fX = quilt.fOrigin.fX - fLocation.fX; - diff.fY = quilt.fOrigin.fY - fLocation.fY; - diff.fZ = quilt.fOrigin.fZ - fLocation.fZ; - dot = SkUnit3D::Dot(SkUnit3D{diff.fX, diff.fY, diff.fZ}, - SkUnit3D{mapPtr[6], mapPtr[7], mapPtr[8]}); + SkV3 diff = quilt.fOrigin - fLocation; + SkScalar dot = diff.dot({mapPtr[6], mapPtr[7], mapPtr[8]}); // This multiplies fOrientation by the matrix [quilt.fU quilt.fV diff] -- U, V, and diff are // column vectors in the matrix -- then divides by the length of the projection of diff onto @@ -307,7 +150,6 @@ void SkCamera3D::patchToMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const { /////////////////////////////////////////////////////////////////////////////// Sk3DView::Sk3DView() { - fInitialRec.fMatrix.reset(); fRec = &fInitialRec; } @@ -338,22 +180,22 @@ void Sk3DView::restore() { void Sk3DView::setCameraLocation(SkScalar x, SkScalar y, SkScalar z) { // the camera location is passed in inches, set in pt SkScalar lz = z * 72.0f; - fCamera.fLocation.set(x * 72.0f, y * 72.0f, lz); - fCamera.fObserver.set(0, 0, lz); + fCamera.fLocation = {x * 72.0f, y * 72.0f, lz}; + fCamera.fObserver = {0, 0, lz}; fCamera.update(); } SkScalar Sk3DView::getCameraLocationX() const { - return fCamera.fLocation.fX / 72.0f; + return fCamera.fLocation.x / 72.0f; } SkScalar Sk3DView::getCameraLocationY() const { - return fCamera.fLocation.fY / 72.0f; + return fCamera.fLocation.y / 72.0f; } SkScalar Sk3DView::getCameraLocationZ() const { - return fCamera.fLocation.fZ / 72.0f; + return fCamera.fLocation.z / 72.0f; } #endif @@ -362,15 +204,15 @@ void Sk3DView::translate(SkScalar x, SkScalar y, SkScalar z) { } void Sk3DView::rotateX(SkScalar deg) { - fRec->fMatrix.preRotateX(deg); + fRec->fMatrix.preConcat(SkM44::Rotate({1, 0, 0}, deg * SK_ScalarPI / 180)); } void Sk3DView::rotateY(SkScalar deg) { - fRec->fMatrix.preRotateY(deg); + fRec->fMatrix.preConcat(SkM44::Rotate({0,-1, 0}, deg * SK_ScalarPI / 180)); } void Sk3DView::rotateZ(SkScalar deg) { - fRec->fMatrix.preRotateZ(deg); + fRec->fMatrix.preConcat(SkM44::Rotate({0, 0, 1}, deg * SK_ScalarPI / 180)); } SkScalar Sk3DView::dotWithNormal(SkScalar x, SkScalar y, SkScalar z) const { diff --git a/chromium/third_party/skia/src/utils/SkClipStackUtils.cpp b/chromium/third_party/skia/src/utils/SkClipStackUtils.cpp index 00b933630e4..fade198d6d9 100644 --- a/chromium/third_party/skia/src/utils/SkClipStackUtils.cpp +++ b/chromium/third_party/skia/src/utils/SkClipStackUtils.cpp @@ -14,6 +14,11 @@ void SkClipStack_AsPath(const SkClipStack& cs, SkPath* path) { SkClipStack::Iter iter(cs, SkClipStack::Iter::kBottom_IterStart); while (const SkClipStack::Element* element = iter.next()) { + if (element->getDeviceSpaceType() == SkClipStack::Element::DeviceSpaceType::kShader) { + // TODO: Handle DeviceSpaceType::kShader somehow; it can't be turned into an SkPath + // but perhaps the pdf backend can apply shaders in another way. + continue; + } SkPath operand; if (element->getDeviceSpaceType() != SkClipStack::Element::DeviceSpaceType::kEmpty) { element->asDeviceSpacePath(&operand); diff --git a/chromium/third_party/skia/src/utils/SkCustomTypeface.cpp b/chromium/third_party/skia/src/utils/SkCustomTypeface.cpp index 61664aff9c1..2fbdd7542b9 100644 --- a/chromium/third_party/skia/src/utils/SkCustomTypeface.cpp +++ b/chromium/third_party/skia/src/utils/SkCustomTypeface.cpp @@ -11,21 +11,46 @@ #include "include/utils/SkCustomTypeface.h" #include "src/core/SkAdvancedTypefaceMetrics.h" -class SkUserTypeface : public SkTypeface { +static SkFontMetrics scale_fontmetrics(const SkFontMetrics& src, float sx, float sy) { + SkFontMetrics dst = src; + + #define SCALE_X(field) dst.field *= sx + #define SCALE_Y(field) dst.field *= sy + + SCALE_X(fAvgCharWidth); + SCALE_X(fMaxCharWidth); + SCALE_X(fXMin); + SCALE_X(fXMax); + + SCALE_Y(fTop); + SCALE_Y(fAscent); + SCALE_Y(fDescent); + SCALE_Y(fBottom); + SCALE_Y(fLeading); + SCALE_Y(fXHeight); + SCALE_Y(fCapHeight); + SCALE_Y(fUnderlineThickness); + SCALE_Y(fUnderlinePosition); + SCALE_Y(fStrikeoutThickness); + SCALE_Y(fStrikeoutPosition); + + #undef SCALE_X + #undef SCALE_Y + + return dst; +} + +class SkUserTypeface final : public SkTypeface { +private: friend class SkCustomTypefaceBuilder; friend class SkUserScalerContext; - SkUserTypeface(int count) - : SkTypeface(SkFontStyle()) - , fGlyphCount(count) - {} + SkUserTypeface() : SkTypeface(SkFontStyle()) {} - const int fGlyphCount; std::vector<SkPath> fPaths; std::vector<float> fAdvances; - SkRect fBounds; + SkFontMetrics fMetrics; -protected: SkScalerContext* onCreateScalerContext(const SkScalerContextEffects&, const SkDescriptor* desc) const override; void onFilterRec(SkScalerContextRec* rec) const override; @@ -46,9 +71,12 @@ protected: sk_sp<SkTypeface> onMakeClone(const SkFontArguments& args) const override { return sk_ref_sp(this); } - int onCountGlyphs() const override { return fGlyphCount; } + int onCountGlyphs() const override { return this->glyphCount(); } int onGetUPEM() const override { return 2048; /* ?? */ } - bool onComputeBounds(SkRect* bounds) const override { *bounds = fBounds; return true; } + bool onComputeBounds(SkRect* bounds) const override { + bounds->setLTRB(fMetrics.fXMin, fMetrics.fTop, fMetrics.fXMax, fMetrics.fBottom); + return true; + } // noops @@ -59,27 +87,39 @@ protected: int) const override { return 0; } int onGetTableTags(SkFontTableTag tags[]) const override { return 0; } size_t onGetTableData(SkFontTableTag, size_t, size_t, void*) const override { return 0; } + + int glyphCount() const { + SkASSERT(fPaths.size() == fAdvances.size()); + return SkToInt(fPaths.size()); + } }; -SkCustomTypefaceBuilder::SkCustomTypefaceBuilder(int numGlyphs) : fGlyphCount(numGlyphs) { - fAdvances.resize(numGlyphs); - fPaths.resize(numGlyphs); +SkCustomTypefaceBuilder::SkCustomTypefaceBuilder() { + sk_bzero(&fMetrics, sizeof(fMetrics)); +} + +void SkCustomTypefaceBuilder::setMetrics(const SkFontMetrics& fm, float scale) { + fMetrics = scale_fontmetrics(fm, scale, scale); } void SkCustomTypefaceBuilder::setGlyph(SkGlyphID index, float advance, const SkPath& path) { - if (index >= (unsigned)fGlyphCount) { - return; + SkASSERT(fPaths.size() == fAdvances.size()); + if (index >= fPaths.size()) { + fPaths.resize(SkToSizeT(index) + 1); + fAdvances.resize(SkToSizeT(index) + 1); } fAdvances[index] = advance; fPaths[index] = path; } sk_sp<SkTypeface> SkCustomTypefaceBuilder::detach() { - if (fGlyphCount <= 0) return nullptr; + SkASSERT(fPaths.size() == fAdvances.size()); + if (fPaths.empty()) return nullptr; - SkUserTypeface* tf = new SkUserTypeface(fGlyphCount); + sk_sp<SkUserTypeface> tf(new SkUserTypeface()); tf->fAdvances = std::move(fAdvances); tf->fPaths = std::move(fPaths); + tf->fMetrics = fMetrics; // initially inverted, so that any "union" will overwrite the first time SkRect bounds = {SK_ScalarMax, SK_ScalarMax, -SK_ScalarMax, -SK_ScalarMax}; @@ -89,9 +129,12 @@ sk_sp<SkTypeface> SkCustomTypefaceBuilder::detach() { bounds.join(path.getBounds()); } } - tf->fBounds = bounds; + tf->fMetrics.fTop = bounds.top(); + tf->fMetrics.fBottom = bounds.bottom(); + tf->fMetrics.fXMin = bounds.left(); + tf->fMetrics.fXMax = bounds.right(); - return sk_sp<SkTypeface>(tf); + return std::move(tf); } ///////////// @@ -103,8 +146,8 @@ void SkUserTypeface::onFilterRec(SkScalerContextRec* rec) const { } void SkUserTypeface::getGlyphToUnicodeMap(SkUnichar* glyphToUnicode) const { - for (int gid = 0; gid < fGlyphCount; ++gid) { - glyphToUnicode[gid] = 0; + for (int gid = 0; gid < this->glyphCount(); ++gid) { + glyphToUnicode[gid] = SkTo<SkUnichar>(gid); } } @@ -118,7 +161,7 @@ void SkUserTypeface::onGetFontDescriptor(SkFontDescriptor* desc, bool* isLocal) void SkUserTypeface::onCharsToGlyphs(const SkUnichar uni[], int count, SkGlyphID glyphs[]) const { for (int i = 0; i < count; ++i) { - glyphs[i] = 0; + glyphs[i] = uni[i] < this->glyphCount() ? SkTo<SkGlyphID>(uni[i]) : 0; } } @@ -150,7 +193,7 @@ public: protected: unsigned generateGlyphCount() override { - return this->userTF()->fGlyphCount; + return this->userTF()->glyphCount(); } bool generateAdvance(SkGlyph* glyph) override { @@ -176,15 +219,8 @@ protected: } void generateFontMetrics(SkFontMetrics* metrics) override { - auto [_, sy] = fMatrix.mapXY(0, 1); - - sk_bzero(metrics, sizeof(*metrics)); - metrics->fTop = this->userTF()->fBounds.fTop * sy; - metrics->fBottom = this->userTF()->fBounds.fBottom * sy; - - // todo: get these from the creator of the typeface? - metrics->fAscent = metrics->fTop; - metrics->fDescent = metrics->fBottom; + auto [sx, sy] = fMatrix.mapXY(1, 1); + *metrics = scale_fontmetrics(this->userTF()->fMetrics, sx, sy); } private: @@ -268,7 +304,7 @@ static void compress_write(SkWStream* stream, const SkPath& path, int upem) { static constexpr int kMaxGlyphCount = 65536; static constexpr size_t kHeaderSize = 16; -static const char gHeaderString[] = "SkUserTypeface00"; +static const char gHeaderString[] = "SkUserTypeface01"; static_assert(sizeof(gHeaderString) == 1 + kHeaderSize, "need header to be 16 bytes"); std::unique_ptr<SkStreamAsset> SkUserTypeface::onOpenStream(int* ttcIndex) const { @@ -276,20 +312,19 @@ std::unique_ptr<SkStreamAsset> SkUserTypeface::onOpenStream(int* ttcIndex) const wstream.write(gHeaderString, kHeaderSize); - SkASSERT(fAdvances.size() == (unsigned)fGlyphCount); - SkASSERT(fPaths.size() == (unsigned)fGlyphCount); + wstream.write(&fMetrics, sizeof(fMetrics)); // just hacking around -- this makes the serialized font 1/2 size const bool use_compression = false; - wstream.write32(fGlyphCount); + wstream.write32(this->glyphCount()); if (use_compression) { for (float a : fAdvances) { write_scaled_float_to_16(&wstream, a, 2048); } } else { - wstream.write(fAdvances.data(), fGlyphCount * sizeof(float)); + wstream.write(fAdvances.data(), this->glyphCount() * sizeof(float)); } for (const auto& p : fPaths) { @@ -334,12 +369,19 @@ sk_sp<SkTypeface> SkCustomTypefaceBuilder::Deserialize(SkStream* stream) { return nullptr; } + SkFontMetrics metrics; + if (stream->read(&metrics, sizeof(metrics)) != sizeof(metrics)) { + return nullptr; + } + int glyphCount; if (!stream->readS32(&glyphCount) || glyphCount < 0 || glyphCount > kMaxGlyphCount) { return nullptr; } - SkCustomTypefaceBuilder builder(glyphCount); + SkCustomTypefaceBuilder builder; + + builder.setMetrics(metrics); std::vector<float> advances(glyphCount); if (stream->read(advances.data(), glyphCount * sizeof(float)) != glyphCount * sizeof(float)) { diff --git a/chromium/third_party/skia/src/utils/SkJSON.cpp b/chromium/third_party/skia/src/utils/SkJSON.cpp index 181ca752e5a..c53fc1bfc0a 100644 --- a/chromium/third_party/skia/src/utils/SkJSON.cpp +++ b/chromium/third_party/skia/src/utils/SkJSON.cpp @@ -28,23 +28,22 @@ static constexpr size_t kRecAlign = alignof(Value); void Value::init_tagged(Tag t) { memset(fData8, 0, sizeof(fData8)); - fData8[Value::kTagOffset] = SkTo<uint8_t>(t); + fData8[0] = SkTo<uint8_t>(t); SkASSERT(this->getTag() == t); } -// Pointer values store a type (in the upper kTagBits bits) and a pointer. +// Pointer values store a type (in the lower kTagBits bits) and a pointer. void Value::init_tagged_pointer(Tag t, void* p) { - *this->cast<uintptr_t>() = reinterpret_cast<uintptr_t>(p); - if (sizeof(Value) == sizeof(uintptr_t)) { - // For 64-bit, we rely on the pointer upper bits being unused/zero. - SkASSERT(!(fData8[kTagOffset] & kTagMask)); - fData8[kTagOffset] |= SkTo<uint8_t>(t); + *this->cast<uintptr_t>() = reinterpret_cast<uintptr_t>(p); + // For 64-bit, we rely on the pointer lower bits being zero. + SkASSERT(!(fData8[0] & kTagMask)); + fData8[0] |= SkTo<uint8_t>(t); } else { - // For 32-bit, we need to zero-initialize the upper 32 bits + // For 32-bit, we store the pointer in the upper word SkASSERT(sizeof(Value) == sizeof(uintptr_t) * 2); - this->cast<uintptr_t>()[kTagOffset >> 2] = 0; - fData8[kTagOffset] = SkTo<uint8_t>(t); + this->init_tagged(t); + *this->cast<uintptr_t>() = reinterpret_cast<uintptr_t>(p); } SkASSERT(this->getTag() == t); @@ -126,11 +125,8 @@ public: return; } - static_assert(static_cast<uint8_t>(Tag::kShortString) == 0, "please don't break this"); - static_assert(sizeof(Value) == 8, ""); - - // TODO: LIKELY - if (src && src + 7 <= eos) { + // initFastShortString is faster (doh), but requires access to 6 chars past src. + if (src && src + 6 <= eos) { this->initFastShortString(src, size); } else { this->initShortString(src, size); @@ -140,7 +136,8 @@ public: } private: - static constexpr size_t kMaxInlineStringSize = sizeof(Value) - 1; + // first byte reserved for tagging, \0 terminator => 6 usable chars + static constexpr size_t kMaxInlineStringSize = sizeof(Value) - 2; void initLongString(const char* src, size_t size, SkArenaAlloc& alloc) { SkASSERT(size > kMaxInlineStringSize); @@ -162,12 +159,23 @@ private: void initFastShortString(const char* src, size_t size) { SkASSERT(size <= kMaxInlineStringSize); - // Load 8 chars and mask out the tag and \0 terminator. uint64_t* s64 = this->cast<uint64_t>(); - memcpy(s64, src, 8); + + // Load 8 chars and mask out the tag and \0 terminator. + // Note: we picked kShortString == 0 to avoid setting explicitly below. + static_assert(SkToU8(Tag::kShortString) == 0, "please don't break this"); + + // Since the first byte is occupied by the tag, we want the string chars [0..5] to land + // on bytes [1..6] => the fastest way is to read8 @(src - 1) (always safe, because the + // string requires a " prefix at the very least). + memcpy(s64, src - 1, 8); #if defined(SK_CPU_LENDIAN) - *s64 &= 0x00ffffffffffffffULL >> ((kMaxInlineStringSize - size) * 8); + // The mask for a max-length string (6), with a leading tag and trailing \0 is + // 0x00ffffffffffff00. Accounting for the final left-shift, this becomes + // 0x0000ffffffffffff. + *s64 &= (0x0000ffffffffffffULL >> ((kMaxInlineStringSize - size) * 8)) // trailing \0s + << 8; // tag byte #else static_assert(false, "Big-endian builds are not supported at this time."); #endif diff --git a/chromium/third_party/skia/src/utils/SkJSON.h b/chromium/third_party/skia/src/utils/SkJSON.h index 931b30f0a4e..d3f0b1d48f0 100644 --- a/chromium/third_party/skia/src/utils/SkJSON.h +++ b/chromium/third_party/skia/src/utils/SkJSON.h @@ -117,58 +117,69 @@ protected: char[8] (short string storage) external payload (tagged) pointer - -- highest 3 bits reserved for type storage + -- lowest 3 bits reserved for tag storage */ enum class Tag : uint8_t { - // We picked kShortString == 0 so that tag 0x00 and stored max_size-size (7-7=0) - // conveniently overlap the '\0' terminator, allowing us to store a 7 character - // C string inline. + // n.b.: we picked kShortString == 0 on purpose, + // to enable certain short-string optimizations. kShortString = 0b00000000, // inline payload - kNull = 0b00100000, // no payload - kBool = 0b01000000, // inline payload - kInt = 0b01100000, // inline payload - kFloat = 0b10000000, // inline payload - kString = 0b10100000, // ptr to external storage - kArray = 0b11000000, // ptr to external storage - kObject = 0b11100000, // ptr to external storage + kNull = 0b00000001, // no payload + kBool = 0b00000010, // inline payload + kInt = 0b00000011, // inline payload + kFloat = 0b00000100, // inline payload + kString = 0b00000101, // ptr to external storage + kArray = 0b00000110, // ptr to external storage + kObject = 0b00000111, // ptr to external storage }; - static constexpr uint8_t kTagMask = 0b11100000; + static constexpr uint8_t kTagMask = 0b00000111; void init_tagged(Tag); void init_tagged_pointer(Tag, void*); Tag getTag() const { - return static_cast<Tag>(fData8[kTagOffset] & kTagMask); + return static_cast<Tag>(fData8[0] & kTagMask); } - // Access the record data as T. + // Access the record payload as T. // - // This is also used to access the payload for inline records. Since the record type lives in - // the high bits, sizeof(T) must be less than sizeof(Value) when accessing inline payloads. + // Since the tag is stored in the lower bits, we skip the first word whenever feasible. // - // E.g. + // E.g. (U == unused) // // uint8_t // ----------------------------------------------------------------------- - // | val8 | val8 | val8 | val8 | val8 | val8 | val8 | TYPE| + // |TAG| U | val8 | U | U | U | U | U | U | + // ----------------------------------------------------------------------- + // + // uint16_t + // ----------------------------------------------------------------------- + // |TAG| U | val16 | U | U | // ----------------------------------------------------------------------- // // uint32_t // ----------------------------------------------------------------------- - // | val32 | unused | TYPE| + // |TAG| U | val32 | + // ----------------------------------------------------------------------- + // + // T* (32b) + // ----------------------------------------------------------------------- + // |TAG| U | T* (32bits) | // ----------------------------------------------------------------------- // // T* (64b) // ----------------------------------------------------------------------- - // | T* (kTypeShift bits) |TYPE| + // |TAG| T* (61bits) | // ----------------------------------------------------------------------- // template <typename T> const T* cast() const { static_assert(sizeof (T) <= sizeof(Value), ""); static_assert(alignof(T) <= alignof(Value), ""); - return reinterpret_cast<const T*>(this); + + return (sizeof(T) > sizeof(*this) / 2) + ? reinterpret_cast<const T*>(this) + 0 // need all the bits + : reinterpret_cast<const T*>(this) + 1; // skip the first word (where the tag lives) } template <typename T> @@ -183,8 +194,8 @@ protected: return (sizeof(uintptr_t) < sizeof(Value)) // For 32-bit, pointers are stored unmodified. ? *this->cast<const T*>() - // For 64-bit, we use the high bits of the pointer as tag storage. - : reinterpret_cast<T*>(*this->cast<uintptr_t>() & kTagPointerMask); + // For 64-bit, we use the lower bits of the pointer as tag storage. + : reinterpret_cast<T*>(*this->cast<uintptr_t>() & ~static_cast<uintptr_t>(kTagMask)); } private: @@ -192,12 +203,7 @@ private: uint8_t fData8[kValueSize]; -#if defined(SK_CPU_LENDIAN) - static constexpr size_t kTagOffset = kValueSize - 1; - - static constexpr uintptr_t kTagPointerMask = - ~(static_cast<uintptr_t>(kTagMask) << ((sizeof(uintptr_t) - 1) * 8)); -#else +#if !defined(SK_CPU_LENDIAN) // The current value layout assumes LE and will take some tweaking for BE. static_assert(false, "Big-endian builds are not supported at this time."); #endif @@ -319,11 +325,11 @@ class ObjectValue final : public VectorValue<Member, Value::Type::kObject> { public: ObjectValue(const Member* src, size_t size, SkArenaAlloc& alloc); - const Value& operator[](const char*) const; + const Value& operator[](const char*) const; -private: - // Not particularly interesting - hiding for disambiguation. - const Member& operator[](size_t i) const = delete; + const Member& operator[](size_t i) const { + return this->VectorValue::operator[](i); + } }; class DOM final : public SkNoncopyable { diff --git a/chromium/third_party/skia/src/utils/SkLuaCanvas.cpp b/chromium/third_party/skia/src/utils/SkLuaCanvas.cpp index 7bdeb482da4..3a094c3f5f6 100644 --- a/chromium/third_party/skia/src/utils/SkLuaCanvas.cpp +++ b/chromium/third_party/skia/src/utils/SkLuaCanvas.cpp @@ -114,10 +114,10 @@ void SkLuaCanvas::didConcat44(const SkM44&) { // TODO } void SkLuaCanvas::didScale(SkScalar x, SkScalar y) { - this->didConcat(SkMatrix::MakeScale(x, y)); + this->didConcat(SkMatrix::Scale(x, y)); } void SkLuaCanvas::didTranslate(SkScalar x, SkScalar y) { - this->didConcat(SkMatrix::MakeTrans(x, y)); + this->didConcat(SkMatrix::Translate(x, y)); } void SkLuaCanvas::didConcat(const SkMatrix& matrix) { switch (matrix.getType()) { diff --git a/chromium/third_party/skia/src/utils/SkParseColor.cpp b/chromium/third_party/skia/src/utils/SkParseColor.cpp index ba7c51048f1..9846a8ff5ee 100644 --- a/chromium/third_party/skia/src/utils/SkParseColor.cpp +++ b/chromium/third_party/skia/src/utils/SkParseColor.cpp @@ -8,211 +8,172 @@ #include "include/utils/SkParse.h" -static const unsigned int gColorNames[] = { -0x85891945, 0x32a50000, 0x00f0f8ff, // aliceblue -0x85d44c6b, 0x16e84d0a, 0x00faebd7, // antiquewhite -0x86350800, 0x0000ffff, // aqua -0x86350b43, 0x492e2800, 0x007fffd4, // aquamarine -0x87559140, 0x00f0ffff, // azure -0x88a93940, 0x00f5f5dc, // beige -0x89338d4a, 0x00ffe4c4, // bisque -0x89811ac0, 0x00000000, // black -0x898170d1, 0x1481635f, 0x38800000, 0x00ffebcd, // blanchedalmond -0x89952800, 0x000000ff, // blue -0x89952d93, 0x3d85a000, 0x008a2be2, // blueviolet -0x8a4fbb80, 0x00a52a2a, // brown -0x8ab2666f, 0x3de40000, 0x00deb887, // burlywood -0x8c242d05, 0x32a50000, 0x005f9ea0, // cadetblue -0x8d019525, 0x16b32800, 0x007fff00, // chartreuse -0x8d0f1bd9, 0x06850000, 0x00d2691e, // chocolate -0x8df20b00, 0x00ff7f50, // coral -0x8df27199, 0x3ee59099, 0x54a00000, 0x006495ed, // cornflowerblue -0x8df274d3, 0x31600000, 0x00fff8dc, // cornsilk -0x8e496cdf, 0x38000000, 0x00dc143c, // crimson -0x8f217000, 0x0000ffff, // cyan -0x90325899, 0x54a00000, 0x0000008b, // darkblue -0x903258f3, 0x05c00000, 0x00008b8b, // darkcyan -0x903259df, 0x3085749f, 0x10000000, 0x00b8860b, // darkgoldenrod -0x903259e5, 0x07200000, 0x00a9a9a9, // darkgray -0x903259e5, 0x14ae0000, 0x00006400, // darkgreen -0x90325ad1, 0x05690000, 0x00bdb76b, // darkkhaki -0x90325b43, 0x1caea040, 0x008b008b, // darkmagenta -0x90325bd9, 0x26c53c8b, 0x15c00000, 0x00556b2f, // darkolivegreen -0x90325be5, 0x05c72800, 0x00ff8c00, // darkorange -0x90325be5, 0x0d092000, 0x009932cc, // darkorchid -0x90325c8b, 0x10000000, 0x008b0000, // darkred -0x90325cc3, 0x31af7000, 0x00e9967a, // darksalmon -0x90325ccb, 0x04f2295c, 0x008fbc8f, // darkseagreen -0x90325cd9, 0x0685132b, 0x14000000, 0x00483d8b, // darkslateblue -0x90325cd9, 0x06853c83, 0x64000000, 0x002f4f4f, // darkslategray -0x90325d2b, 0x4a357a67, 0x14000000, 0x0000ced1, // darkturquoise -0x90325d93, 0x3d85a000, 0x009400d3, // darkviolet -0x90a58413, 0x39600000, 0x00ff1493, // deeppink -0x90a584d7, 0x644ca940, 0x0000bfff, // deepskyblue -0x912d3c83, 0x64000000, 0x00696969, // dimgray -0x91e43965, 0x09952800, 0x001e90ff, // dodgerblue -0x993228a5, 0x246b0000, 0x00b22222, // firebrick -0x998f9059, 0x5d09a140, 0x00fffaf0, // floralwhite -0x99f22ce9, 0x1e452b80, 0x00228b22, // forestgreen -0x9aa344d3, 0x04000000, 0x00ff00ff, // fuchsia -0x9c2974c5, 0x3e4f0000, 0x00dcdcdc, // gainsboro -0x9d0f9d2f, 0x21342800, 0x00f8f8ff, // ghostwhite -0x9dec2000, 0x00ffd700, // gold -0x9dec215d, 0x49e40000, 0x00daa520, // goldenrod -0x9e41c800, 0x00808080, // gray -0x9e452b80, 0x00008000, // green -0x9e452bb3, 0x158c7dc0, 0x00adff2f, // greenyellow -0xa1ee2e49, 0x16e00000, 0x00f0fff0, // honeydew -0xa1f4825d, 0x2c000000, 0x00ff69b4, // hotpink -0xa5c4485d, 0x48a40000, 0x00cd5c5c, // indianred -0xa5c449de, 0x004b0082, // indigo -0xa6cf9640, 0x00fffff0, // ivory -0xad015a40, 0x00f0e68c, // khaki -0xb0362b89, 0x16400000, 0x00e6e6fa, // lavender -0xb0362b89, 0x16426567, 0x20000000, 0x00fff0f5, // lavenderblush -0xb03771e5, 0x14ae0000, 0x007cfc00, // lawngreen -0xb0ad7b87, 0x212633dc, 0x00fffacd, // lemonchiffon -0xb1274505, 0x32a50000, 0x00add8e6, // lightblue -0xb1274507, 0x3e416000, 0x00f08080, // lightcoral -0xb1274507, 0x642e0000, 0x00e0ffff, // lightcyan -0xb127450f, 0x3d842ba5, 0x3c992b19, 0x3ee00000, 0x00fafad2, // lightgoldenrodyellow -0xb127450f, 0x48a57000, 0x0090ee90, // lightgreen -0xb127450f, 0x48b90000, 0x00d3d3d3, // lightgrey -0xb1274521, 0x25cb0000, 0x00ffb6c1, // lightpink -0xb1274527, 0x058d7b80, 0x00ffa07a, // lightsalmon -0xb1274527, 0x1427914b, 0x38000000, 0x0020b2aa, // lightseagreen -0xb1274527, 0x2f22654a, 0x0087cefa, // lightskyblue -0xb1274527, 0x303429e5, 0x07200000, 0x00778899, // lightslategray -0xb1274527, 0x50a56099, 0x54a00000, 0x00b0c4de, // lightsteelblue -0xb1274533, 0x158c7dc0, 0x00ffffe0, // lightyellow -0xb12d2800, 0x0000ff00, // lime -0xb12d29e5, 0x14ae0000, 0x0032cd32, // limegreen -0xb12e2b80, 0x00faf0e6, // linen -0xb4272ba9, 0x04000000, 0x00ff00ff, // magenta -0xb4327bdc, 0x00800000, // maroon -0xb4a44d5b, 0x06350b43, 0x492e2800, 0x0066cdaa, // mediumaquamarine -0xb4a44d5b, 0x09952800, 0x000000cd, // mediumblue -0xb4a44d5b, 0x3e434248, 0x00ba55d3, // mediumorchid -0xb4a44d5b, 0x42b2830a, 0x009370db, // mediumpurple -0xb4a44d5b, 0x4ca13c8b, 0x15c00000, 0x003cb371, // mediumseagreen -0xb4a44d5b, 0x4d81a145, 0x32a50000, 0x007b68ee, // mediumslateblue -0xb4a44d5b, 0x4e124b8f, 0x1e452b80, 0x0000fa9a, // mediumspringgreen -0xb4a44d5b, 0x52b28d5f, 0x26650000, 0x0048d1cc, // mediumturquoise -0xb4a44d5b, 0x592f6169, 0x48a40000, 0x00c71585, // mediumvioletred -0xb524724f, 0x2282654a, 0x00191970, // midnightblue -0xb52ea0e5, 0x142d0000, 0x00f5fffa, // mintcream -0xb533a665, 0x3e650000, 0x00ffe4e1, // mistyrose -0xb5e31867, 0x25c00000, 0x00ffe4b5, // moccasin -0xb8360a9f, 0x5d09a140, 0x00ffdead, // navajowhite -0xb836c800, 0x00000080, // navy -0xbd846047, 0x14000000, 0x00fdf5e6, // oldlace -0xbd89b140, 0x00808000, // olive -0xbd89b149, 0x48220000, 0x006b8e23, // olivedrab -0xbe4171ca, 0x00ffa500, // orange -0xbe4171cb, 0x48a40000, 0x00ff4500, // orangered -0xbe434248, 0x00da70d6, // orchid -0xc02c29df, 0x3085749f, 0x10000000, 0x00eee8aa, // palegoldenrod -0xc02c29e5, 0x14ae0000, 0x0098fb98, // palegreen -0xc02c2d2b, 0x4a357a67, 0x14000000, 0x00afeeee, // paleturquoise -0xc02c2d93, 0x3d85a48b, 0x10000000, 0x00db7093, // palevioletred -0xc0300e43, 0x5d098000, 0x00ffefd5, // papayawhip -0xc0a11a21, 0x54c60000, 0x00ffdab9, // peachpuff -0xc0b2a800, 0x00cd853f, // peru -0xc12e5800, 0x00ffc0cb, // pink -0xc1956800, 0x00dda0dd, // plum -0xc1f72165, 0x09952800, 0x00b0e0e6, // powderblue -0xc2b2830a, 0x00800080, // purple -0xc8a40000, 0x00ff0000, // red -0xc9f3c8a5, 0x3eee0000, 0x00bc8f8f, // rosybrown -0xc9f90b05, 0x32a50000, 0x004169e1, // royalblue -0xcc24230b, 0x0a4fbb80, 0x008b4513, // saddlebrown -0xcc2c6bdc, 0x00fa8072, // salmon -0xcc2e2645, 0x49f77000, 0x00f4a460, // sandybrown -0xcca13c8b, 0x15c00000, 0x002e8b57, // seagreen -0xcca19a0b, 0x31800000, 0x00fff5ee, // seashell -0xcd257382, 0x00a0522d, // sienna -0xcd2cb164, 0x00c0c0c0, // silver -0xcd79132b, 0x14000000, 0x0087ceeb, // skyblue -0xcd81a145, 0x32a50000, 0x006a5acd, // slateblue -0xcd81a14f, 0x48390000, 0x00708090, // slategray -0xcdcfb800, 0x00fffafa, // snow -0xce124b8f, 0x1e452b80, 0x0000ff7f, // springgreen -0xce852b05, 0x32a50000, 0x004682b4, // steelblue -0xd02e0000, 0x00d2b48c, // tan -0xd0a16000, 0x00008080, // teal -0xd1099d19, 0x14000000, 0x00d8bfd8, // thistle -0xd1ed0d1e, 0x00ff6347, // tomato -0xd2b28d5f, 0x26650000, 0x0040e0d0, // turquoise -0xd92f6168, 0x00ee82ee, // violet -0xdd050d00, 0x00f5deb3, // wheat -0xdd09a140, 0x00ffffff, // white -0xdd09a167, 0x35eb2800, 0x00f5f5f5, // whitesmoke -0xe4ac63ee, 0x00ffff00, // yellow -0xe4ac63ef, 0x1e452b80, 0x009acd32 // yellowgreen -}; // original = 2505 : replacement = 1616 +#pragma pack(push,1) +static constexpr struct ColorRec { + const char* name; + uint8_t r, g, b; +} gNamedColors[] = { + { "aliceblue", 0xf0,0xf8,0xff }, + { "antiquewhite", 0xfa,0xeb,0xd7 }, + { "aqua", 0x00,0xff,0xff }, + { "aquamarine", 0x7f,0xff,0xd4 }, + { "azure", 0xf0,0xff,0xff }, + { "beige", 0xf5,0xf5,0xdc }, + { "bisque", 0xff,0xe4,0xc4 }, + { "black", 0x00,0x00,0x00 }, + { "blanchedalmond", 0xff,0xeb,0xcd }, + { "blue", 0x00,0x00,0xff }, + { "blueviolet", 0x8a,0x2b,0xe2 }, + { "brown", 0xa5,0x2a,0x2a }, + { "burlywood", 0xde,0xb8,0x87 }, + { "cadetblue", 0x5f,0x9e,0xa0 }, + { "chartreuse", 0x7f,0xff,0x00 }, + { "chocolate", 0xd2,0x69,0x1e }, + { "coral", 0xff,0x7f,0x50 }, + { "cornflowerblue", 0x64,0x95,0xed }, + { "cornsilk", 0xff,0xf8,0xdc }, + { "crimson", 0xdc,0x14,0x3c }, + { "cyan", 0x00,0xff,0xff }, + { "darkblue", 0x00,0x00,0x8b }, + { "darkcyan", 0x00,0x8b,0x8b }, + { "darkgoldenrod", 0xb8,0x86,0x0b }, + { "darkgray", 0xa9,0xa9,0xa9 }, + { "darkgreen", 0x00,0x64,0x00 }, + { "darkkhaki", 0xbd,0xb7,0x6b }, + { "darkmagenta", 0x8b,0x00,0x8b }, + { "darkolivegreen", 0x55,0x6b,0x2f }, + { "darkorange", 0xff,0x8c,0x00 }, + { "darkorchid", 0x99,0x32,0xcc }, + { "darkred", 0x8b,0x00,0x00 }, + { "darksalmon", 0xe9,0x96,0x7a }, + { "darkseagreen", 0x8f,0xbc,0x8f }, + { "darkslateblue", 0x48,0x3d,0x8b }, + { "darkslategray", 0x2f,0x4f,0x4f }, + { "darkturquoise", 0x00,0xce,0xd1 }, + { "darkviolet", 0x94,0x00,0xd3 }, + { "deeppink", 0xff,0x14,0x93 }, + { "deepskyblue", 0x00,0xbf,0xff }, + { "dimgray", 0x69,0x69,0x69 }, + { "dodgerblue", 0x1e,0x90,0xff }, + { "firebrick", 0xb2,0x22,0x22 }, + { "floralwhite", 0xff,0xfa,0xf0 }, + { "forestgreen", 0x22,0x8b,0x22 }, + { "fuchsia", 0xff,0x00,0xff }, + { "gainsboro", 0xdc,0xdc,0xdc }, + { "ghostwhite", 0xf8,0xf8,0xff }, + { "gold", 0xff,0xd7,0x00 }, + { "goldenrod", 0xda,0xa5,0x20 }, + { "gray", 0x80,0x80,0x80 }, + { "green", 0x00,0x80,0x00 }, + { "greenyellow", 0xad,0xff,0x2f }, + { "honeydew", 0xf0,0xff,0xf0 }, + { "hotpink", 0xff,0x69,0xb4 }, + { "indianred", 0xcd,0x5c,0x5c }, + { "indigo", 0x4b,0x00,0x82 }, + { "ivory", 0xff,0xff,0xf0 }, + { "khaki", 0xf0,0xe6,0x8c }, + { "lavender", 0xe6,0xe6,0xfa }, + { "lavenderblush", 0xff,0xf0,0xf5 }, + { "lawngreen", 0x7c,0xfc,0x00 }, + { "lemonchiffon", 0xff,0xfa,0xcd }, + { "lightblue", 0xad,0xd8,0xe6 }, + { "lightcoral", 0xf0,0x80,0x80 }, + { "lightcyan", 0xe0,0xff,0xff }, + { "lightgoldenrodyellow", 0xfa,0xfa,0xd2 }, + { "lightgreen", 0x90,0xee,0x90 }, + { "lightgrey", 0xd3,0xd3,0xd3 }, + { "lightpink", 0xff,0xb6,0xc1 }, + { "lightsalmon", 0xff,0xa0,0x7a }, + { "lightseagreen", 0x20,0xb2,0xaa }, + { "lightskyblue", 0x87,0xce,0xfa }, + { "lightslategray", 0x77,0x88,0x99 }, + { "lightsteelblue", 0xb0,0xc4,0xde }, + { "lightyellow", 0xff,0xff,0xe0 }, + { "lime", 0x00,0xff,0x00 }, + { "limegreen", 0x32,0xcd,0x32 }, + { "linen", 0xfa,0xf0,0xe6 }, + { "magenta", 0xff,0x00,0xff }, + { "maroon", 0x80,0x00,0x00 }, + { "mediumaquamarine", 0x66,0xcd,0xaa }, + { "mediumblue", 0x00,0x00,0xcd }, + { "mediumorchid", 0xba,0x55,0xd3 }, + { "mediumpurple", 0x93,0x70,0xdb }, + { "mediumseagreen", 0x3c,0xb3,0x71 }, + { "mediumslateblue", 0x7b,0x68,0xee }, + { "mediumspringgreen", 0x00,0xfa,0x9a }, + { "mediumturquoise", 0x48,0xd1,0xcc }, + { "mediumvioletred", 0xc7,0x15,0x85 }, + { "midnightblue", 0x19,0x19,0x70 }, + { "mintcream", 0xf5,0xff,0xfa }, + { "mistyrose", 0xff,0xe4,0xe1 }, + { "moccasin", 0xff,0xe4,0xb5 }, + { "navajowhite", 0xff,0xde,0xad }, + { "navy", 0x00,0x00,0x80 }, + { "oldlace", 0xfd,0xf5,0xe6 }, + { "olive", 0x80,0x80,0x00 }, + { "olivedrab", 0x6b,0x8e,0x23 }, + { "orange", 0xff,0xa5,0x00 }, + { "orangered", 0xff,0x45,0x00 }, + { "orchid", 0xda,0x70,0xd6 }, + { "palegoldenrod", 0xee,0xe8,0xaa }, + { "palegreen", 0x98,0xfb,0x98 }, + { "paleturquoise", 0xaf,0xee,0xee }, + { "palevioletred", 0xdb,0x70,0x93 }, + { "papayawhip", 0xff,0xef,0xd5 }, + { "peachpuff", 0xff,0xda,0xb9 }, + { "peru", 0xcd,0x85,0x3f }, + { "pink", 0xff,0xc0,0xcb }, + { "plum", 0xdd,0xa0,0xdd }, + { "powderblue", 0xb0,0xe0,0xe6 }, + { "purple", 0x80,0x00,0x80 }, + { "red", 0xff,0x00,0x00 }, + { "rosybrown", 0xbc,0x8f,0x8f }, + { "royalblue", 0x41,0x69,0xe1 }, + { "saddlebrown", 0x8b,0x45,0x13 }, + { "salmon", 0xfa,0x80,0x72 }, + { "sandybrown", 0xf4,0xa4,0x60 }, + { "seagreen", 0x2e,0x8b,0x57 }, + { "seashell", 0xff,0xf5,0xee }, + { "sienna", 0xa0,0x52,0x2d }, + { "silver", 0xc0,0xc0,0xc0 }, + { "skyblue", 0x87,0xce,0xeb }, + { "slateblue", 0x6a,0x5a,0xcd }, + { "slategray", 0x70,0x80,0x90 }, + { "snow", 0xff,0xfa,0xfa }, + { "springgreen", 0x00,0xff,0x7f }, + { "steelblue", 0x46,0x82,0xb4 }, + { "tan", 0xd2,0xb4,0x8c }, + { "teal", 0x00,0x80,0x80 }, + { "thistle", 0xd8,0xbf,0xd8 }, + { "tomato", 0xff,0x63,0x47 }, + { "turquoise", 0x40,0xe0,0xd0 }, + { "violet", 0xee,0x82,0xee }, + { "wheat", 0xf5,0xde,0xb3 }, + { "white", 0xff,0xff,0xff }, + { "whitesmoke", 0xf5,0xf5,0xf5 }, + { "yellow", 0xff,0xff,0x00 }, + { "yellowgreen", 0x9a,0xcd,0x32 }, +}; +#pragma pack(pop) const char* SkParse::FindNamedColor(const char* name, size_t len, SkColor* color) { - const char* namePtr = name; - unsigned int sixMatches[4]; - unsigned int* sixMatchPtr = sixMatches; - bool first = true; - bool last = false; - char ch; - do { - unsigned int sixMatch = 0; - for (int chIndex = 0; chIndex < 6; chIndex++) { - sixMatch <<= 5; - ch = *namePtr | 0x20; - if (ch < 'a' || ch > 'z') - ch = 0; - else { - ch = ch - 'a' + 1; - namePtr++; - } - sixMatch |= ch ; // turn 'A' (0x41) into 'a' (0x61); - } - sixMatch <<= 1; - sixMatch |= 1; - if (first) { - sixMatch |= 0x80000000; - first = false; - } - ch = *namePtr | 0x20; - last = ch < 'a' || ch > 'z'; - if (last) - sixMatch &= ~1; - len -= 6; - *sixMatchPtr++ = sixMatch; - } while (last == false && len > 0); - const int colorNameSize = sizeof(gColorNames) / sizeof(unsigned int); - int lo = 0; - int hi = colorNameSize - 3; // back off to beginning of yellowgreen - while (lo <= hi) { - int mid = (hi + lo) >> 1; - while ((int) gColorNames[mid] >= 0) - --mid; - sixMatchPtr = sixMatches; - while (gColorNames[mid] == *sixMatchPtr) { - ++mid; - if ((*sixMatchPtr & 1) == 0) { // last - *color = gColorNames[mid] | 0xFF000000; - return namePtr; - } - ++sixMatchPtr; - } - int sixMask = *sixMatchPtr & ~0x80000000; - int midMask = gColorNames[mid] & ~0x80000000; - if (sixMask > midMask) { - lo = mid + 2; // skip color - while ((int) gColorNames[lo] >= 0) - ++lo; - } else if (hi == mid) - return nullptr; - else - hi = mid; + const auto* rec = std::lower_bound(std::begin(gNamedColors), + std::end (gNamedColors), + ColorRec{name, 0,0,0}, // key + [](const ColorRec& rec, const ColorRec& key) { + return strcmp(rec.name, key.name) < 0; + }); + + if (rec == std::end(gNamedColors) || strcmp(name, rec->name)) { + return nullptr; + } + + if (color) { + *color = SkColorSetRGB(rec->r, rec->g, rec->b); } - return nullptr; + + return name + strlen(rec->name); } // !!! move to char utilities diff --git a/chromium/third_party/skia/src/utils/SkParsePath.cpp b/chromium/third_party/skia/src/utils/SkParsePath.cpp index 688daae33b1..31a912ca476 100644 --- a/chromium/third_party/skia/src/utils/SkParsePath.cpp +++ b/chromium/third_party/skia/src/utils/SkParsePath.cpp @@ -92,7 +92,7 @@ bool SkParsePath::FromSVGString(const char data[], SkPath* result) { } char ch = data[0]; if (is_digit(ch) || ch == '-' || ch == '+' || ch == '.') { - if (op == '\0') { + if (op == '\0' || op == 'Z') { return false; } } else if (is_sep(ch)) { diff --git a/chromium/third_party/skia/src/utils/SkShadowUtils.cpp b/chromium/third_party/skia/src/utils/SkShadowUtils.cpp index 869997f7b34..4691b3fef26 100644 --- a/chromium/third_party/skia/src/utils/SkShadowUtils.cpp +++ b/chromium/third_party/skia/src/utils/SkShadowUtils.cpp @@ -17,6 +17,7 @@ #include "include/private/SkIDChangeListener.h" #include "include/utils/SkRandom.h" #include "src/core/SkBlurMask.h" +#include "src/core/SkColorFilterBase.h" #include "src/core/SkColorFilterPriv.h" #include "src/core/SkDevice.h" #include "src/core/SkDrawShadowInfo.h" @@ -40,7 +41,7 @@ * Final result is black with alpha of Gaussian(B)*G. * The assumption is that the original color's alpha is 1. */ -class SkGaussianColorFilter : public SkColorFilter { +class SkGaussianColorFilter : public SkColorFilterBase { public: SkGaussianColorFilter() : INHERITED() {} @@ -73,7 +74,7 @@ protected: private: SK_FLATTENABLE_HOOKS(SkGaussianColorFilter) - typedef SkColorFilter INHERITED; + typedef SkColorFilterBase INHERITED; }; sk_sp<SkFlattenable> SkGaussianColorFilter::CreateProc(SkReadBuffer&) { @@ -84,7 +85,8 @@ sk_sp<SkFlattenable> SkGaussianColorFilter::CreateProc(SkReadBuffer&) { std::unique_ptr<GrFragmentProcessor> SkGaussianColorFilter::asFragmentProcessor( GrRecordingContext*, const GrColorInfo&) const { - return GrBlurredEdgeFragmentProcessor::Make(GrBlurredEdgeFragmentProcessor::Mode::kGaussian); + return GrBlurredEdgeFragmentProcessor::Make( + /*inputFP=*/nullptr, GrBlurredEdgeFragmentProcessor::Mode::kGaussian); } #endif @@ -594,8 +596,7 @@ void SkBaseDevice::drawShadow(const SkPath& path, const SkDrawShadowRec& rec) { SkAutoDeviceTransformRestore adr( this, hasPerspective ? SkMatrix::I() - : SkMatrix::Concat(this->localToDevice(), - SkMatrix::MakeTrans(tx, ty))); + : this->localToDevice() * SkMatrix::Translate(tx, ty)); this->drawVertices(vertices, mode, paint); } }; diff --git a/chromium/third_party/skia/src/utils/mac/SkCGBase.h b/chromium/third_party/skia/src/utils/mac/SkCGBase.h new file mode 100644 index 00000000000..a7b0ed06d05 --- /dev/null +++ b/chromium/third_party/skia/src/utils/mac/SkCGBase.h @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCGBase_DEFINED +#define SkCGBase_DEFINED + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#ifdef SK_BUILD_FOR_MAC +#import <ApplicationServices/ApplicationServices.h> +#endif + +#ifdef SK_BUILD_FOR_IOS +#include <CoreGraphics/CoreGraphics.h> +#endif + +// Skia extensions for types in CGBase.h + +static inline CGFloat SkScalarToCGFloat(SkScalar scalar) { + return CGFLOAT_IS_DOUBLE ? SkScalarToDouble(scalar) : SkScalarToFloat(scalar); +} + +static inline SkScalar SkScalarFromCGFloat(CGFloat cgFloat) { + return CGFLOAT_IS_DOUBLE ? SkDoubleToScalar(cgFloat) : SkFloatToScalar(cgFloat); +} + +static inline float SkFloatFromCGFloat(CGFloat cgFloat) { + return CGFLOAT_IS_DOUBLE ? static_cast<float>(cgFloat) : cgFloat; +} + +#endif +#endif //SkCGBase_DEFINED diff --git a/chromium/third_party/skia/src/utils/mac/SkCGGeometry.h b/chromium/third_party/skia/src/utils/mac/SkCGGeometry.h new file mode 100644 index 00000000000..04b1263bcd5 --- /dev/null +++ b/chromium/third_party/skia/src/utils/mac/SkCGGeometry.h @@ -0,0 +1,52 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCGGeometry_DEFINED +#define SkCGGeometry_DEFINED + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#ifdef SK_BUILD_FOR_MAC +#import <ApplicationServices/ApplicationServices.h> +#endif + +#ifdef SK_BUILD_FOR_IOS +#include <CoreGraphics/CoreGraphics.h> +#endif + +// Skia extensions for types in CGGeometry.h + +// Inline versions of these CGRect helpers. +// The CG versions require making a call and a copy of the CGRect on the stack. + +static inline bool SkCGRectIsEmpty(const CGRect& rect) { + return rect.size.width <= 0 || rect.size.height <= 0; +} + +static inline CGFloat SkCGRectGetMinX(const CGRect& rect) { + return rect.origin.x; +} + +static inline CGFloat SkCGRectGetMaxX(const CGRect& rect) { + return rect.origin.x + rect.size.width; +} + +static inline CGFloat SkCGRectGetMinY(const CGRect& rect) { + return rect.origin.y; +} + +static inline CGFloat SkCGRectGetMaxY(const CGRect& rect) { + return rect.origin.y + rect.size.height; +} + +static inline CGFloat SkCGRectGetWidth(const CGRect& rect) { + return rect.size.width; +} + +#endif +#endif //SkCGGeometry_DEFINED diff --git a/chromium/third_party/skia/src/utils/mac/SkCTFontSmoothBehavior.cpp b/chromium/third_party/skia/src/utils/mac/SkCTFontSmoothBehavior.cpp new file mode 100644 index 00000000000..da516874596 --- /dev/null +++ b/chromium/third_party/skia/src/utils/mac/SkCTFontSmoothBehavior.cpp @@ -0,0 +1,271 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "include/core/SkTypes.h" + +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +#include "src/utils/mac/SkCTFontSmoothBehavior.h" +#include "src/utils/mac/SkUniqueCFRef.h" + +#ifdef SK_BUILD_FOR_MAC +#import <ApplicationServices/ApplicationServices.h> +#endif + +#ifdef SK_BUILD_FOR_IOS +#include <CoreText/CoreText.h> +#include <CoreText/CTFontManager.h> +#include <CoreGraphics/CoreGraphics.h> +#include <CoreFoundation/CoreFoundation.h> +#endif + +static constexpr CGBitmapInfo kBitmapInfoRGB = ((CGBitmapInfo)kCGImageAlphaNoneSkipFirst | + kCGBitmapByteOrder32Host); + +/** Drawn in FontForge, reduced with fonttools ttx, converted by xxd -i, + * this TrueType font contains a glyph of the spider. + * + * To re-forge the original bytes of the TrueType font file, + * remove all ',|( +0x)' from this definition, + * copy the data to the clipboard, + * run 'pbpaste | xxd -p -r - spider.ttf'. + */ +static constexpr const uint8_t kSpiderSymbol_ttf[] = { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x80, 0x00, 0x03, 0x00, 0x40, + 0x47, 0x44, 0x45, 0x46, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x07, 0xa8, + 0x00, 0x00, 0x00, 0x18, 0x4f, 0x53, 0x2f, 0x32, 0x8a, 0xf4, 0xfb, 0xdb, + 0x00, 0x00, 0x01, 0x48, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6d, 0x61, 0x70, + 0xe0, 0x7f, 0x10, 0x7e, 0x00, 0x00, 0x01, 0xb8, 0x00, 0x00, 0x00, 0x54, + 0x67, 0x61, 0x73, 0x70, 0xff, 0xff, 0x00, 0x03, 0x00, 0x00, 0x07, 0xa0, + 0x00, 0x00, 0x00, 0x08, 0x67, 0x6c, 0x79, 0x66, 0x97, 0x0b, 0x6a, 0xf6, + 0x00, 0x00, 0x02, 0x18, 0x00, 0x00, 0x03, 0x40, 0x68, 0x65, 0x61, 0x64, + 0x0f, 0xa2, 0x24, 0x1a, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0x36, + 0x68, 0x68, 0x65, 0x61, 0x0e, 0xd3, 0x07, 0x3f, 0x00, 0x00, 0x01, 0x04, + 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78, 0x10, 0x03, 0x00, 0x44, + 0x00, 0x00, 0x01, 0xa8, 0x00, 0x00, 0x00, 0x0e, 0x6c, 0x6f, 0x63, 0x61, + 0x01, 0xb4, 0x00, 0x28, 0x00, 0x00, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x0a, + 0x6d, 0x61, 0x78, 0x70, 0x00, 0x4a, 0x01, 0x4d, 0x00, 0x00, 0x01, 0x28, + 0x00, 0x00, 0x00, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0xc3, 0xe5, 0x39, 0xd4, + 0x00, 0x00, 0x05, 0x58, 0x00, 0x00, 0x02, 0x28, 0x70, 0x6f, 0x73, 0x74, + 0xff, 0x03, 0x00, 0x67, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x0f, 0x08, 0x1d, + 0x5f, 0x0f, 0x3c, 0xf5, 0x00, 0x0b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd1, 0x97, 0xa8, 0x5a, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xe8, 0x32, 0x33, + 0x00, 0x03, 0xff, 0x3b, 0x08, 0x00, 0x05, 0x55, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x05, 0x55, 0xff, 0x3b, 0x01, 0x79, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x04, 0x01, 0x1c, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x40, 0x00, 0x2e, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x08, 0x00, 0x01, 0x90, 0x00, 0x05, + 0x00, 0x00, 0x05, 0x33, 0x05, 0x99, 0x00, 0x00, 0x01, 0x1e, 0x05, 0x33, + 0x05, 0x99, 0x00, 0x00, 0x03, 0xd7, 0x00, 0x66, 0x02, 0x12, 0x00, 0x00, + 0x05, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x73, 0x6b, 0x69, 0x61, 0x00, 0xc0, 0x00, 0x00, 0xf0, 0x21, + 0x06, 0x66, 0xfe, 0x66, 0x01, 0x79, 0x05, 0x55, 0x00, 0xc5, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x20, 0x00, 0x01, 0x08, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x04, 0x00, 0x48, + 0x00, 0x00, 0x00, 0x0e, 0x00, 0x08, 0x00, 0x02, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x09, 0x00, 0x0d, 0x00, 0x1d, 0x00, 0x21, 0xf0, 0x21, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0d, 0x00, 0x1d, 0x00, 0x21, + 0xf0, 0x21, 0xff, 0xff, 0x00, 0x01, 0xff, 0xf9, 0xff, 0xf5, 0xff, 0xe4, + 0xff, 0xe2, 0x0f, 0xe2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, + 0x00, 0x14, 0x00, 0x14, 0x01, 0xa0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x44, + 0x00, 0x00, 0x02, 0x64, 0x05, 0x55, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, + 0x33, 0x11, 0x21, 0x11, 0x25, 0x21, 0x11, 0x21, 0x44, 0x02, 0x20, 0xfe, + 0x24, 0x01, 0x98, 0xfe, 0x68, 0x05, 0x55, 0xfa, 0xab, 0x44, 0x04, 0xcd, + 0x00, 0x04, 0x00, 0x03, 0xff, 0x3b, 0x08, 0x00, 0x05, 0x4c, 0x00, 0x15, + 0x00, 0x1d, 0x00, 0x25, 0x01, 0x1b, 0x00, 0x00, 0x01, 0x36, 0x37, 0x36, + 0x27, 0x26, 0x07, 0x06, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, 0x26, 0x07, + 0x06, 0x17, 0x16, 0x17, 0x16, 0x32, 0x37, 0x32, 0x35, 0x34, 0x23, 0x22, + 0x15, 0x14, 0x27, 0x32, 0x35, 0x34, 0x23, 0x22, 0x15, 0x14, 0x03, 0x32, + 0x17, 0x30, 0x17, 0x31, 0x36, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x33, + 0x32, 0x33, 0x16, 0x33, 0x32, 0x17, 0x16, 0x07, 0x06, 0x23, 0x22, 0x27, + 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, + 0x1f, 0x02, 0x37, 0x36, 0x37, 0x36, 0x33, 0x32, 0x17, 0x17, 0x16, 0x33, + 0x16, 0x17, 0x16, 0x07, 0x06, 0x23, 0x22, 0x27, 0x27, 0x26, 0x23, 0x22, + 0x07, 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x33, 0x32, 0x33, 0x32, + 0x37, 0x36, 0x37, 0x36, 0x17, 0x16, 0x1f, 0x02, 0x16, 0x17, 0x16, 0x15, + 0x14, 0x23, 0x22, 0x27, 0x27, 0x26, 0x27, 0x27, 0x26, 0x27, 0x26, 0x07, + 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x07, + 0x06, 0x23, 0x22, 0x27, 0x26, 0x07, 0x06, 0x07, 0x06, 0x15, 0x14, 0x17, + 0x16, 0x17, 0x16, 0x15, 0x14, 0x07, 0x06, 0x23, 0x22, 0x27, 0x26, 0x27, + 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x37, 0x34, 0x27, 0x26, 0x07, + 0x06, 0x07, 0x06, 0x0f, 0x02, 0x06, 0x23, 0x22, 0x27, 0x26, 0x35, 0x34, + 0x37, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, + 0x26, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x07, 0x07, 0x06, 0x23, 0x22, + 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x37, 0x36, 0x37, 0x37, 0x36, + 0x37, 0x36, 0x37, 0x36, 0x35, 0x34, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, + 0x23, 0x22, 0x07, 0x06, 0x07, 0x06, 0x07, 0x06, 0x27, 0x26, 0x27, 0x26, + 0x27, 0x26, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, 0x37, 0x36, 0x33, 0x32, + 0x17, 0x16, 0x33, 0x32, 0x37, 0x36, 0x35, 0x34, 0x37, 0x36, 0x37, 0x36, + 0x33, 0x04, 0xf5, 0x23, 0x13, 0x11, 0x14, 0x16, 0x1d, 0x1b, 0x4c, 0x1f, + 0x0e, 0x2d, 0x23, 0x14, 0x2c, 0x13, 0x18, 0x25, 0x2c, 0x10, 0x3c, 0x71, + 0x1d, 0x5c, 0x5c, 0x3f, 0xae, 0x5c, 0x5c, 0x3f, 0x6a, 0x27, 0x31, 0x5b, + 0x09, 0x27, 0x36, 0x03, 0x0a, 0x26, 0x35, 0x2e, 0x09, 0x08, 0xc6, 0x13, + 0x81, 0x17, 0x20, 0x18, 0x21, 0x1e, 0x04, 0x04, 0x15, 0x5c, 0x22, 0x26, + 0x48, 0x56, 0x3b, 0x10, 0x21, 0x01, 0x0c, 0x06, 0x06, 0x0f, 0x31, 0x44, + 0x3c, 0x52, 0x4a, 0x1d, 0x11, 0x3f, 0xb4, 0x71, 0x01, 0x26, 0x06, 0x0d, + 0x15, 0x1a, 0x2a, 0x13, 0x53, 0xaa, 0x42, 0x1d, 0x0a, 0x33, 0x20, 0x21, + 0x2b, 0x01, 0x02, 0x3e, 0x21, 0x09, 0x02, 0x02, 0x0f, 0x2d, 0x4b, 0x0a, + 0x22, 0x15, 0x20, 0x1f, 0x72, 0x8b, 0x2d, 0x2f, 0x1d, 0x1f, 0x0e, 0x25, + 0x3f, 0x4d, 0x1b, 0x63, 0x2a, 0x2c, 0x14, 0x22, 0x18, 0x1c, 0x0f, 0x08, + 0x2a, 0x08, 0x08, 0x0d, 0x3b, 0x4c, 0x52, 0x74, 0x27, 0x71, 0x2e, 0x01, + 0x0c, 0x10, 0x15, 0x0d, 0x06, 0x0d, 0x05, 0x01, 0x06, 0x2c, 0x28, 0x14, + 0x1b, 0x05, 0x04, 0x10, 0x06, 0x12, 0x08, 0x0a, 0x16, 0x27, 0x03, 0x0d, + 0x30, 0x4c, 0x4c, 0x4b, 0x1f, 0x0b, 0x22, 0x26, 0x0d, 0x15, 0x0d, 0x2d, + 0x68, 0x34, 0x14, 0x3c, 0x25, 0x12, 0x04, 0x10, 0x18, 0x0b, 0x09, 0x30, + 0x2b, 0x44, 0x66, 0x14, 0x47, 0x47, 0x59, 0x73, 0x25, 0x05, 0x03, 0x1f, + 0x01, 0x08, 0x3f, 0x48, 0x4b, 0x4b, 0x76, 0x2f, 0x49, 0x2d, 0x22, 0x24, + 0x0c, 0x15, 0x08, 0x0e, 0x33, 0x03, 0x44, 0x4c, 0x10, 0x46, 0x13, 0x1f, + 0x27, 0x1b, 0x1d, 0x13, 0x02, 0x24, 0x08, 0x02, 0x42, 0x0e, 0x4d, 0x3c, + 0x19, 0x1b, 0x40, 0x2b, 0x2b, 0x1e, 0x16, 0x11, 0x04, 0x1f, 0x11, 0x04, + 0x18, 0x11, 0x35, 0x01, 0xa3, 0x13, 0x24, 0x1f, 0x0b, 0x0c, 0x19, 0x19, + 0x18, 0x13, 0x0f, 0x0c, 0x1a, 0x18, 0x1f, 0x19, 0x1e, 0x07, 0x1a, 0xc3, + 0x54, 0x51, 0x54, 0x51, 0x04, 0x53, 0x51, 0x54, 0x50, 0x02, 0x48, 0x1a, + 0x31, 0x18, 0x55, 0x74, 0x04, 0x0e, 0x09, 0x0d, 0x06, 0x10, 0x16, 0x1b, + 0x24, 0x01, 0x04, 0x0b, 0x04, 0x10, 0x3f, 0x0a, 0x41, 0x02, 0x41, 0x20, + 0x06, 0x12, 0x16, 0x21, 0x17, 0x2a, 0x1e, 0x15, 0x40, 0x27, 0x11, 0x0e, + 0x1e, 0x11, 0x15, 0x1f, 0x43, 0x13, 0x1a, 0x10, 0x15, 0x1b, 0x04, 0x09, + 0x4d, 0x2a, 0x0f, 0x19, 0x0a, 0x0a, 0x03, 0x05, 0x15, 0x3c, 0x64, 0x21, + 0x4b, 0x2e, 0x21, 0x28, 0x13, 0x47, 0x44, 0x19, 0x3f, 0x11, 0x18, 0x0b, + 0x0a, 0x07, 0x18, 0x0d, 0x07, 0x24, 0x2c, 0x2b, 0x21, 0x32, 0x10, 0x48, + 0x2a, 0x2d, 0x1e, 0x1a, 0x01, 0x0c, 0x43, 0x59, 0x28, 0x4e, 0x1c, 0x0d, + 0x5d, 0x24, 0x14, 0x0a, 0x05, 0x1f, 0x24, 0x32, 0x46, 0x3e, 0x5f, 0x3e, + 0x44, 0x1a, 0x30, 0x15, 0x0d, 0x07, 0x18, 0x2b, 0x03, 0x0d, 0x1a, 0x28, + 0x28, 0x57, 0xb2, 0x29, 0x27, 0x40, 0x2c, 0x23, 0x16, 0x63, 0x58, 0x1a, + 0x0a, 0x18, 0x11, 0x23, 0x08, 0x1b, 0x29, 0x05, 0x04, 0x0b, 0x15, 0x0d, + 0x14, 0x0b, 0x2a, 0x29, 0x5a, 0x62, 0x01, 0x19, 0x1e, 0x05, 0x05, 0x26, + 0x42, 0x42, 0x2a, 0x2a, 0x3f, 0x0d, 0x0f, 0x09, 0x05, 0x07, 0x01, 0x0b, + 0x25, 0x3e, 0x0d, 0x17, 0x11, 0x01, 0x03, 0x0d, 0x13, 0x20, 0x19, 0x11, + 0x03, 0x02, 0x01, 0x04, 0x11, 0x04, 0x05, 0x1b, 0x3d, 0x10, 0x29, 0x20, + 0x04, 0x04, 0x0a, 0x07, 0x04, 0x1f, 0x15, 0x20, 0x3e, 0x0f, 0x2a, 0x1e, + 0x00, 0x00, 0x00, 0x1b, 0x01, 0x4a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x07, 0x00, 0x27, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x04, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x05, 0x00, 0x02, 0x00, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x0c, 0x00, 0x1b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0d, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0e, 0x00, 0x1a, 0x00, 0x30, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, + 0x00, 0x00, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, + 0x00, 0x01, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, + 0x00, 0x02, 0x00, 0x0e, 0x00, 0x98, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, + 0x00, 0x03, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, + 0x00, 0x04, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, + 0x00, 0x05, 0x00, 0x04, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, + 0x00, 0x06, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, + 0x00, 0x0d, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x00, 0x04, 0x09, + 0x00, 0x0e, 0x00, 0x34, 0x00, 0xaa, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x00, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x01, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x02, 0x00, 0x0e, 0x00, 0x98, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x03, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x04, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x05, 0x00, 0x04, 0x00, 0xa6, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x06, 0x00, 0x18, 0x00, 0x80, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x0d, 0x00, 0x36, 0x00, 0x4a, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, + 0x00, 0x0e, 0x00, 0x34, 0x00, 0xaa, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, + 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x31, 0x35, + 0x2c, 0x20, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x53, 0x70, 0x69, + 0x64, 0x65, 0x72, 0x53, 0x79, 0x6d, 0x62, 0x6f, 0x6c, 0x52, 0x65, 0x67, + 0x75, 0x6c, 0x61, 0x72, 0x56, 0x31, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, + 0x2f, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x2e, 0x73, 0x69, 0x6c, + 0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x4f, 0x46, 0x4c, 0x00, 0x43, 0x00, 0x6f, + 0x00, 0x70, 0x00, 0x79, 0x00, 0x72, 0x00, 0x69, 0x00, 0x67, 0x00, 0x68, + 0x00, 0x74, 0x00, 0x20, 0x00, 0x28, 0x00, 0x63, 0x00, 0x29, 0x00, 0x20, + 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x35, 0x00, 0x2c, 0x00, 0x20, + 0x00, 0x47, 0x00, 0x6f, 0x00, 0x6f, 0x00, 0x67, 0x00, 0x6c, 0x00, 0x65, + 0x00, 0x2e, 0x00, 0x53, 0x00, 0x70, 0x00, 0x69, 0x00, 0x64, 0x00, 0x65, + 0x00, 0x72, 0x00, 0x53, 0x00, 0x79, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x6f, + 0x00, 0x6c, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00, 0x6c, + 0x00, 0x61, 0x00, 0x72, 0x00, 0x56, 0x00, 0x31, 0x00, 0x68, 0x00, 0x74, + 0x00, 0x74, 0x00, 0x70, 0x00, 0x3a, 0x00, 0x2f, 0x00, 0x2f, 0x00, 0x73, + 0x00, 0x63, 0x00, 0x72, 0x00, 0x69, 0x00, 0x70, 0x00, 0x74, 0x00, 0x73, + 0x00, 0x2e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6c, 0x00, 0x2e, 0x00, 0x6f, + 0x00, 0x72, 0x00, 0x67, 0x00, 0x2f, 0x00, 0x4f, 0x00, 0x46, 0x00, 0x4c, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x66, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0xff, 0xff, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x0c, 0x00, 0x14, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00 +}; + +/** + * There does not appear to be a publicly accessible API for determining if lcd + * font smoothing will be applied if we request it. The main issue is that if + * smoothing is applied a gamma of 2.0 will be used, if not a gamma of 1.0. + */ +SkCTFontSmoothBehavior SkCTFontGetSmoothBehavior() { + static SkCTFontSmoothBehavior gSmoothBehavior = []{ + uint32_t noSmoothBitmap[16][16] = {}; + uint32_t smoothBitmap[16][16] = {}; + + SkUniqueCFRef<CGColorSpaceRef> colorspace(CGColorSpaceCreateDeviceRGB()); + SkUniqueCFRef<CGContextRef> noSmoothContext( + CGBitmapContextCreate(&noSmoothBitmap, 16, 16, 8, 16*4, + colorspace.get(), kBitmapInfoRGB)); + SkUniqueCFRef<CGContextRef> smoothContext( + CGBitmapContextCreate(&smoothBitmap, 16, 16, 8, 16*4, + colorspace.get(), kBitmapInfoRGB)); + + SkUniqueCFRef<CFDataRef> data(CFDataCreateWithBytesNoCopy( + kCFAllocatorDefault, kSpiderSymbol_ttf, SK_ARRAY_COUNT(kSpiderSymbol_ttf), + kCFAllocatorNull)); + SkUniqueCFRef<CTFontDescriptorRef> desc( + CTFontManagerCreateFontDescriptorFromData(data.get())); + SkUniqueCFRef<CTFontRef> ctFont(CTFontCreateWithFontDescriptor(desc.get(), 16, nullptr)); + SkASSERT(ctFont); + + CGContextSetShouldSmoothFonts(noSmoothContext.get(), false); + CGContextSetShouldAntialias(noSmoothContext.get(), true); + CGContextSetTextDrawingMode(noSmoothContext.get(), kCGTextFill); + CGContextSetGrayFillColor(noSmoothContext.get(), 1, 1); + + CGContextSetShouldSmoothFonts(smoothContext.get(), true); + CGContextSetShouldAntialias(smoothContext.get(), true); + CGContextSetTextDrawingMode(smoothContext.get(), kCGTextFill); + CGContextSetGrayFillColor(smoothContext.get(), 1, 1); + + CGPoint point = CGPointMake(0, 3); + CGGlyph spiderGlyph = 3; + CTFontDrawGlyphs(ctFont.get(), &spiderGlyph, &point, 1, noSmoothContext.get()); + CTFontDrawGlyphs(ctFont.get(), &spiderGlyph, &point, 1, smoothContext.get()); + + // For debugging. + //SkUniqueCFRef<CGImageRef> image(CGBitmapContextCreateImage(noSmoothContext())); + //SkUniqueCFRef<CGImageRef> image(CGBitmapContextCreateImage(smoothContext())); + + SkCTFontSmoothBehavior smoothBehavior = SkCTFontSmoothBehavior::none; + for (int x = 0; x < 16; ++x) { + for (int y = 0; y < 16; ++y) { + uint32_t smoothPixel = smoothBitmap[x][y]; + uint32_t r = (smoothPixel >> 16) & 0xFF; + uint32_t g = (smoothPixel >> 8) & 0xFF; + uint32_t b = (smoothPixel >> 0) & 0xFF; + if (r != g || r != b) { + return SkCTFontSmoothBehavior::subpixel; + } + if (noSmoothBitmap[x][y] != smoothPixel) { + smoothBehavior = SkCTFontSmoothBehavior::some; + } + } + } + return smoothBehavior; + }(); + return gSmoothBehavior; +} + +#endif diff --git a/chromium/third_party/skia/src/utils/mac/SkCTFontSmoothBehavior.h b/chromium/third_party/skia/src/utils/mac/SkCTFontSmoothBehavior.h new file mode 100644 index 00000000000..126cdb3ab2d --- /dev/null +++ b/chromium/third_party/skia/src/utils/mac/SkCTFontSmoothBehavior.h @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkCTFontSmoothBehavior_DEFINED +#define SkCTFontSmoothBehavior_DEFINED + +#include "include/core/SkTypes.h" +#if defined(SK_BUILD_FOR_MAC) || defined(SK_BUILD_FOR_IOS) + +enum class SkCTFontSmoothBehavior { + none, // SmoothFonts produces no effect. + some, // SmoothFonts produces some effect, but not subpixel coverage. + subpixel, // SmoothFonts produces some effect and provides subpixel coverage. +}; + +SkCTFontSmoothBehavior SkCTFontGetSmoothBehavior(); + +#endif +#endif // SkCTFontSmoothBehavior_DEFINED diff --git a/chromium/third_party/skia/src/utils/mac/SkStream_mac.cpp b/chromium/third_party/skia/src/utils/mac/SkStream_mac.cpp deleted file mode 100644 index b299fced492..00000000000 --- a/chromium/third_party/skia/src/utils/mac/SkStream_mac.cpp +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2012 Google Inc. - * - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -// Remove file after it is removed from downstream builds. diff --git a/chromium/third_party/skia/src/xps/SkXPSDevice.cpp b/chromium/third_party/skia/src/xps/SkXPSDevice.cpp index e9f045cc855..ec4ba68fc03 100644 --- a/chromium/third_party/skia/src/xps/SkXPSDevice.cpp +++ b/chromium/third_party/skia/src/xps/SkXPSDevice.cpp @@ -116,7 +116,7 @@ HRESULT SkXPSDevice::createId(wchar_t* buffer, size_t bufferSize, wchar_t sep) { SkXPSDevice::SkXPSDevice(SkISize s) : INHERITED(SkImageInfo::MakeUnknown(s.width(), s.height()), SkSurfaceProps(0, kUnknown_SkPixelGeometry)) - , fCurrentPage(0) {} + , fCurrentPage(0), fTopTypefaces(&fTypefaces) {} SkXPSDevice::~SkXPSDevice() {} @@ -414,7 +414,7 @@ static HRESULT subset_typeface(const SkXPSDevice::TypefaceUse& current) { bool SkXPSDevice::endPortfolio() { //Subset fonts - for (const TypefaceUse& current : this->fTypefaces) { + for (const TypefaceUse& current : *this->fTopTypefaces) { //Ignore return for now, if it didn't subset, let it be. subset_typeface(current); } @@ -1632,7 +1632,7 @@ void SkXPSDevice::drawPath(const SkPath& platonicPath, return; } } - // The xpsCompatiblePath is now inverse even odd, so fall through. + [[fallthrough]]; // The xpsCompatiblePath is now inverse even odd, so fall through. case SkPathFillType::kInverseEvenOdd: { const SkRect universe = SkRect::MakeLTRB( 0, 0, @@ -1726,7 +1726,7 @@ HRESULT SkXPSDevice::CreateTypefaceUse(const SkFont& font, //Check cache. const SkFontID typefaceID = typeface->uniqueID(); - for (TypefaceUse& current : this->fTypefaces) { + for (TypefaceUse& current : *this->fTopTypefaces) { if (current.typefaceId == typefaceID) { *typefaceUse = ¤t; return S_OK; @@ -1774,7 +1774,7 @@ HRESULT SkXPSDevice::CreateTypefaceUse(const SkFont& font, int glyphCount = typeface->countGlyphs(); - TypefaceUse& newTypefaceUse = this->fTypefaces.emplace_back( + TypefaceUse& newTypefaceUse = this->fTopTypefaces->emplace_back( typefaceID, isTTC ? ttcIndex : -1, std::move(fontData), @@ -1954,10 +1954,11 @@ void SkXPSDevice::drawGlyphRunList(const SkGlyphRunList& glyphRunList) { } } -void SkXPSDevice::drawDevice( SkBaseDevice* dev, +void SkXPSDevice::drawDevice(SkBaseDevice* dev, int x, int y, const SkPaint&) { SkXPSDevice* that = static_cast<SkXPSDevice*>(dev); + SkASSERT(that->fTopTypefaces == this->fTopTypefaces); SkTScopedComPtr<IXpsOMMatrixTransform> xpsTransform; // TODO(halcanary): assert that current transform is identity rather than calling setter. @@ -1988,8 +1989,11 @@ SkBaseDevice* SkXPSDevice::onCreateDevice(const CreateInfo& info, const SkPaint* } #endif SkXPSDevice* dev = new SkXPSDevice(info.fInfo.dimensions()); - // TODO(halcanary) implement copy constructor on SkTScopedCOmPtr dev->fXpsFactory.reset(SkRefComPtr(fXpsFactory.get())); + dev->fCurrentCanvasSize = this->fCurrentCanvasSize; + dev->fCurrentUnitsPerMeter = this->fCurrentUnitsPerMeter; + dev->fCurrentPixelsPerMeter = this->fCurrentPixelsPerMeter; + dev->fTopTypefaces = this->fTopTypefaces; SkAssertResult(dev->createCanvasForLayer()); return dev; } diff --git a/chromium/third_party/skia/src/xps/SkXPSDevice.h b/chromium/third_party/skia/src/xps/SkXPSDevice.h index c0e6679c48c..0dcbb9b079a 100644 --- a/chromium/third_party/skia/src/xps/SkXPSDevice.h +++ b/chromium/third_party/skia/src/xps/SkXPSDevice.h @@ -125,6 +125,7 @@ private: SkVector fCurrentPixelsPerMeter; SkTArray<TypefaceUse, true> fTypefaces; + SkTArray<TypefaceUse, true>* fTopTypefaces; /** Creates a GUID based id and places it into buffer. buffer should have space for at least GUID_ID_LEN wide characters. |