/* * 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 GrSurfaceFillContext_DEFINED #define GrSurfaceFillContext_DEFINED #include "include/core/SkSize.h" #include "include/private/GrTypesPriv.h" #include "src/gpu/GrImageInfo.h" #include "src/gpu/GrOpsTask.h" #include "src/gpu/GrSurfaceContext.h" #include "src/gpu/GrSwizzle.h" #include "src/gpu/effects/GrMatrixEffect.h" #include #include class GrFragmentProcessor; class GrImageContext; class GrOp; class GrBackendFormat; class GrRecordingContext; class GrSurfaceProxyView; class SkColorSpace; class GrSurfaceFillContext : public GrSurfaceContext { public: /** * Checks whether the passed color type is renderable with the passed context. If so, the * same color type is passed back along with the default format used for the color type. If * not, provides an alternative (perhaps lower bit depth and/or unorm instead of float) color * type that is supported along with it's default format or kUnknown if there no renderable * fallback format. */ static std::tuple GetFallbackColorTypeAndFormat(GrImageContext*, GrColorType, int sampleCount); GrSurfaceFillContext(GrRecordingContext*, GrSurfaceProxyView readView, GrSurfaceProxyView writeView, const GrColorInfo&, bool flushTimeOpsTask = false); /** * Uses GrImageInfo's color type to pick the default texture format. Will return a * GrSurfaceDrawContext if possible. */ static std::unique_ptr Make(GrRecordingContext*, GrImageInfo, SkBackingFit = SkBackingFit::kExact, int sampleCount = 1, GrMipmapped = GrMipmapped::kNo, GrProtected = GrProtected::kNo, GrSurfaceOrigin = kTopLeft_GrSurfaceOrigin, SkBudgeted = SkBudgeted::kYes); /** * Like the above but uses GetFallbackColorTypeAndFormat to find a fallback color type (and * compatible format) if the passed GrImageInfo's color type is not renderable. */ static std::unique_ptr MakeWithFallback( GrRecordingContext*, GrImageInfo, SkBackingFit = SkBackingFit::kExact, int sampleCount = 1, GrMipmapped = GrMipmapped::kNo, GrProtected = GrProtected::kNo, GrSurfaceOrigin = kTopLeft_GrSurfaceOrigin, SkBudgeted = SkBudgeted::kYes); /** * Makes a custom configured GrSurfaceFillContext where the caller specifies the specific * texture format and swizzles. The color type will be kUnknown. Returns a GrSurfaceDrawContext * if possible. */ static std::unique_ptr Make(GrRecordingContext*, SkAlphaType, sk_sp, SkISize dimensions, SkBackingFit, const GrBackendFormat&, int sampleCount, GrMipmapped, GrProtected, GrSwizzle readSwizzle, GrSwizzle writeSwizzle, GrSurfaceOrigin, SkBudgeted); /** * Creates a GrSurfaceFillContext from an existing GrBackendTexture. The GrColorInfo's color * type must be compatible with backend texture's format or this will fail. All formats are * considered compatible with kUnknown. Returns a GrSurfaceDrawContext if possible. */ static std::unique_ptr MakeFromBackendTexture( GrRecordingContext*, GrColorInfo, const GrBackendTexture&, int sampleCount, GrSurfaceOrigin, sk_sp releaseHelper); GrSurfaceFillContext* asFillContext() override { return this; } /** * Provides a performance hint that the render target's contents are allowed * to become undefined. */ void discard(); /** * 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. */ template void clear(const SkIRect& rect, const SkRGBA4f& color) { this->internalClear(&rect, this->adjustColorAlphaType(color)); } /** Clears the entire render target to the color. */ template void clear(const SkRGBA4f& color) { this->internalClear(nullptr, this->adjustColorAlphaType(color)); } /** * Clear at minimum the pixels within 'scissor', but is allowed to clear the full render target * if that is the more performant option. */ template void clearAtLeast(const SkIRect& scissor, const SkRGBA4f& color) { this->internalClear(&scissor, this->adjustColorAlphaType(color), /* upgrade to full */ true); } /** Fills 'dstRect' with 'fp' */ void fillRectWithFP(const SkIRect& dstRect, std::unique_ptr fp); /** * A convenience version of fillRectWithFP that applies a coordinate transformation via * GrMatrixEffect. */ void fillRectWithFP(const SkIRect& dstRect, const SkMatrix& localMatrix, std::unique_ptr fp) { fp = GrMatrixEffect::Make(localMatrix, std::move(fp)); this->fillRectWithFP(dstRect, std::move(fp)); } /** Fills 'dstRect' with 'fp' using a local matrix that maps 'srcRect' to 'dstRect' */ void fillRectToRectWithFP(const SkRect& srcRect, const SkIRect& dstRect, std::unique_ptr fp) { SkMatrix lm = SkMatrix::RectToRect(SkRect::Make(dstRect), srcRect); this->fillRectWithFP(dstRect, lm, std::move(fp)); } /** Fills 'dstRect' with 'fp' using a local matrix that maps 'srcRect' to 'dstRect' */ void fillRectToRectWithFP(const SkIRect& srcRect, const SkIRect& dstRect, std::unique_ptr fp) { this->fillRectToRectWithFP(SkRect::Make(srcRect), dstRect, std::move(fp)); } /** Fills the entire render target with the passed FP. */ void fillWithFP(std::unique_ptr fp) { this->fillRectWithFP(SkIRect::MakeSize(fWriteView.proxy()->dimensions()), std::move(fp)); } /** * A convenience version of fillWithFP that applies a coordinate transformation via * GrMatrixEffect and fills the entire render target. */ void fillWithFP(const SkMatrix& localMatrix, std::unique_ptr fp) { this->fillRectWithFP( SkIRect::MakeSize(fWriteView.proxy()->dimensions()), localMatrix, std::move(fp)); } /** * Draws the src texture with no matrix. The dstRect is the dstPoint with the width and height * of the srcRect. The srcRect and dstRect are clipped to the bounds of the src and dst surfaces * respectively. */ bool blitTexture(GrSurfaceProxyView view, const SkIRect& srcRect, const SkIPoint& dstPoint); GrOpsTask* getOpsTask(); int numSamples() const { return this->asRenderTargetProxy()->numSamples(); } bool wrapsVkSecondaryCB() const { return this->asRenderTargetProxy()->wrapsVkSecondaryCB(); } GrMipmapped mipmapped() const; SkArenaAlloc* arenaAlloc() { return this->arenas()->arenaAlloc(); } GrSubRunAllocator* subRunAlloc() { return this->arenas()->subRunAlloc(); } #if GR_TEST_UTILS GrOpsTask* testingOnly_PeekLastOpsTask() { return fOpsTask.get(); } #endif const GrSurfaceProxyView& writeSurfaceView() const { return fWriteView; } protected: /** * Creates a constant color paint for a clear, using src-over if possible to improve batching. */ static void ClearToGrPaint(std::array color, GrPaint* paint); void addOp(GrOp::Owner); private: sk_sp arenas() { return fWriteView.proxy()->asRenderTargetProxy()->arenas(); } template static std::array ConvertColor(SkRGBA4f color); template std::array adjustColorAlphaType(SkRGBA4f color) const; /** Override to be notified in subclass before the current ops task is replaced. */ virtual void willReplaceOpsTask(GrOpsTask* prevTask, GrOpsTask* nextTask) {} /** * Override to be called to participate in the decision to discard all previous ops if a * fullscreen clear occurs. */ virtual GrOpsTask::CanDiscardPreviousOps canDiscardPreviousOpsOnFullClear() const { return GrOpsTask::CanDiscardPreviousOps::kYes; } void internalClear(const SkIRect* scissor, std::array color, bool upgradePartialToFull = false); void addDrawOp(GrOp::Owner); SkDEBUGCODE(void onValidate() const override;) GrSurfaceProxyView fWriteView; // The GrOpsTask can be closed by some other surface context that has picked it up. For this // reason, the GrOpsTask should only ever be accessed via 'getOpsTask'. sk_sp fOpsTask; bool fFlushTimeOpsTask; using INHERITED = GrSurfaceContext; }; template<> inline std::array GrSurfaceFillContext::ConvertColor( SkPMColor4f color) { return color.unpremul().array(); } template<> inline std::array GrSurfaceFillContext::ConvertColor( SkColor4f color) { return color.premul().array(); } template std::array GrSurfaceFillContext::adjustColorAlphaType(SkRGBA4f color) const { if (AlphaType == kUnknown_SkAlphaType || this->colorInfo().alphaType() == kUnknown_SkAlphaType) { return color.array(); } return (AlphaType == this->colorInfo().alphaType()) ? color.array() : ConvertColor(color); } #endif