Handle color and stencil clears in GrClearOp

With prior changes, it became "clear" that GrClearOp and
GrClearStencilClipOp behaved very similarly, except that the stencil
op did not have any onCombine logic.

This just combines them in to a single clear op that will call the
render pass's clear and stencil clear functions as needed. I also
implemented combine logic to apply color and stencil clears in a single
op if the scissor state was compatible (although there's no render pass
API to combine the two clears into a single GPU function).

Change-Id: I8aa749fe64cc487d187854fd0acf6b03b86f1356
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/290822
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Chris Dalton <csmartdalton@google.com>
This commit is contained in:
Michael Ludwig 2020-06-08 09:30:09 -04:00 committed by Skia Commit-Bot
parent be20205787
commit 9cced93b7a
6 changed files with 86 additions and 135 deletions

View File

@ -368,8 +368,6 @@ skia_gpu_sources = [
"$_src/gpu/ops/GrAtlasTextOp.h", "$_src/gpu/ops/GrAtlasTextOp.h",
"$_src/gpu/ops/GrClearOp.cpp", "$_src/gpu/ops/GrClearOp.cpp",
"$_src/gpu/ops/GrClearOp.h", "$_src/gpu/ops/GrClearOp.h",
"$_src/gpu/ops/GrClearStencilClipOp.cpp",
"$_src/gpu/ops/GrClearStencilClipOp.h",
"$_src/gpu/ops/GrDashLinePathRenderer.cpp", "$_src/gpu/ops/GrDashLinePathRenderer.cpp",
"$_src/gpu/ops/GrDashLinePathRenderer.h", "$_src/gpu/ops/GrDashLinePathRenderer.h",
"$_src/gpu/ops/GrDashOp.cpp", "$_src/gpu/ops/GrDashOp.cpp",

View File

@ -55,7 +55,6 @@
#include "src/gpu/geometry/GrStyledShape.h" #include "src/gpu/geometry/GrStyledShape.h"
#include "src/gpu/ops/GrAtlasTextOp.h" #include "src/gpu/ops/GrAtlasTextOp.h"
#include "src/gpu/ops/GrClearOp.h" #include "src/gpu/ops/GrClearOp.h"
#include "src/gpu/ops/GrClearStencilClipOp.h"
#include "src/gpu/ops/GrDrawAtlasOp.h" #include "src/gpu/ops/GrDrawAtlasOp.h"
#include "src/gpu/ops/GrDrawOp.h" #include "src/gpu/ops/GrDrawOp.h"
#include "src/gpu/ops/GrDrawVerticesOp.h" #include "src/gpu/ops/GrDrawVerticesOp.h"
@ -553,7 +552,7 @@ void GrRenderTargetContext::internalClear(const SkIRect* scissor,
GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(), GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
SkRect::Make(scissorState.rect()))); SkRect::Make(scissorState.rect())));
} else { } else {
this->addOp(GrClearOp::Make(fContext, scissorState, color)); this->addOp(GrClearOp::MakeColor(fContext, scissorState, color));
} }
} }
@ -959,7 +958,7 @@ void GrRenderTargetContext::internalStencilClear(const SkIRect* scissor, bool in
GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(), GrFillRectOp::MakeNonAARect(fContext, std::move(paint), SkMatrix::I(),
SkRect::Make(scissorState.rect()), ss)); SkRect::Make(scissorState.rect()), ss));
} else { } else {
this->addOp(GrClearStencilClipOp::Make(fContext, scissorState, insideStencilMask)); this->addOp(GrClearOp::MakeStencilClip(fContext, scissorState, insideStencilMask));
} }
} }

View File

@ -14,21 +14,74 @@
#include "src/gpu/GrProxyProvider.h" #include "src/gpu/GrProxyProvider.h"
#include "src/gpu/GrRecordingContextPriv.h" #include "src/gpu/GrRecordingContextPriv.h"
std::unique_ptr<GrClearOp> GrClearOp::Make(GrRecordingContext* context, static bool contains_scissor(const GrScissorState& a, const GrScissorState& b) {
const GrScissorState& scissor, return !a.enabled() || (b.enabled() && a.rect().contains(b.rect()));
const SkPMColor4f& color) {
GrOpMemoryPool* pool = context->priv().opMemoryPool();
return pool->allocate<GrClearOp>(scissor, color);
} }
GrClearOp::GrClearOp(const GrScissorState& scissor, const SkPMColor4f& color) std::unique_ptr<GrClearOp> GrClearOp::MakeColor(GrRecordingContext* context,
const GrScissorState& scissor,
const SkPMColor4f& color) {
GrOpMemoryPool* pool = context->priv().opMemoryPool();
return pool->allocate<GrClearOp>(Buffer::kColor, scissor, color, false);
}
std::unique_ptr<GrClearOp> GrClearOp::MakeStencilClip(GrRecordingContext* context,
const GrScissorState& scissor,
bool insideMask) {
GrOpMemoryPool* pool = context->priv().opMemoryPool();
return pool->allocate<GrClearOp>(Buffer::kStencilClip, scissor, SkPMColor4f(), insideMask);
}
GrClearOp::GrClearOp(Buffer buffer, const GrScissorState& scissor,
const SkPMColor4f& color, bool insideMask)
: INHERITED(ClassID()) : INHERITED(ClassID())
, fScissor(scissor) , fScissor(scissor)
, fColor(color) { , fColor(color)
, fStencilInsideMask(insideMask)
, fBuffer(buffer) {
this->setBounds(SkRect::Make(scissor.rect()), HasAABloat::kNo, IsHairline::kNo); this->setBounds(SkRect::Make(scissor.rect()), HasAABloat::kNo, IsHairline::kNo);
} }
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;
}
return CombineResult::kCannotCombine;
}
void GrClearOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) { void GrClearOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {
SkASSERT(state->opsRenderPass()); SkASSERT(state->opsRenderPass());
state->opsRenderPass()->clear(fScissor, fColor); if (fBuffer & Buffer::kColor) {
state->opsRenderPass()->clear(fScissor, fColor);
}
if (fBuffer & Buffer::kStencilClip) {
state->opsRenderPass()->clearStencilClip(fScissor, fStencilInsideMask);
}
} }

