Add a "conservative raster" flag for GrFillRectOp
Adds the ability to fill a rect with conservative raster enabled, and
fixes a bug in the gpu tessellation atlas where there were artifacts
from mixed samples.
Change-Id: Ic0b4f2059129ac238fdcb08d43896fc2b9e50211
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/269989
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/ops/GrFillRectOp.cpp b/src/gpu/ops/GrFillRectOp.cpp
index d522621..d63b312 100644
--- a/src/gpu/ops/GrFillRectOp.cpp
+++ b/src/gpu/ops/GrFillRectOp.cpp
@@ -21,7 +21,6 @@
#include "src/gpu/glsl/GrGLSLVarying.h"
#include "src/gpu/ops/GrMeshDrawOp.h"
#include "src/gpu/ops/GrQuadPerEdgeAA.h"
-#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
namespace {
@@ -65,20 +64,21 @@
GrPaint&& paint,
GrAAType aaType,
DrawQuad* quad,
- const GrUserStencilSettings* stencilSettings) {
+ const GrUserStencilSettings* stencilSettings,
+ Helper::InputFlags inputFlags) {
// Clean up deviations between aaType and edgeAA
GrQuadUtils::ResolveAAType(aaType, quad->fEdgeFlags, quad->fDevice,
&aaType, &quad->fEdgeFlags);
return Helper::FactoryHelper<FillRectOp>(context, std::move(paint), aaType, quad,
- stencilSettings);
+ stencilSettings, inputFlags);
}
// aaType is passed to Helper in the initializer list, so incongruities between aaType and
// edgeFlags must be resolved prior to calling this constructor.
FillRectOp(Helper::MakeArgs args, SkPMColor4f paintColor, GrAAType aaType,
- DrawQuad* quad, const GrUserStencilSettings* stencil)
+ DrawQuad* quad, const GrUserStencilSettings* stencil, Helper::InputFlags inputFlags)
: INHERITED(ClassID())
- , fHelper(args, aaType, stencil)
+ , fHelper(args, aaType, stencil, inputFlags)
, fQuads(1, !fHelper.isTrivial()) {
// 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).
@@ -425,8 +425,10 @@
GrPaint&& paint,
GrAAType aaType,
DrawQuad* quad,
- const GrUserStencilSettings* stencil) {
- return FillRectOp::Make(context, std::move(paint), aaType, std::move(quad), stencil);
+ const GrUserStencilSettings* stencil,
+ InputFlags inputFlags) {
+ return FillRectOp::Make(context, std::move(paint), aaType, std::move(quad), stencil,
+ inputFlags);
}
std::unique_ptr<GrDrawOp> GrFillRectOp::MakeNonAARect(GrRecordingContext* context,
@@ -435,7 +437,8 @@
const SkRect& rect,
const GrUserStencilSettings* stencil) {
DrawQuad quad{GrQuad::MakeFromRect(rect, view), GrQuad(rect), GrQuadAAFlags::kNone};
- return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, &quad, stencil);
+ return FillRectOp::Make(context, std::move(paint), GrAAType::kNone, &quad, stencil,
+ InputFlags::kNone);
}
std::unique_ptr<GrDrawOp> GrFillRectOp::MakeOp(GrRecordingContext* context,
@@ -454,7 +457,7 @@
quads[0].fAAFlags};
paint.setColor4f(quads[0].fColor);
std::unique_ptr<GrDrawOp> op = FillRectOp::Make(context, std::move(paint), aaType,
- &quad, stencilSettings);
+ &quad, stencilSettings, InputFlags::kNone);
FillRectOp* fillRects = op->cast<FillRectOp>();
*numConsumed = 1;
diff --git a/src/gpu/ops/GrFillRectOp.h b/src/gpu/ops/GrFillRectOp.h
index e44dae52..947ee7c 100644
--- a/src/gpu/ops/GrFillRectOp.h
+++ b/src/gpu/ops/GrFillRectOp.h
@@ -10,6 +10,7 @@
#include "include/private/GrTypesPriv.h"
#include "src/gpu/GrRenderTargetContext.h"
+#include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
class GrDrawOp;
class GrPaint;
@@ -27,12 +28,14 @@
*/
class GrFillRectOp {
public:
+ using InputFlags = GrSimpleMeshDrawOpHelper::InputFlags;
static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
GrPaint&& paint,
GrAAType aaType,
DrawQuad* quad,
- const GrUserStencilSettings* stencil = nullptr);
+ const GrUserStencilSettings* stencil = nullptr,
+ InputFlags = InputFlags::kNone);
// Utility function to create a non-AA rect transformed by view. This is used commonly enough
// in testing and GMs that manage ops without going through GrRTC that it's worth the
diff --git a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
index 8929af6..acdb16c 100644
--- a/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
+++ b/src/gpu/ops/GrSimpleMeshDrawOpHelper.h
@@ -42,6 +42,7 @@
enum class InputFlags : uint8_t {
kNone = 0,
kSnapVerticesToPixelCenters = (uint8_t)GrPipeline::InputFlags::kSnapVerticesToPixelCenters,
+ kConservativeRaster = (uint8_t)GrPipeline::InputFlags::kConservativeRaster,
};
GR_DECL_BITFIELD_CLASS_OPS_FRIENDS(InputFlags);
diff --git a/src/gpu/tessellate/GrGpuTessellationPathRenderer.cpp b/src/gpu/tessellate/GrGpuTessellationPathRenderer.cpp
index 3e911b3..1f4c9fd 100644
--- a/src/gpu/tessellate/GrGpuTessellationPathRenderer.cpp
+++ b/src/gpu/tessellate/GrGpuTessellationPathRenderer.cpp
@@ -12,8 +12,9 @@
#include "src/gpu/GrMemoryPool.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/GrRenderTargetContext.h"
-#include "src/gpu/GrRenderTargetContextPriv.h"
+#include "src/gpu/GrSurfaceContextPriv.h"
#include "src/gpu/geometry/GrShape.h"
+#include "src/gpu/ops/GrFillRectOp.h"
#include "src/gpu/tessellate/GrDrawAtlasPathOp.h"
#include "src/gpu/tessellate/GrTessellatePathOp.h"
@@ -173,18 +174,39 @@
}
}
- // The next draw will be the final op in the renderTargetContext. So if Ganesh is planning
- // to discard the stencil values anyway, then we might not actually need to reset the
- // stencil values back to zero.
- bool mustResetStencil = !onFlushRP->caps()->discardStencilValuesAfterRenderPass() ||
- rtc->numSamples() <= 1; // Need a stencil reset for mixed samples.
+ // Finally, draw a fullscreen rect to convert our stencilled paths into alpha coverage masks.
+ auto fillRectFlags = GrFillRectOp::InputFlags::kNone;
- // Draw a fullscreen rect to convert our stencilled paths into alpha coverage masks.
+ // This will be the final op in the renderTargetContext. So if Ganesh is planning to discard the
+ // stencil values anyway, then we might not actually need to reset the stencil values back to 0.
+ bool mustResetStencil = !onFlushRP->caps()->discardStencilValuesAfterRenderPass();
+
+ if (rtc->numSamples() <= 1) {
+ // We are mixed sampled. We need to enable conservative raster and ensure stencil values get
+ // reset in order to avoid artifacts along the diagonal of the atlas.
+ fillRectFlags |= GrFillRectOp::InputFlags::kConservativeRaster;
+ mustResetStencil = true;
+ }
+
+ SkRect coverRect = SkRect::MakeIWH(fAtlas.drawBounds().width(), fAtlas.drawBounds().height());
+ const GrUserStencilSettings* stencil;
+ if (mustResetStencil) {
+ // Outset the cover rect in case there are T-junctions in the path bounds.
+ coverRect.outset(1, 1);
+ stencil = &kTestAndResetStencil;
+ } else {
+ stencil = &kTestStencil;
+ }
+
+ GrQuad coverQuad(coverRect);
+ DrawQuad drawQuad{coverQuad, coverQuad, GrQuadAAFlags::kAll};
+
GrPaint paint;
paint.setColor4f(SK_PMColor4fWHITE);
- SkRect drawRect = SkRect::MakeIWH(fAtlas.drawBounds().width(), fAtlas.drawBounds().height());
- rtc->priv().stencilRect(GrNoClip(), (mustResetStencil) ? &kTestAndResetStencil : &kTestStencil,
- std::move(paint), GrAA::kYes, SkMatrix::I(), drawRect, nullptr);
+
+ auto coverOp = GrFillRectOp::Make(rtc->surfPriv().getContext(), std::move(paint),
+ GrAAType::kMSAA, &drawQuad, stencil, fillRectFlags);
+ rtc->addDrawOp(GrNoClip(), std::move(coverOp));
if (rtc->asSurfaceProxy()->requiresManualMSAAResolve()) {
onFlushRP->addTextureResolveTask(sk_ref_sp(rtc->asTextureProxy()),
diff --git a/src/gpu/tessellate/GrTessellatePathOp.cpp b/src/gpu/tessellate/GrTessellatePathOp.cpp
index 53e8382..db7a50f 100644
--- a/src/gpu/tessellate/GrTessellatePathOp.cpp
+++ b/src/gpu/tessellate/GrTessellatePathOp.cpp
@@ -84,7 +84,6 @@
}
// Fastest CPU approach: emit one cubic wedge per verb, fanning out from the center.
-
if ((fPathVertexCount = GrPathParser::EmitCenterWedgePatches(fPath, &pathVertexAllocator))) {
fStencilPathShader = state->allocator()->make<GrStencilWedgeShader>(fViewMatrix);
}