/* * Copyright 2021 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SurfaceFillContext_DEFINED #define SurfaceFillContext_DEFINED #include "include/core/SkAlphaType.h" #include "include/core/SkColor.h" #include "include/core/SkMatrix.h" #include "include/core/SkRect.h" #include "include/core/SkRefCnt.h" #include "include/private/SkColorData.h" #include "include/private/base/SkDebug.h" #include "src/gpu/ganesh/GrColorInfo.h" #include "src/gpu/ganesh/GrFragmentProcessor.h" #include "src/gpu/ganesh/GrRenderTargetProxy.h" #include "src/gpu/ganesh/GrSurfaceProxy.h" #include "src/gpu/ganesh/GrSurfaceProxyView.h" #include "src/gpu/ganesh/SurfaceContext.h" #include "src/gpu/ganesh/ops/GrOp.h" #include "src/gpu/ganesh/ops/OpsTask.h" #include #include #include class GrPaint; class GrRecordingContext; class GrRenderTask; class SkArenaAlloc; struct SkIPoint; namespace sktext::gpu { class SubRunAllocator; } namespace skgpu::ganesh { class SurfaceFillContext : public SurfaceContext { public: SurfaceFillContext(GrRecordingContext* rContext, GrSurfaceProxyView readView, GrSurfaceProxyView writeView, const GrColorInfo& colorInfo); SurfaceFillContext* asFillContext() override { return this; } OpsTask* getOpsTask(); #if defined(GPU_TEST_UTILS) OpsTask* testingOnly_PeekLastOpsTask() { return fOpsTask.get(); } #endif /** * Provides a performance hint that the render target's contents are allowed * to become undefined. */ void discard(); void resolveMSAA(); /** * 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); /** * A convenience version of fillRectWithFP that applies a coordinate transformation via * GrMatrixEffect. */ void fillRectWithFP(const SkIRect& dstRect, const SkMatrix& localMatrix, std::unique_ptr); /** 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)); } /** * 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, const SkIRect& srcRect, const SkIPoint& dstPoint); sk_sp refRenderTask(); int numSamples() const { return this->asRenderTargetProxy()->numSamples(); } bool wrapsVkSecondaryCB() const { return this->asRenderTargetProxy()->wrapsVkSecondaryCB(); } SkArenaAlloc* arenaAlloc() { return this->arenas()->arenaAlloc(); } sktext::gpu::SubRunAllocator* subRunAlloc() { return this->arenas()->subRunAlloc(); } const GrSurfaceProxyView& writeSurfaceView() const { return fWriteView; } protected: OpsTask* replaceOpsTask(); /** * 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); template static std::array ConvertColor(SkRGBA4f color); template std::array adjustColorAlphaType(SkRGBA4f color) const; GrSurfaceProxyView fWriteView; private: sk_sp arenas() { return fWriteView.proxy()->asRenderTargetProxy()->arenas(); } void addDrawOp(GrOp::Owner); /** Override to be notified in subclass before the current ops task is replaced. */ virtual void willReplaceOpsTask(OpsTask* prevTask, OpsTask* nextTask) {} /** * Override to be called to participate in the decision to discard all previous ops if a * fullscreen clear occurs. */ virtual OpsTask::CanDiscardPreviousOps canDiscardPreviousOpsOnFullClear() const { return OpsTask::CanDiscardPreviousOps::kYes; } void internalClear(const SkIRect* scissor, std::array color, bool upgradePartialToFull = false); SkDEBUGCODE(void onValidate() const override;) // The OpsTask can be closed by some other surface context that has picked it up. For this // reason, the OpsTask should only ever be accessed via 'getOpsTask'. sk_sp fOpsTask; using INHERITED = SurfaceContext; }; template<> inline std::array SurfaceFillContext::ConvertColor( SkPMColor4f color) { return color.unpremul().array(); } template<> inline std::array SurfaceFillContext::ConvertColor( SkColor4f color) { return color.premul().array(); } template std::array SurfaceFillContext::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); } } // namespace skgpu::ganesh #endif // SurfaceFillContext_DEFINED