View File

@ -8,6 +8,7 @@
#ifndef GrClearOp_DEFINED #ifndef GrClearOp_DEFINED
#define GrClearOp_DEFINED #define GrClearOp_DEFINED
#include "include/gpu/GrTypes.h"
#include "src/gpu/GrScissorState.h" #include "src/gpu/GrScissorState.h"
#include "src/gpu/ops/GrOp.h" #include "src/gpu/ops/GrOp.h"
@ -19,9 +20,13 @@ public:
DEFINE_OP_CLASS_ID DEFINE_OP_CLASS_ID
// A fullscreen or scissored clear, depending on the clip and proxy dimensions // A fullscreen or scissored clear, depending on the clip and proxy dimensions
static std::unique_ptr<GrClearOp> Make(GrRecordingContext* context, static std::unique_ptr<GrClearOp> MakeColor(GrRecordingContext* context,
const GrScissorState& scissor, const GrScissorState& scissor,
const SkPMColor4f& color); const SkPMColor4f& color);
static std::unique_ptr<GrClearOp> MakeStencilClip(GrRecordingContext* context,
const GrScissorState& scissor,
bool insideMask);
const char* name() const override { return "Clear"; } const char* name() const override { return "Clear"; }
@ -44,33 +49,20 @@ public:
private: private:
friend class GrOpMemoryPool; // for ctors friend class GrOpMemoryPool; // for ctors
GrClearOp(const GrScissorState& scissor, const SkPMColor4f& color); enum class Buffer {
kColor = 0b01,
kStencilClip = 0b10,
kBoth = 0b11,
};
GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(Buffer);
GrClearOp(Buffer buffer, const GrScissorState& scissor, const SkPMColor4f& color, bool stencil);
CombineResult onCombineIfPossible(GrOp* t, GrRecordingContext::Arenas*, CombineResult onCombineIfPossible(GrOp* t, GrRecordingContext::Arenas*,
const GrCaps& caps) override { 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 (cb->contains(this)) {
fScissor = cb->fScissor;
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 { void onPrePrepare(GrRecordingContext*, const GrSurfaceProxyView* writeView, GrAppliedClip*,
// The constructor ensures that scissor gets disabled on any clip that fills the entire RT.
return !fScissor.enabled() ||
(that->fScissor.enabled() && fScissor.rect().contains(that->fScissor.rect()));
}
void onPrePrepare(GrRecordingContext*,
const GrSurfaceProxyView* writeView,
GrAppliedClip*,
const GrXferProcessor::DstProxyView&) override {} const GrXferProcessor::DstProxyView&) override {}
void onPrepare(GrOpFlushState*) override {} void onPrepare(GrOpFlushState*) override {}
@ -79,8 +71,12 @@ private:
GrScissorState fScissor; GrScissorState fScissor;
SkPMColor4f fColor; SkPMColor4f fColor;
bool fStencilInsideMask;
Buffer fBuffer;
typedef GrOp INHERITED; typedef GrOp INHERITED;
}; };
GR_MAKE_BITFIELD_CLASS_OPS(GrClearOp::Buffer)
#endif #endif

View File

@ -1,27 +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 GrScissorState& scissor,
bool insideStencilMask) {
GrOpMemoryPool* pool = context->priv().opMemoryPool();
return pool->allocate<GrClearStencilClipOp>(scissor, insideStencilMask);
}
void GrClearStencilClipOp::onExecute(GrOpFlushState* state, const SkRect& chainBounds) {
SkASSERT(state->opsRenderPass());
state->opsRenderPass()->clearStencilClip(fScissor, fInsideStencilMask);
}

View File

@ -1,68 +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/GrRenderTargetProxy.h"
#include "src/gpu/GrScissorState.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 GrScissorState& scissor,
bool insideStencilMask);
const char* name() const override { return "ClearStencilClip"; }
#ifdef SK_DEBUG
SkString dumpInfo() const override {
SkString string("Scissor [");
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");
}
string.appendf("], insideMask: %s\n", fInsideStencilMask ? "true" : "false");
string.append(INHERITED::dumpInfo());
return string;
}
#endif
private:
friend class GrOpMemoryPool; // for ctor
GrClearStencilClipOp(const GrScissorState& scissor, bool insideStencilMask)
: INHERITED(ClassID())
, fScissor(scissor)
, fInsideStencilMask(insideStencilMask) {
this->setBounds(SkRect::Make(scissor.rect()), 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 GrScissorState fScissor;
const bool fInsideStencilMask;
typedef GrOp INHERITED;
};
#endif