Consolidate stroke-rect ops and use GrFillRectOp instead of GrNonAA/AARectOp

Bug: skia:
Change-Id: Iee57bc970a026de2ad5a0758153e9cbb20753fa1
Reviewed-on: https://skia-review.googlesource.com/c/173105
Commit-Queue: Michael Ludwig <michaelludwig@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
This commit is contained in:
Michael Ludwig 2018-12-10 12:43:36 -05:00 committed by Skia Commit-Bot
parent 46f40f4247
commit 72ab3461b7
23 changed files with 515 additions and 1474 deletions

View File

@ -13,7 +13,7 @@
#include "SkRRect.h"
#include "effects/GrRRectEffect.h"
#include "ops/GrDrawOp.h"
#include "ops/GrRectOpFactory.h"
#include "ops/GrFillRectOp.h"
namespace skiagm {
@ -95,9 +95,8 @@ protected:
bounds.offset(SkIntToScalar(x), SkIntToScalar(y));
renderTargetContext->priv().testingOnly_addDrawOp(
GrRectOpFactory::MakeNonAAFill(context, std::move(grPaint),
SkMatrix::I(),
bounds, GrAAType::kNone));
GrFillRectOp::Make(context, std::move(grPaint), GrAAType::kNone,
SkMatrix::I(), bounds));
}
canvas->restore();
x = x + fTestOffsetX;

View File

@ -16,7 +16,7 @@
#include "SkGradientShader.h"
#include "effects/GrConstColorProcessor.h"
#include "ops/GrDrawOp.h"
#include "ops/GrRectOpFactory.h"
#include "ops/GrFillRectOp.h"
namespace skiagm {
/**
@ -108,8 +108,8 @@ protected:
grPaint.addColorFragmentProcessor(std::move(fp));
renderTargetContext->priv().testingOnly_addDrawOp(
GrRectOpFactory::MakeNonAAFill(context, std::move(grPaint), viewMatrix,
renderRect, GrAAType::kNone));
GrFillRectOp::Make(context, std::move(grPaint), GrAAType::kNone,
viewMatrix, renderRect));
// Draw labels for the input to the processor and the processor to the right of
// the test rect. The input label appears above the processor label.

View File

@ -11,7 +11,7 @@
#include "GrRenderTargetContextPriv.h"
#include "effects/GrRRectEffect.h"
#include "ops/GrDrawOp.h"
#include "ops/GrRectOpFactory.h"
#include "ops/GrFillRectOp.h"
#include "SkRRect.h"
namespace skiagm {
@ -117,9 +117,8 @@ protected:
bounds.outset(2.f, 2.f);
renderTargetContext->priv().testingOnly_addDrawOp(
GrRectOpFactory::MakeNonAAFill(context, std::move(grPaint),
SkMatrix::I(), bounds,
GrAAType::kNone));
GrFillRectOp::Make(context, std::move(grPaint), GrAAType::kNone,
SkMatrix::I(), bounds));
} else {
drew = false;
}

View File

@ -18,7 +18,7 @@
#include "SkSurface.h"
#include "effects/GrTextureDomain.h"
#include "ops/GrDrawOp.h"
#include "ops/GrRectOpFactory.h"
#include "ops/GrFillRectOp.h"
namespace skiagm {
/**
@ -129,8 +129,8 @@ protected:
const SkMatrix viewMatrix = SkMatrix::MakeTrans(x, y);
grPaint.addColorFragmentProcessor(std::move(fp));
renderTargetContext->priv().testingOnly_addDrawOp(
GrRectOpFactory::MakeNonAAFill(context, std::move(grPaint), viewMatrix,
renderRect, GrAAType::kNone));
GrFillRectOp::Make(context, std::move(grPaint), GrAAType::kNone,
viewMatrix, renderRect));
x += renderRect.width() + kTestPad;
}
y += renderRect.height() + kTestPad;

View File

@ -19,7 +19,7 @@
#include "SkGradientShader.h"
#include "effects/GrYUVtoRGBEffect.h"
#include "ops/GrDrawOp.h"
#include "ops/GrRectOpFactory.h"
#include "ops/GrFillRectOp.h"
#define YSIZE 8
#define USIZE 4
@ -130,8 +130,8 @@ protected:
SkMatrix viewMatrix;
viewMatrix.setTranslate(x, y);
renderTargetContext->priv().testingOnly_addDrawOp(
GrRectOpFactory::MakeNonAAFill(context, std::move(grPaint), viewMatrix,
renderRect, GrAAType::kNone));
GrFillRectOp::Make(context, std::move(grPaint), GrAAType::kNone,
viewMatrix, renderRect));
}
x += renderRect.width() + kTestPad;
}
@ -251,8 +251,8 @@ protected:
SkMatrix viewMatrix;
viewMatrix.setTranslate(x, y);
grPaint.addColorFragmentProcessor(std::move(fp));
std::unique_ptr<GrDrawOp> op(GrRectOpFactory::MakeNonAAFill(
context, std::move(grPaint), viewMatrix, renderRect, GrAAType::kNone));
std::unique_ptr<GrDrawOp> op(GrFillRectOp::Make(context, std::move(grPaint),
GrAAType::kNone, viewMatrix, renderRect));
renderTargetContext->priv().testingOnly_addDrawOp(std::move(op));
}
}

View File

@ -231,14 +231,12 @@ skia_gpu_sources = [
"$_src/gpu/ops/GrAAConvexTessellator.h",
"$_src/gpu/ops/GrAAConvexPathRenderer.cpp",
"$_src/gpu/ops/GrAAConvexPathRenderer.h",
"$_src/gpu/ops/GrAAFillRectOp.cpp",
"$_src/gpu/ops/GrAAFillRRectOp.cpp",
"$_src/gpu/ops/GrAAFillRRectOp.h",
"$_src/gpu/ops/GrAAHairLinePathRenderer.cpp",
"$_src/gpu/ops/GrAAHairLinePathRenderer.h",
"$_src/gpu/ops/GrAALinearizingConvexPathRenderer.cpp",
"$_src/gpu/ops/GrAALinearizingConvexPathRenderer.h",
"$_src/gpu/ops/GrAAStrokeRectOp.cpp",
"$_src/gpu/ops/GrAtlasTextOp.cpp",
"$_src/gpu/ops/GrAtlasTextOp.h",
"$_src/gpu/ops/GrClearOp.cpp",
@ -266,8 +264,6 @@ skia_gpu_sources = [
"$_src/gpu/ops/GrFillRectOp.h",
"$_src/gpu/ops/GrMeshDrawOp.cpp",
"$_src/gpu/ops/GrMeshDrawOp.h",
"$_src/gpu/ops/GrNonAAFillRectOp.cpp",
"$_src/gpu/ops/GrNonAAStrokeRectOp.cpp",
"$_src/gpu/ops/GrLatticeOp.cpp",
"$_src/gpu/ops/GrLatticeOp.h",
"$_src/gpu/ops/GrOp.cpp",
@ -276,7 +272,6 @@ skia_gpu_sources = [
"$_src/gpu/ops/GrOvalOpFactory.h",
"$_src/gpu/ops/GrQuadPerEdgeAA.cpp",
"$_src/gpu/ops/GrQuadPerEdgeAA.h",
"$_src/gpu/ops/GrRectOpFactory.h",
"$_src/gpu/ops/GrRegionOp.cpp",
"$_src/gpu/ops/GrRegionOp.h",
"$_src/gpu/ops/GrSemaphoreOp.cpp",
@ -287,6 +282,8 @@ skia_gpu_sources = [
"$_src/gpu/ops/GrSimpleMeshDrawOpHelper.h",
"$_src/gpu/ops/GrSmallPathRenderer.cpp",
"$_src/gpu/ops/GrSmallPathRenderer.h",
"$_src/gpu/ops/GrStrokeRectOp.cpp",
"$_src/gpu/ops/GrStrokeRectOp.h",
"$_src/gpu/ops/GrTessellatingPathRenderer.cpp",
"$_src/gpu/ops/GrTessellatingPathRenderer.h",
"$_src/gpu/ops/GrTextureOp.cpp",

View File

@ -49,11 +49,11 @@
#include "ops/GrLatticeOp.h"
#include "ops/GrOp.h"
#include "ops/GrOvalOpFactory.h"
#include "ops/GrRectOpFactory.h"
#include "ops/GrRegionOp.h"
#include "ops/GrSemaphoreOp.h"
#include "ops/GrShadowRRectOp.h"
#include "ops/GrStencilPathOp.h"
#include "ops/GrStrokeRectOp.h"
#include "ops/GrTextureOp.h"
#include "text/GrTextContext.h"
#include "text/GrTextTarget.h"
@ -302,9 +302,9 @@ void GrRenderTargetContextPriv::absClear(const SkIRect* clearRect, const SkPMCol
GrPaint paint;
paint.setColor4f(color);
SkRect scissor = SkRect::Make(rtRect);
std::unique_ptr<GrDrawOp> op(GrRectOpFactory::MakeNonAAFill(fRenderTargetContext->fContext,
std::move(paint), SkMatrix::I(),
scissor, GrAAType::kNone));
std::unique_ptr<GrDrawOp> op(GrFillRectOp::Make(fRenderTargetContext->fContext,
std::move(paint), GrAAType::kNone,
SkMatrix::I(), scissor));
if (!op) {
return;
}
@ -351,9 +351,9 @@ void GrRenderTargetContext::internalClear(const GrFixedClip& clip,
GrPaint paint;
paint.setColor4f(color);
SkRect scissor = SkRect::Make(clip.scissorRect());
std::unique_ptr<GrDrawOp> op(GrRectOpFactory::MakeNonAAFill(fContext, std::move(paint),
SkMatrix::I(), scissor,
GrAAType::kNone));
std::unique_ptr<GrDrawOp> op(GrFillRectOp::Make(fContext, std::move(paint),
GrAAType::kNone, SkMatrix::I(),
scissor));
if (!op) {
return;
}
@ -451,8 +451,8 @@ void GrRenderTargetContext::drawPaint(const GrClip& clip,
AutoCheckFlush acf(this->drawingManager());
std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
fContext, std::move(paint), SkMatrix::I(), localMatrix, r, GrAAType::kNone);
std::unique_ptr<GrDrawOp> op = GrFillRectOp::MakeWithLocalMatrix(
fContext, std::move(paint), GrAAType::kNone, SkMatrix::I(), localMatrix, r);
this->addDrawOp(clip, std::move(op));
}
}
@ -519,17 +519,8 @@ bool GrRenderTargetContext::drawFilledRect(const GrClip& clip,
}
GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
std::unique_ptr<GrDrawOp> op;
if (GrAAType::kCoverage == aaType) {
op = GrRectOpFactory::MakeAAFill(fContext, std::move(paint), viewMatrix, croppedRect, ss);
} else {
op = GrRectOpFactory::MakeNonAAFill(fContext, std::move(paint), viewMatrix, croppedRect,
aaType, ss);
}
if (!op) {
return false;
}
this->addDrawOp(clip, std::move(op));
this->addDrawOp(clip, GrFillRectOp::Make(fContext, std::move(paint), aaType, viewMatrix,
croppedRect, ss));
return true;
}
@ -620,17 +611,9 @@ void GrRenderTargetContext::drawRect(const GrClip& clip,
std::unique_ptr<GrDrawOp> op;
GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
if (GrAAType::kCoverage == aaType) {
// The stroke path needs the rect to remain axis aligned (no rotation or skew).
if (viewMatrix.rectStaysRect()) {
op = GrRectOpFactory::MakeAAStroke(fContext, std::move(paint), viewMatrix, rect,
stroke);
}
} else {
op = GrRectOpFactory::MakeNonAAStroke(fContext, std::move(paint), viewMatrix, rect,
stroke, aaType);
}
op = GrStrokeRectOp::Make(fContext, std::move(paint), aaType, viewMatrix, rect, stroke);
// op may be null if the stroke is not supported or if using coverage aa and the view matrix
// does not preserve rectangles.
if (op) {
this->addDrawOp(clip, std::move(op));
return;
@ -730,9 +713,8 @@ void GrRenderTargetContextPriv::stencilRect(const GrHardClip& clip,
GrPaint paint;
paint.setXPFactory(GrDisableColorXPFactory::Get());
std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFill(fRenderTargetContext->fContext,
std::move(paint), viewMatrix,
rect, aaType, ss);
std::unique_ptr<GrDrawOp> op = GrFillRectOp::Make(
fRenderTargetContext->fContext, std::move(paint), aaType, viewMatrix, rect, ss);
fRenderTargetContext->addDrawOp(clip, std::move(op));
}
@ -784,29 +766,8 @@ void GrRenderTargetContext::fillRectToRect(const GrClip& clip,
AutoCheckFlush acf(this->drawingManager());
GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
if (GrAAType::kCoverage != aaType) {
std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalRect(
fContext, std::move(paint), viewMatrix, croppedRect, croppedLocalRect, aaType);
this->addDrawOp(clip, std::move(op));
return;
}
std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeAAFillWithLocalRect(
fContext, std::move(paint), viewMatrix, croppedRect, croppedLocalRect);
if (op) {
this->addDrawOp(clip, std::move(op));
return;
}
SkMatrix viewAndUnLocalMatrix;
if (!viewAndUnLocalMatrix.setRectToRect(localRect, rectToDraw, SkMatrix::kFill_ScaleToFit)) {
SkDebugf("fillRectToRect called with empty local matrix.\n");
return;
}
viewAndUnLocalMatrix.postConcat(viewMatrix);
this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewAndUnLocalMatrix,
GrShape(localRect));
this->addDrawOp(clip, GrFillRectOp::MakeWithLocalRect(fContext, std::move(paint), aaType,
viewMatrix, croppedRect, croppedLocalRect));
}
void GrRenderTargetContext::drawTexture(const GrClip& clip, sk_sp<GrTextureProxy> proxy,
@ -871,33 +832,8 @@ void GrRenderTargetContext::fillRectWithLocalMatrix(const GrClip& clip,
AutoCheckFlush acf(this->drawingManager());
GrAAType aaType = this->chooseAAType(aa, GrAllowMixedSamples::kNo);
if (GrAAType::kCoverage != aaType) {
std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
fContext, std::move(paint), viewMatrix, localMatrix, croppedRect, aaType);
this->addDrawOp(clip, std::move(op));
return;
}
std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeAAFillWithLocalMatrix(
fContext, std::move(paint), viewMatrix, localMatrix, croppedRect);
if (op) {
this->addDrawOp(clip, std::move(op));
return;
}
SkMatrix viewAndUnLocalMatrix;
if (!localMatrix.invert(&viewAndUnLocalMatrix)) {
SkDebugf("fillRectWithLocalMatrix called with degenerate local matrix.\n");
return;
}
viewAndUnLocalMatrix.postConcat(viewMatrix);
SkPath path;
path.setIsVolatile(true);
path.addRect(rectToDraw);
path.transform(localMatrix);
this->drawShapeUsingPathRenderer(clip, std::move(paint), aa, viewAndUnLocalMatrix,
GrShape(path));
this->addDrawOp(clip, GrFillRectOp::MakeWithLocalMatrix(fContext, std::move(paint), aaType,
viewMatrix, localMatrix, croppedRect));
}
void GrRenderTargetContext::drawVertices(const GrClip& clip,
@ -1579,7 +1515,7 @@ void GrRenderTargetContext::drawShape(const GrClip& clip,
SkRect rects[2];
if (shape.asNestedRects(rects)) {
// Concave AA paths are expensive - try to avoid them for special cases
std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeAAFillNestedRects(
std::unique_ptr<GrDrawOp> op = GrStrokeRectOp::MakeNested(
fContext, std::move(paint), viewMatrix, rects);
if (op) {
this->addDrawOp(clip, std::move(op));

View File

@ -22,7 +22,7 @@
#include "SkTaskGroup.h"
#include "SkTraceEvent.h"
#include "ops/GrDrawOp.h"
#include "ops/GrRectOpFactory.h"
#include "ops/GrFillRectOp.h"
////////////////////////////////////////////////////////////////////////////////
GrPathRenderer::CanDrawPath
@ -100,9 +100,9 @@ void GrSoftwarePathRenderer::DrawNonAARect(GrRenderTargetContext* renderTargetCo
const SkMatrix& localMatrix) {
GrContext* context = renderTargetContext->surfPriv().getContext();
renderTargetContext->addDrawOp(clip,
GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
context, std::move(paint), viewMatrix, localMatrix, rect,
GrAAType::kNone, &userStencilSettings));
GrFillRectOp::MakeWithLocalMatrix(
context, std::move(paint), GrAAType::kNone, viewMatrix,
localMatrix, rect, &userStencilSettings));
}
void GrSoftwarePathRenderer::DrawAroundInvPath(GrRenderTargetContext* renderTargetContext,

View File

@ -1,446 +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 "GrColor.h"
#include "GrDefaultGeoProcFactory.h"
#include "GrMeshDrawOp.h"
#include "GrOpFlushState.h"
#include "GrRectOpFactory.h"
#include "GrResourceKey.h"
#include "GrResourceProvider.h"
#include "GrTypes.h"
#include "SkMatrix.h"
#include "SkMatrixPriv.h"
#include "SkRect.h"
#include "SkPointPriv.h"
#include "ops/GrSimpleMeshDrawOpHelper.h"
#include <new>
GR_DECLARE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
static inline bool view_matrix_ok_for_aa_fill_rect(const SkMatrix& viewMatrix) {
return viewMatrix.preservesRightAngles();
}
static inline void set_inset_fan(SkPoint* pts, size_t stride, const SkRect& r, SkScalar dx,
SkScalar dy) {
SkPointPriv::SetRectFan(pts, r.fLeft + dx, r.fTop + dy, r.fRight - dx, r.fBottom - dy, stride);
}
static const int kNumAAFillRectsInIndexBuffer = 256;
static const int kVertsPerAAFillRect = 8;
static const int kIndicesPerAAFillRect = 30;
static sk_sp<const GrBuffer> get_index_buffer(GrResourceProvider* resourceProvider) {
GR_DEFINE_STATIC_UNIQUE_KEY(gAAFillRectIndexBufferKey);
// clang-format off
static const uint16_t gFillAARectIdx[] = {
0, 1, 5, 5, 4, 0,
1, 2, 6, 6, 5, 1,
2, 3, 7, 7, 6, 2,
3, 0, 4, 4, 7, 3,
4, 5, 6, 6, 7, 4,
};
// clang-format on
GR_STATIC_ASSERT(SK_ARRAY_COUNT(gFillAARectIdx) == kIndicesPerAAFillRect);
return resourceProvider->findOrCreatePatternedIndexBuffer(
gFillAARectIdx, kIndicesPerAAFillRect, kNumAAFillRectsInIndexBuffer,
kVertsPerAAFillRect, gAAFillRectIndexBufferKey);
}
static void generate_aa_fill_rect_geometry(intptr_t verts,
size_t vertexStride,
GrColor color,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect& devRect,
bool tweakAlphaForCoverage,
const SkMatrix* localMatrix) {
SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts);
SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + 4 * vertexStride);
SkScalar inset;
if (viewMatrix.rectStaysRect()) {
inset = SkMinScalar(devRect.width(), SK_Scalar1);
inset = SK_ScalarHalf * SkMinScalar(inset, devRect.height());
set_inset_fan(fan0Pos, vertexStride, devRect, -SK_ScalarHalf, -SK_ScalarHalf);
set_inset_fan(fan1Pos, vertexStride, devRect, inset, inset);
} else {
// compute transformed (1, 0) and (0, 1) vectors
SkVector vec[2] = {{viewMatrix[SkMatrix::kMScaleX], viewMatrix[SkMatrix::kMSkewY]},
{viewMatrix[SkMatrix::kMSkewX], viewMatrix[SkMatrix::kMScaleY]}};
SkScalar len1 = SkPoint::Normalize(&vec[0]);
vec[0].scale(SK_ScalarHalf);
SkScalar len2 = SkPoint::Normalize(&vec[1]);
vec[1].scale(SK_ScalarHalf);
inset = SkMinScalar(len1 * rect.width(), SK_Scalar1);
inset = SK_ScalarHalf * SkMinScalar(inset, len2 * rect.height());
// create the rotated rect
SkPointPriv::SetRectFan(fan0Pos, rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
vertexStride);
SkMatrixPriv::MapPointsWithStride(viewMatrix, fan0Pos, vertexStride, 4);
// Now create the inset points and then outset the original
// rotated points
// TL
*((SkPoint*)((intptr_t)fan1Pos + 0 * vertexStride)) =
*((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) + vec[0] + vec[1];
*((SkPoint*)((intptr_t)fan0Pos + 0 * vertexStride)) -= vec[0] + vec[1];
// BL
*((SkPoint*)((intptr_t)fan1Pos + 1 * vertexStride)) =
*((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) + vec[0] - vec[1];
*((SkPoint*)((intptr_t)fan0Pos + 1 * vertexStride)) -= vec[0] - vec[1];
// BR
*((SkPoint*)((intptr_t)fan1Pos + 2 * vertexStride)) =
*((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) - vec[0] - vec[1];
*((SkPoint*)((intptr_t)fan0Pos + 2 * vertexStride)) += vec[0] + vec[1];
// TR
*((SkPoint*)((intptr_t)fan1Pos + 3 * vertexStride)) =
*((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) - vec[0] + vec[1];
*((SkPoint*)((intptr_t)fan0Pos + 3 * vertexStride)) += vec[0] - vec[1];
}
if (localMatrix) {
SkMatrix invViewMatrix;
if (!viewMatrix.invert(&invViewMatrix)) {
SkDebugf("View matrix is non-invertible, local coords will be wrong.");
invViewMatrix = SkMatrix::I();
}
SkMatrix localCoordMatrix;
localCoordMatrix.setConcat(*localMatrix, invViewMatrix);
SkPoint* fan0Loc = reinterpret_cast<SkPoint*>(verts + sizeof(SkPoint) + sizeof(GrColor));
SkMatrixPriv::MapPointsWithStride(localCoordMatrix, fan0Loc, vertexStride, fan0Pos,
vertexStride, 8);
}
// Make verts point to vertex color and then set all the color and coverage vertex attrs
// values.
verts += sizeof(SkPoint);
// The coverage offset is always the last vertex attribute
intptr_t coverageOffset = vertexStride - sizeof(GrColor) - sizeof(SkPoint);
for (int i = 0; i < 4; ++i) {
if (tweakAlphaForCoverage) {
*reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0;
} else {
*reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
*reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = 0;
}
}
int scale;
if (inset < SK_ScalarHalf) {
scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf));
SkASSERT(scale >= 0 && scale <= 255);
} else {
scale = 0xff;
}
verts += 4 * vertexStride;
float innerCoverage = GrNormalizeByteToFloat(scale);
GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale);
for (int i = 0; i < 4; ++i) {
if (tweakAlphaForCoverage) {
*reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledColor;
} else {
*reinterpret_cast<GrColor*>(verts + i * vertexStride) = color;
*reinterpret_cast<float*>(verts + i * vertexStride + coverageOffset) = innerCoverage;
}
}
}
namespace {
class AAFillRectOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelperWithStencil;
public:
DEFINE_OP_CLASS_ID
static std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect& devRect,
const SkMatrix* localMatrix,
const GrUserStencilSettings* stencil) {
SkASSERT(view_matrix_ok_for_aa_fill_rect(viewMatrix));
return Helper::FactoryHelper<AAFillRectOp>(context, std::move(paint), viewMatrix, rect,
devRect, localMatrix, stencil);
}
AAFillRectOp(const Helper::MakeArgs& helperArgs,
const SkPMColor4f& color,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect& devRect,
const SkMatrix* localMatrix,
const GrUserStencilSettings* stencil)
: INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage, stencil) {
if (localMatrix) {
void* mem = fRectData.push_back_n(sizeof(RectWithLocalMatrixInfo));
new (mem) RectWithLocalMatrixInfo(color, viewMatrix, rect, devRect, *localMatrix);
} else {
void* mem = fRectData.push_back_n(sizeof(RectInfo));
new (mem) RectInfo(color, viewMatrix, rect, devRect);
}
IsZeroArea zeroArea =
(!rect.width() || !rect.height()) ? IsZeroArea::kYes : IsZeroArea::kNo;
this->setBounds(devRect, HasAABloat::kYes, zeroArea);
fRectCnt = 1;
}
const char* name() const override { return "AAFillRectOp"; }
void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
fHelper.visitProxies(func);
}
#ifdef SK_DEBUG
SkString dumpInfo() const override {
SkString str;
str.append(INHERITED::dumpInfo());
str.appendf("# combined: %d\n", fRectCnt);
const RectInfo* info = this->first();
for (int i = 0; i < fRectCnt; ++i) {
const SkRect& rect = info->rect();
str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
info->color().toBytes_RGBA(), rect.fLeft, rect.fTop, rect.fRight,
rect.fBottom);
info = this->next(info);
}
str += fHelper.dumpInfo();
str += INHERITED::dumpInfo();
return str;
}
#endif
FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
SkPMColor4f color = this->first()->color();
auto result = fHelper.xpRequiresDstTexture(
caps, clip, GrProcessorAnalysisCoverage::kSingleChannel, &color);
this->first()->setColor(color);
return result;
}
private:
void onPrepareDraws(Target* target) override {
using namespace GrDefaultGeoProcFactory;
Color color(Color::kPremulGrColorAttribute_Type);
Coverage::Type coverageType = Coverage::kSolid_Type;
if (!fHelper.compatibleWithAlphaAsCoverage()) {
coverageType = Coverage::kAttribute_Type;
}
LocalCoords lc = LocalCoords::kUnused_Type;
if (fHelper.usesLocalCoords()) {
lc = LocalCoords::kHasExplicit_Type;
}
sk_sp<GrGeometryProcessor> gp =
GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(), color, coverageType,
lc, SkMatrix::I());
if (!gp) {
SkDebugf("Couldn't create GrGeometryProcessor\n");
return;
}
size_t vertexStride = gp->vertexStride();
sk_sp<const GrBuffer> indexBuffer = get_index_buffer(target->resourceProvider());
PatternHelper helper(target, GrPrimitiveType::kTriangles, vertexStride, indexBuffer.get(),
kVertsPerAAFillRect, kIndicesPerAAFillRect, fRectCnt);
void* vertices = helper.vertices();
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
}
const RectInfo* info = this->first();
const SkMatrix* localMatrix = nullptr;
for (int i = 0; i < fRectCnt; i++) {
intptr_t verts =
reinterpret_cast<intptr_t>(vertices) + i * kVertsPerAAFillRect * vertexStride;
if (fHelper.usesLocalCoords()) {
if (info->hasLocalMatrix()) {
localMatrix = &static_cast<const RectWithLocalMatrixInfo*>(info)->localMatrix();
} else {
localMatrix = &SkMatrix::I();
}
}
// TODO4F: Preserve float colors
generate_aa_fill_rect_geometry(verts, vertexStride, info->color().toBytes_RGBA(),
info->viewMatrix(), info->rect(), info->devRect(),
fHelper.compatibleWithAlphaAsCoverage(), localMatrix);
info = this->next(info);
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
AAFillRectOp* that = t->cast<AAFillRectOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return CombineResult::kCannotCombine;
}
fRectData.push_back_n(that->fRectData.count(), that->fRectData.begin());
fRectCnt += that->fRectCnt;
return CombineResult::kMerged;
}
struct RectInfo {
public:
RectInfo(const SkPMColor4f& color, const SkMatrix& viewMatrix, const SkRect& rect,
const SkRect& devRect)
: RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kNo) {}
bool hasLocalMatrix() const { return HasLocalMatrix::kYes == fHasLocalMatrix; }
const SkPMColor4f& color() const { return fColor; }
const SkMatrix& viewMatrix() const { return fViewMatrix; }
const SkRect& rect() const { return fRect; }
const SkRect& devRect() const { return fDevRect; }
void setColor(const SkPMColor4f& color) { fColor = color; }
protected:
enum class HasLocalMatrix : uint32_t { kNo, kYes };
RectInfo(const SkPMColor4f& color, const SkMatrix& viewMatrix, const SkRect& rect,
const SkRect& devRect, HasLocalMatrix hasLM)
: fHasLocalMatrix(hasLM)
, fColor(color)
, fViewMatrix(viewMatrix)
, fRect(rect)
, fDevRect(devRect) {}
HasLocalMatrix fHasLocalMatrix;
SkPMColor4f fColor;
SkMatrix fViewMatrix;
SkRect fRect;
SkRect fDevRect;
};
struct RectWithLocalMatrixInfo : public RectInfo {
public:
RectWithLocalMatrixInfo(const SkPMColor4f& color, const SkMatrix& viewMatrix,
const SkRect& rect, const SkRect& devRect,
const SkMatrix& localMatrix)
: RectInfo(color, viewMatrix, rect, devRect, HasLocalMatrix::kYes)
, fLocalMatrix(localMatrix) {}
const SkMatrix& localMatrix() const { return fLocalMatrix; }
private:
SkMatrix fLocalMatrix;
};
RectInfo* first() { return reinterpret_cast<RectInfo*>(fRectData.begin()); }
const RectInfo* first() const { return reinterpret_cast<const RectInfo*>(fRectData.begin()); }
const RectInfo* next(const RectInfo* prev) const {
intptr_t next =
reinterpret_cast<intptr_t>(prev) +
(prev->hasLocalMatrix() ? sizeof(RectWithLocalMatrixInfo) : sizeof(RectInfo));
return reinterpret_cast<const RectInfo*>(next);
}
SkSTArray<4 * sizeof(RectWithLocalMatrixInfo), uint8_t, true> fRectData;
Helper fHelper;
int fRectCnt;
typedef GrMeshDrawOp INHERITED;
};
} // anonymous namespace
namespace GrRectOpFactory {
std::unique_ptr<GrDrawOp> MakeAAFill(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencil) {
if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
return nullptr;
}
SkRect devRect;
viewMatrix.mapRect(&devRect, rect);
return AAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, devRect,
nullptr, stencil);
}
std::unique_ptr<GrDrawOp> MakeAAFillWithLocalMatrix(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
const SkRect& rect) {
if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
return nullptr;
}
SkRect devRect;
viewMatrix.mapRect(&devRect, rect);
return AAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, devRect,
&localMatrix, nullptr);
}
std::unique_ptr<GrDrawOp> MakeAAFillWithLocalRect(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect& localRect) {
if (!view_matrix_ok_for_aa_fill_rect(viewMatrix)) {
return nullptr;
}
SkRect devRect;
viewMatrix.mapRect(&devRect, rect);
SkMatrix localMatrix;
if (!localMatrix.setRectToRect(rect, localRect, SkMatrix::kFill_ScaleToFit)) {
return nullptr;
}
return AAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, devRect,
&localMatrix, nullptr);
}
} // namespace GrRectOpFactory
///////////////////////////////////////////////////////////////////////////////////////////////////
#if GR_TEST_UTILS
#include "GrDrawOpTest.h"
GR_DRAW_OP_TEST_DEFINE(AAFillRectOp) {
SkMatrix viewMatrix;
do {
viewMatrix = GrTest::TestMatrixInvertible(random);
} while (!view_matrix_ok_for_aa_fill_rect(viewMatrix));
SkRect rect = GrTest::TestRect(random);
SkRect devRect;
viewMatrix.mapRect(&devRect, rect);
const SkMatrix* localMatrix = nullptr;
SkMatrix m;
if (random->nextBool()) {
m = GrTest::TestMatrix(random);
}
const GrUserStencilSettings* stencil = random->nextBool() ? nullptr
: GrGetRandomStencil(random, context);
return AAFillRectOp::Make(context, std::move(paint), viewMatrix, rect,
devRect, localMatrix, stencil);
}
#endif

View File

@ -9,6 +9,7 @@
#include "GrContext.h"
#include "GrDefaultGeoProcFactory.h"
#include "GrDrawOpTest.h"
#include "GrFillRectOp.h"
#include "GrFixedClip.h"
#include "GrMesh.h"
#include "GrOpFlushState.h"
@ -23,7 +24,6 @@
#include "SkTLazy.h"
#include "SkTraceEvent.h"
#include "ops/GrMeshDrawOp.h"
#include "ops/GrRectOpFactory.h"
GrDefaultPathRenderer::GrDefaultPathRenderer() {
}
@ -611,11 +611,11 @@ bool GrDefaultPathRenderer::internalDrawPath(GrRenderTargetContext* renderTarget
}
const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
viewMatrix;
// This is a non-coverage aa rect op since we assert aaType != kCoverage at the start
renderTargetContext->addDrawOp(
clip,
GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
context, std::move(paint), viewM, localMatrix,
bounds, aaType, passes[p]));
GrFillRectOp::MakeWithLocalMatrix(context, std::move(paint), aaType, viewM,
localMatrix, bounds, passes[p]));
} else {
bool stencilPass = stencilOnly || passCount > 1;
std::unique_ptr<GrDrawOp> op;

View File

@ -174,8 +174,13 @@ public:
break;
}
}
auto result = fHelper.xpRequiresDstTexture(
caps, clip, GrProcessorAnalysisCoverage::kSingleChannel, &quadColors);
// If the AA type is coverage, it will be a single value per pixel; if it's not coverage AA
// then the coverage is always 1.0, so specify kNone for more optimal blending.
GrProcessorAnalysisCoverage coverage = fHelper.aaType() == GrAAType::kCoverage ?
GrProcessorAnalysisCoverage::kSingleChannel :
GrProcessorAnalysisCoverage::kNone;
auto result = fHelper.xpRequiresDstTexture(caps, clip, coverage, &quadColors);
// If there is a constant color after analysis, that means all of the quads should be set
// to the same color (even if they started out with different colors).
SkPMColor4f colorOverride;
@ -352,40 +357,40 @@ private:
namespace GrFillRectOp {
std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencilSettings) {
std::unique_ptr<GrDrawOp> MakePerEdge(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencilSettings) {
return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
GrPerspQuad(rect, SkMatrix::I()), GrQuadType::kRect);
}
std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencilSettings) {
std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencilSettings) {
GrQuadType localQuadType = GrQuadTypeForTransformedRect(localMatrix);
return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
GrPerspQuad(rect, localMatrix), localQuadType);
}
std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect& localRect,
const GrUserStencilSettings* stencilSettings) {
std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect& localRect,
const GrUserStencilSettings* stencilSettings) {
return FillRectOp::Make(context, std::move(paint), aaType, edgeAA, stencilSettings,
GrPerspQuad(rect, viewMatrix), GrQuadTypeForTransformedRect(viewMatrix),
GrPerspQuad(localRect, SkMatrix::I()), GrQuadType::kRect);
@ -426,6 +431,41 @@ std::unique_ptr<GrDrawOp> MakeSet(GrContext* context,
return op;
}
std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
const SkMatrix& viewMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencil) {
return MakePerEdge(context, std::move(paint), aaType,
aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
viewMatrix, rect, stencil);
}
std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencil) {
return MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
viewMatrix, localMatrix, rect, stencil);
}
std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect& localRect,
const GrUserStencilSettings* stencil) {
return MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
aaType == GrAAType::kCoverage ? GrQuadAAFlags::kAll : GrQuadAAFlags::kNone,
viewMatrix, rect, localRect, stencil);
}
} // namespace GrFillRectOp
#if GR_TEST_UTILS
@ -477,19 +517,21 @@ GR_DRAW_OP_TEST_DEFINE(FillRectOp) {
} else {
// Single local matrix
SkMatrix localMatrix = GrTest::TestMatrixInvertible(random);
return GrFillRectOp::MakeWithLocalMatrix(context, std::move(paint), aaType, aaFlags,
viewMatrix, localMatrix, rect, stencil);
return GrFillRectOp::MakePerEdgeWithLocalMatrix(context, std::move(paint), aaType,
aaFlags, viewMatrix, localMatrix,
rect, stencil);
}
} else {
// Pass local rect directly
SkRect localRect = GrTest::TestRect(random);
return GrFillRectOp::MakeWithLocalRect(context, std::move(paint), aaType, aaFlags,
viewMatrix, rect, localRect, stencil);
return GrFillRectOp::MakePerEdgeWithLocalRect(context, std::move(paint), aaType,
aaFlags, viewMatrix, rect, localRect,
stencil);
}
} else {
// The simplest constructor
return GrFillRectOp::Make(context, std::move(paint), aaType, aaFlags, viewMatrix, rect,
stencil);
return GrFillRectOp::MakePerEdge(context, std::move(paint), aaType, aaFlags, viewMatrix,
rect, stencil);
}
}

View File

@ -17,12 +17,55 @@ struct GrUserStencilSettings;
class SkMatrix;
struct SkRect;
/**
* A set of factory functions for drawing filled rectangles either coverage-antialiased, or
* non-antialiased. The non-antialiased ops can be used with MSAA. As with other GrDrawOp factories,
* the GrPaint is only consumed by these methods if a valid op is returned. If null is returned then
* the paint is unmodified and may still be used.
*/
namespace GrFillRectOp {
// General purpose factory functions that handle per-edge anti-aliasing
std::unique_ptr<GrDrawOp> MakePerEdge(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencil = nullptr);
std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalMatrix(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
const SkRect& rect,
const GrUserStencilSettings* stl = nullptr);
std::unique_ptr<GrDrawOp> MakePerEdgeWithLocalRect(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect& localRect,
const GrUserStencilSettings* stencil = nullptr);
// Bulk API for drawing quads with a single op
std::unique_ptr<GrDrawOp> MakeSet(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
const SkMatrix& viewMatrix,
const GrRenderTargetContext::QuadSetEntry quads[],
int quadCount,
const GrUserStencilSettings* stencil = nullptr);
// Specializations where all edges are treated the same. If the aa type is coverage, then the
// edges will be anti-aliased, otherwise per-edge AA will be disabled.
std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkRect& rect,
const GrUserStencilSettings* stencil = nullptr);
@ -30,7 +73,6 @@ std::unique_ptr<GrDrawOp> Make(GrContext* context,
std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
const SkRect& rect,
@ -39,19 +81,11 @@ std::unique_ptr<GrDrawOp> MakeWithLocalMatrix(GrContext* context,
std::unique_ptr<GrDrawOp> MakeWithLocalRect(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
GrQuadAAFlags edgeAA,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect& localRect,
const GrUserStencilSettings* stencil = nullptr);
std::unique_ptr<GrDrawOp> MakeSet(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
const SkMatrix& viewMatrix,
const GrRenderTargetContext::QuadSetEntry quads[],
int quadCount,
const GrUserStencilSettings* stencil = nullptr);
}
} // namespace GrFillRectOp
#endif // GrFillRectOp_DEFINED

View File

@ -1,466 +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 "GrAppliedClip.h"
#include "GrColor.h"
#include "GrDefaultGeoProcFactory.h"
#include "GrDrawOpTest.h"
#include "GrMeshDrawOp.h"
#include "GrOpFlushState.h"
#include "GrPrimitiveProcessor.h"
#include "GrQuad.h"
#include "GrRectOpFactory.h"
#include "GrResourceProvider.h"
#include "GrSimpleMeshDrawOpHelper.h"
#include "SkMatrixPriv.h"
static const int kVertsPerRect = 4;
static const int kIndicesPerRect = 6;
/** We always use per-vertex colors so that rects can be combined across color changes. Sometimes
we have explicit local coords and sometimes not. We *could* always provide explicit local
coords and just duplicate the positions when the caller hasn't provided a local coord rect,
but we haven't seen a use case which frequently switches between local rect and no local
rect draws.
The vertex attrib order is always pos, color, [local coords].
*/
static sk_sp<GrGeometryProcessor> make_gp(const GrShaderCaps* shaderCaps) {
using namespace GrDefaultGeoProcFactory;
return GrDefaultGeoProcFactory::Make(shaderCaps,
Color::kPremulGrColorAttribute_Type,
Coverage::kSolid_Type,
LocalCoords::kHasExplicit_Type,
SkMatrix::I());
}
static sk_sp<GrGeometryProcessor> make_perspective_gp(const GrShaderCaps* shaderCaps,
const SkMatrix& viewMatrix,
bool hasExplicitLocalCoords,
const SkMatrix* localMatrix) {
SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
using namespace GrDefaultGeoProcFactory;
// If we have perspective on the viewMatrix then we won't map on the CPU, nor will we map
// the local rect on the cpu (in case the localMatrix also has perspective).
// Otherwise, if we have a local rect, then we apply the localMatrix directly to the localRect
// to generate vertex local coords
if (viewMatrix.hasPerspective()) {
LocalCoords localCoords(hasExplicitLocalCoords ? LocalCoords::kHasExplicit_Type
: LocalCoords::kUsePosition_Type,
localMatrix);
return GrDefaultGeoProcFactory::Make(shaderCaps, Color::kPremulGrColorAttribute_Type,
Coverage::kSolid_Type, localCoords, viewMatrix);
} else if (hasExplicitLocalCoords) {
LocalCoords localCoords(LocalCoords::kHasExplicit_Type, localMatrix);
return GrDefaultGeoProcFactory::Make(shaderCaps, Color::kPremulGrColorAttribute_Type,
Coverage::kSolid_Type, localCoords, SkMatrix::I());
} else {
LocalCoords localCoords(LocalCoords::kUsePosition_Type, localMatrix);
return GrDefaultGeoProcFactory::MakeForDeviceSpace(shaderCaps,
Color::kPremulGrColorAttribute_Type,
Coverage::kSolid_Type, localCoords,
viewMatrix);
}
}
static void tesselate(intptr_t vertices,
size_t vertexStride,
GrColor color,
const SkMatrix* viewMatrix,
const SkRect& rect,
const GrQuad* localQuad) {
SkPoint* positions = reinterpret_cast<SkPoint*>(vertices);
SkPointPriv::SetRectTriStrip(positions, rect, vertexStride);
if (viewMatrix) {
SkMatrixPriv::MapPointsWithStride(*viewMatrix, positions, vertexStride, kVertsPerRect);
}
// Setup local coords
// TODO we should only do this if local coords are being read
if (localQuad) {
static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor);
for (int i = 0; i < kVertsPerRect; i++) {
SkPoint* coords =
reinterpret_cast<SkPoint*>(vertices + kLocalOffset + i * vertexStride);
*coords = localQuad->point(i);
}
}
static const int kColorOffset = sizeof(SkPoint);
GrColor* vertColor = reinterpret_cast<GrColor*>(vertices + kColorOffset);
for (int j = 0; j < 4; ++j) {
*vertColor = color;
vertColor = (GrColor*)((intptr_t)vertColor + vertexStride);
}
}
namespace {
class NonAAFillRectOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelperWithStencil;
public:
static std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect* localRect,
const SkMatrix* localMatrix,
GrAAType aaType,
const GrUserStencilSettings* stencilSettings) {
SkASSERT(GrAAType::kCoverage != aaType);
return Helper::FactoryHelper<NonAAFillRectOp>(context, std::move(paint), viewMatrix, rect,
localRect, localMatrix, aaType,
stencilSettings);
}
NonAAFillRectOp() = delete;
NonAAFillRectOp(const Helper::MakeArgs& args, const SkPMColor4f& color,
const SkMatrix& viewMatrix, const SkRect& rect, const SkRect* localRect,
const SkMatrix* localMatrix, GrAAType aaType,
const GrUserStencilSettings* stencilSettings)
: INHERITED(ClassID()), fHelper(args, aaType, stencilSettings) {
SkASSERT(!viewMatrix.hasPerspective() && (!localMatrix || !localMatrix->hasPerspective()));
RectInfo& info = fRects.push_back();
info.fColor = color;
info.fViewMatrix = viewMatrix;
info.fRect = rect;
if (localRect && localMatrix) {
info.fLocalQuad = GrQuad(*localRect, *localMatrix);
} else if (localRect) {
info.fLocalQuad = GrQuad(*localRect);
} else if (localMatrix) {
info.fLocalQuad = GrQuad(rect, *localMatrix);
} else {
info.fLocalQuad = GrQuad(rect);
}
this->setTransformedBounds(fRects[0].fRect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
}
const char* name() const override { return "NonAAFillRectOp"; }
void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
fHelper.visitProxies(func);
}
#ifdef SK_DEBUG
SkString dumpInfo() const override {
SkString str;
str.append(GrMeshDrawOp::dumpInfo());
str.appendf("# combined: %d\n", fRects.count());
for (int i = 0; i < fRects.count(); ++i) {
const RectInfo& info = fRects[i];
str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
info.fColor.toBytes_RGBA(), info.fRect.fLeft, info.fRect.fTop,
info.fRect.fRight, info.fRect.fBottom);
}
str += fHelper.dumpInfo();
str += INHERITED::dumpInfo();
return str;
}
#endif
RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
SkPMColor4f* color = &fRects.front().fColor;
return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
}
FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
DEFINE_OP_CLASS_ID
private:
void onPrepareDraws(Target* target) override {
sk_sp<GrGeometryProcessor> gp = make_gp(target->caps().shaderCaps());
if (!gp) {
SkDebugf("Couldn't create GrGeometryProcessor\n");
return;
}
size_t kVertexStride = gp->vertexStride();
int rectCount = fRects.count();
sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
PatternHelper helper(target, GrPrimitiveType::kTriangles, kVertexStride, indexBuffer.get(),
kVertsPerRect, kIndicesPerRect, rectCount);
void* vertices = helper.vertices();
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
}
for (int i = 0; i < rectCount; i++) {
intptr_t verts =
reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * kVertexStride;
// TODO4F: Preserve float colors
tesselate(verts, kVertexStride, fRects[i].fColor.toBytes_RGBA(), &fRects[i].fViewMatrix,
fRects[i].fRect, &fRects[i].fLocalQuad);
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
NonAAFillRectOp* that = t->cast<NonAAFillRectOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return CombineResult::kCannotCombine;
}
fRects.push_back_n(that->fRects.count(), that->fRects.begin());
return CombineResult::kMerged;
}
struct RectInfo {
SkPMColor4f fColor;
SkMatrix fViewMatrix;
SkRect fRect;
GrQuad fLocalQuad;
};
Helper fHelper;
SkSTArray<1, RectInfo, true> fRects;
typedef GrMeshDrawOp INHERITED;
};
// We handle perspective in the local matrix or viewmatrix with special ops.
class NonAAFillRectPerspectiveOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelperWithStencil;
public:
static std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect* localRect,
const SkMatrix* localMatrix,
GrAAType aaType,
const GrUserStencilSettings* stencilSettings) {
SkASSERT(GrAAType::kCoverage != aaType);
return Helper::FactoryHelper<NonAAFillRectPerspectiveOp>(context, std::move(paint),
viewMatrix, rect,
localRect, localMatrix, aaType,
stencilSettings);
}
NonAAFillRectPerspectiveOp() = delete;
NonAAFillRectPerspectiveOp(const Helper::MakeArgs& args, const SkPMColor4f& color,
const SkMatrix& viewMatrix, const SkRect& rect,
const SkRect* localRect, const SkMatrix* localMatrix,
GrAAType aaType, const GrUserStencilSettings* stencilSettings)
: INHERITED(ClassID())
, fHelper(args, aaType, stencilSettings)
, fViewMatrix(viewMatrix) {
SkASSERT(viewMatrix.hasPerspective() || (localMatrix && localMatrix->hasPerspective()));
RectInfo& info = fRects.push_back();
info.fColor = color;
info.fRect = rect;
fHasLocalRect = SkToBool(localRect);
fHasLocalMatrix = SkToBool(localMatrix);
if (fHasLocalMatrix) {
fLocalMatrix = *localMatrix;
}
if (fHasLocalRect) {
info.fLocalRect = *localRect;
}
this->setTransformedBounds(rect, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
}
const char* name() const override { return "NonAAFillRectPerspectiveOp"; }
void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
fHelper.visitProxies(func);
}
#ifdef SK_DEBUG
SkString dumpInfo() const override {
SkString str;
str.appendf("# combined: %d\n", fRects.count());
for (int i = 0; i < fRects.count(); ++i) {
const RectInfo& geo = fRects[i];
str.appendf("%d: Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f]\n", i,
geo.fColor.toBytes_RGBA(), geo.fRect.fLeft, geo.fRect.fTop,
geo.fRect.fRight, geo.fRect.fBottom);
}
str += fHelper.dumpInfo();
str += INHERITED::dumpInfo();
return str;
}
#endif
RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
SkPMColor4f* color = &fRects.front().fColor;
return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, color);
}
FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
DEFINE_OP_CLASS_ID
private:
void onPrepareDraws(Target* target) override {
sk_sp<GrGeometryProcessor> gp = make_perspective_gp(
target->caps().shaderCaps(),
fViewMatrix,
fHasLocalRect,
fHasLocalMatrix ? &fLocalMatrix : nullptr);
if (!gp) {
SkDebugf("Couldn't create GrGeometryProcessor\n");
return;
}
size_t vertexStride = gp->vertexStride();
int rectCount = fRects.count();
sk_sp<const GrBuffer> indexBuffer = target->resourceProvider()->refQuadIndexBuffer();
PatternHelper helper(target, GrPrimitiveType::kTriangles, vertexStride, indexBuffer.get(),
kVertsPerRect, kIndicesPerRect, rectCount);
void* vertices = helper.vertices();
if (!vertices || !indexBuffer) {
SkDebugf("Could not allocate vertices\n");
return;
}
for (int i = 0; i < rectCount; i++) {
const RectInfo& info = fRects[i];
// TODO4F: Preserve float colors
GrColor color = info.fColor.toBytes_RGBA();
intptr_t verts =
reinterpret_cast<intptr_t>(vertices) + i * kVertsPerRect * vertexStride;
if (fHasLocalRect) {
GrQuad quad(info.fLocalRect);
tesselate(verts, vertexStride, color, nullptr, info.fRect, &quad);
} else {
tesselate(verts, vertexStride, color, nullptr, info.fRect, nullptr);
}
}
auto pipe = fHelper.makePipeline(target);
helper.recordDraw(target, std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState);
}
CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
NonAAFillRectPerspectiveOp* that = t->cast<NonAAFillRectPerspectiveOp>();
if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
return CombineResult::kCannotCombine;
}
// We could combine across perspective vm changes if we really wanted to.
if (!fViewMatrix.cheapEqualTo(that->fViewMatrix)) {
return CombineResult::kCannotCombine;
}
if (fHasLocalRect != that->fHasLocalRect) {
return CombineResult::kCannotCombine;
}
if (fHasLocalMatrix && !fLocalMatrix.cheapEqualTo(that->fLocalMatrix)) {
return CombineResult::kCannotCombine;
}
fRects.push_back_n(that->fRects.count(), that->fRects.begin());
return CombineResult::kMerged;
}
struct RectInfo {
SkRect fRect;
SkPMColor4f fColor;
SkRect fLocalRect;
};
SkSTArray<1, RectInfo, true> fRects;
Helper fHelper;
bool fHasLocalMatrix;
bool fHasLocalRect;
SkMatrix fLocalMatrix;
SkMatrix fViewMatrix;
typedef GrMeshDrawOp INHERITED;
};
} // anonymous namespace
namespace GrRectOpFactory {
std::unique_ptr<GrDrawOp> MakeNonAAFill(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect& rect,
GrAAType aaType,
const GrUserStencilSettings* stencilSettings) {
if (viewMatrix.hasPerspective()) {
return NonAAFillRectPerspectiveOp::Make(context, std::move(paint), viewMatrix, rect,
nullptr, nullptr, aaType, stencilSettings);
} else {
return NonAAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, nullptr, nullptr,
aaType, stencilSettings);
}
}
std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalMatrix(
GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
const SkRect& rect,
GrAAType aaType,
const GrUserStencilSettings* stencilSettings) {
if (viewMatrix.hasPerspective() || localMatrix.hasPerspective()) {
return NonAAFillRectPerspectiveOp::Make(context, std::move(paint), viewMatrix, rect,
nullptr, &localMatrix, aaType, stencilSettings);
} else {
return NonAAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, nullptr,
&localMatrix, aaType, stencilSettings);
}
}
std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalRect(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkRect& localRect,
GrAAType aaType) {
if (viewMatrix.hasPerspective()) {
return NonAAFillRectPerspectiveOp::Make(context, std::move(paint), viewMatrix, rect,
&localRect, nullptr, aaType, nullptr);
} else {
return NonAAFillRectOp::Make(context, std::move(paint), viewMatrix, rect, &localRect,
nullptr, aaType, nullptr);
}
}
} // namespace GrRectOpFactory
///////////////////////////////////////////////////////////////////////////////////////////////////
#if GR_TEST_UTILS
GR_DRAW_OP_TEST_DEFINE(NonAAFillRectOp) {
SkRect rect = GrTest::TestRect(random);
SkRect localRect = GrTest::TestRect(random);
SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
SkMatrix localMatrix = GrTest::TestMatrix(random);
const GrUserStencilSettings* stencil = GrGetRandomStencil(random, context);
GrAAType aaType = GrAAType::kNone;
if (fsaaType == GrFSAAType::kUnifiedMSAA) {
aaType = random->nextBool() ? GrAAType::kMSAA : GrAAType::kNone;
}
const SkRect* lr = random->nextBool() ? &localRect : nullptr;
const SkMatrix* lm = random->nextBool() ? &localMatrix : nullptr;
if (viewMatrix.hasPerspective() || (lm && lm->hasPerspective())) {
return NonAAFillRectPerspectiveOp::Make(context, std::move(paint), viewMatrix, rect,
lr, lm, aaType, stencil);
} else {
return NonAAFillRectOp::Make(context, std::move(paint), viewMatrix, rect,
lr, lm, aaType, stencil);
}
}
#endif

View File

@ -1,243 +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 "GrColor.h"
#include "GrDefaultGeoProcFactory.h"
#include "GrDrawOpTest.h"
#include "GrMeshDrawOp.h"
#include "GrOpFlushState.h"
#include "GrRectOpFactory.h"
#include "GrSimpleMeshDrawOpHelper.h"
#include "SkRandom.h"
#include "SkStrokeRec.h"
/* create a triangle strip that strokes the specified rect. There are 8
unique vertices, but we repeat the last 2 to close up. Alternatively we
could use an indices array, and then only send 8 verts, but not sure that
would be faster.
*/
static void init_stroke_rect_strip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
const SkScalar rad = SkScalarHalf(width);
verts[0].set(rect.fLeft + rad, rect.fTop + rad);
verts[1].set(rect.fLeft - rad, rect.fTop - rad);
verts[2].set(rect.fRight - rad, rect.fTop + rad);
verts[3].set(rect.fRight + rad, rect.fTop - rad);
verts[4].set(rect.fRight - rad, rect.fBottom - rad);
verts[5].set(rect.fRight + rad, rect.fBottom + rad);
verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
verts[8] = verts[0];
verts[9] = verts[1];
// TODO: we should be catching this higher up the call stack and just draw a single
// non-AA rect
if (2*rad >= rect.width()) {
verts[0].fX = verts[2].fX = verts[4].fX = verts[6].fX = verts[8].fX = rect.centerX();
}
if (2*rad >= rect.height()) {
verts[0].fY = verts[2].fY = verts[4].fY = verts[6].fY = verts[8].fY = rect.centerY();
}
}
// Allow all hairlines and all miters, so long as the miter limit doesn't produce beveled corners.
inline static bool allowed_stroke(const SkStrokeRec& stroke) {
SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style ||
stroke.getStyle() == SkStrokeRec::kHairline_Style);
return !stroke.getWidth() ||
(stroke.getJoin() == SkPaint::kMiter_Join && stroke.getMiter() > SK_ScalarSqrt2);
}
namespace {
class NonAAStrokeRectOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelper;
public:
DEFINE_OP_CLASS_ID
const char* name() const override { return "NonAAStrokeRectOp"; }
void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
fHelper.visitProxies(func);
}
#ifdef SK_DEBUG
SkString dumpInfo() const override {
SkString string;
string.appendf(
"Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
"StrokeWidth: %.2f\n",
fColor.toBytes_RGBA(), fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
fStrokeWidth);
string += fHelper.dumpInfo();
string += INHERITED::dumpInfo();
return string;
}
#endif
static std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkStrokeRec& stroke,
GrAAType aaType) {
if (!allowed_stroke(stroke)) {
return nullptr;
}
Helper::Flags flags = Helper::Flags::kNone;
// Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
// hairline rects. We jam all the vertices to pixel centers to avoid this, but not
// when MSAA is enabled because it can cause ugly artifacts.
if (stroke.getStyle() == SkStrokeRec::kHairline_Style && aaType != GrAAType::kMSAA) {
flags |= Helper::Flags::kSnapVerticesToPixelCenters;
}
return Helper::FactoryHelper<NonAAStrokeRectOp>(context, std::move(paint), flags,
viewMatrix, rect,
stroke, aaType);
}
NonAAStrokeRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color,
Helper::Flags flags, const SkMatrix& viewMatrix, const SkRect& rect,
const SkStrokeRec& stroke, GrAAType aaType)
: INHERITED(ClassID()), fHelper(helperArgs, aaType, flags) {
fColor = color;
fViewMatrix = viewMatrix;
fRect = rect;
// Sort the rect for hairlines
fRect.sort();
fStrokeWidth = stroke.getWidth();
SkScalar rad = SkScalarHalf(fStrokeWidth);
SkRect bounds = rect;
bounds.outset(rad, rad);
// If our caller snaps to pixel centers then we have to round out the bounds
if (flags & Helper::Flags::kSnapVerticesToPixelCenters) {
viewMatrix.mapRect(&bounds);
// We want to be consistent with how we snap non-aa lines. To match what we do in
// GrGLSLVertexShaderBuilder, we first floor all the vertex values and then add half a
// pixel to force us to pixel centers.
bounds.set(SkScalarFloorToScalar(bounds.fLeft),
SkScalarFloorToScalar(bounds.fTop),
SkScalarFloorToScalar(bounds.fRight),
SkScalarFloorToScalar(bounds.fBottom));
bounds.offset(0.5f, 0.5f);
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
} else {
this->setTransformedBounds(bounds, fViewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
}
}
FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone,
&fColor);
}
private:
void onPrepareDraws(Target* target) override {
sk_sp<GrGeometryProcessor> gp;
{
using namespace GrDefaultGeoProcFactory;
Color color(fColor);
LocalCoords::Type localCoordsType = fHelper.usesLocalCoords()
? LocalCoords::kUsePosition_Type
: LocalCoords::kUnused_Type;
gp = GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(), color,
Coverage::kSolid_Type, localCoordsType,
fViewMatrix);
}
size_t kVertexStride = gp->vertexStride();
int vertexCount = kVertsPerHairlineRect;
if (fStrokeWidth > 0) {
vertexCount = kVertsPerStrokeRect;
}
const GrBuffer* vertexBuffer;
int firstVertex;
void* verts =
target->makeVertexSpace(kVertexStride, vertexCount, &vertexBuffer, &firstVertex);
if (!verts) {
SkDebugf("Could not allocate vertices\n");
return;
}
SkPoint* vertex = reinterpret_cast<SkPoint*>(verts);
GrPrimitiveType primType;
if (fStrokeWidth > 0) {
primType = GrPrimitiveType::kTriangleStrip;
init_stroke_rect_strip(vertex, fRect, fStrokeWidth);
} else {
// hairline
primType = GrPrimitiveType::kLineStrip;
vertex[0].set(fRect.fLeft, fRect.fTop);
vertex[1].set(fRect.fRight, fRect.fTop);
vertex[2].set(fRect.fRight, fRect.fBottom);
vertex[3].set(fRect.fLeft, fRect.fBottom);
vertex[4].set(fRect.fLeft, fRect.fTop);
}
GrMesh* mesh = target->allocMesh(primType);
mesh->setNonIndexedNonInstanced(vertexCount);
mesh->setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
// TODO: override onCombineIfPossible
Helper fHelper;
SkPMColor4f fColor;
SkMatrix fViewMatrix;
SkRect fRect;
SkScalar fStrokeWidth;
const static int kVertsPerHairlineRect = 5;
const static int kVertsPerStrokeRect = 10;
typedef GrMeshDrawOp INHERITED;
};
} // anonymous namespace
namespace GrRectOpFactory {
std::unique_ptr<GrDrawOp> MakeNonAAStroke(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkStrokeRec& stroke,
GrAAType aaType) {
return NonAAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, stroke, aaType);
}
} // namespace GrRectOpFactory
#if GR_TEST_UTILS
GR_DRAW_OP_TEST_DEFINE(NonAAStrokeRectOp) {
SkMatrix viewMatrix = GrTest::TestMatrix(random);
SkRect rect = GrTest::TestRect(random);
SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f;
SkPaint strokePaint;
strokePaint.setStrokeWidth(strokeWidth);
strokePaint.setStyle(SkPaint::kStroke_Style);
strokePaint.setStrokeJoin(SkPaint::kMiter_Join);
SkStrokeRec strokeRec(strokePaint);
GrAAType aaType = GrAAType::kNone;
if (fsaaType == GrFSAAType::kUnifiedMSAA) {
aaType = random->nextBool() ? GrAAType::kMSAA : GrAAType::kNone;
}
return NonAAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, strokeRec, aaType);
}
#endif

View File

@ -1,99 +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 GrRectOpFactory_DEFINED
#define GrRectOpFactory_DEFINED
#include <memory>
#include "GrTypes.h"
enum class GrAAType : unsigned;
class GrDrawOp;
class GrPaint;
struct GrUserStencilSettings;
class SkMatrix;
struct SkRect;
class SkStrokeRec;
/**
* A set of factory functions for drawing rectangles including fills, strokes, coverage-antialiased,
* and non-antialiased. The non-antialiased ops can be used with MSAA. As with other GrDrawOp
* factories, the GrPaint is only consumed by these methods if a valid op is returned. If null is
* returned then the paint is unmodified and may still be used.
*/
namespace GrRectOpFactory {
/** AA Fill */
std::unique_ptr<GrDrawOp> MakeAAFill(GrContext*,
GrPaint&&,
const SkMatrix&,
const SkRect&,
const GrUserStencilSettings* = nullptr);
std::unique_ptr<GrDrawOp> MakeAAFillWithLocalMatrix(GrContext*,
GrPaint&&,
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
const SkRect&);
std::unique_ptr<GrDrawOp> MakeAAFillWithLocalRect(GrContext*,
GrPaint&&,
const SkMatrix&,
const SkRect& rect,
const SkRect& localRect);
/** Non-AA Fill - GrAAType must be either kNone or kMSAA. */
std::unique_ptr<GrDrawOp> MakeNonAAFill(GrContext*,
GrPaint&&,
const SkMatrix& viewMatrix,
const SkRect& rect,
GrAAType,
const GrUserStencilSettings* = nullptr);
std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalMatrix(GrContext*,
GrPaint&&,
const SkMatrix& viewMatrix,
const SkMatrix& localMatrix,
const SkRect&,
GrAAType,
const GrUserStencilSettings* = nullptr);
std::unique_ptr<GrDrawOp> MakeNonAAFillWithLocalRect(GrContext*,
GrPaint&&,
const SkMatrix&,
const SkRect& rect,
const SkRect& localRect,
GrAAType);
/** AA Stroke */
std::unique_ptr<GrDrawOp> MakeAAStroke(GrContext*,
GrPaint&&,
const SkMatrix&,
const SkRect&,
const SkStrokeRec&);
// rects[0] == outer rectangle, rects[1] == inner rectangle. Null return means there is nothing to
// draw rather than failure.
std::unique_ptr<GrDrawOp> MakeAAFillNestedRects(GrContext*,
GrPaint&&,
const SkMatrix&,
const SkRect rects[2]);
/** Non-AA Stroke - GrAAType must be either kNone or kMSAA. */
std::unique_ptr<GrDrawOp> MakeNonAAStroke(GrContext*,
GrPaint&&,
const SkMatrix&,
const SkRect&,
const SkStrokeRec&,
GrAAType);
} // namespace GrRectOpFactory
#endif

View File

@ -18,7 +18,7 @@
#include "GrStencilClip.h"
#include "GrStencilPathOp.h"
#include "GrStyle.h"
#include "ops/GrRectOpFactory.h"
#include "ops/GrFillRectOp.h"
GrPathRenderer* GrStencilAndCoverPathRenderer::Create(GrResourceProvider* resourceProvider,
const GrCaps& caps) {
@ -156,10 +156,12 @@ bool GrStencilAndCoverPathRenderer::onDrawPath(const DrawPathArgs& args) {
if (GrAAType::kMixedSamples == coverAAType) {
coverAAType = GrAAType::kNone;
}
std::unique_ptr<GrDrawOp> op = GrRectOpFactory::MakeNonAAFillWithLocalMatrix(
// This is a non-coverage aa rect operation
SkASSERT(coverAAType == GrAAType::kNone || coverAAType == GrAAType::kMSAA);
std::unique_ptr<GrDrawOp> op = GrFillRectOp::MakeWithLocalMatrix(
args.fContext, std::move(args.fPaint),
coverMatrix, localMatrix, coverBounds,
coverAAType, &kInvertedCoverPass);
coverAAType, coverMatrix, localMatrix,
coverBounds, &kInvertedCoverPass);
args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
}

View File

@ -1,25 +1,31 @@
/*
* Copyright 2015 Google Inc.
* 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 "GrStrokeRectOp.h"
#include "GrColor.h"
#include "GrDefaultGeoProcFactory.h"
#include "GrDrawOpTest.h"
#include "GrMeshDrawOp.h"
#include "GrOpFlushState.h"
#include "GrRectOpFactory.h"
#include "GrResourceKey.h"
#include "GrResourceProvider.h"
#include "GrSimpleMeshDrawOpHelper.h"
#include "GrVertexWriter.h"
#include "ops/GrFillRectOp.h"
#include "SkRandom.h"
#include "SkStrokeRec.h"
GR_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
GR_DECLARE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey);
namespace {
// We support all hairlines, bevels, and miters, but not round joins. Also, check whether the miter
// limit makes a miter join effectively beveled.
inline static bool allowed_stroke(const SkStrokeRec& stroke, bool* isMiter) {
// limit makes a miter join effectively beveled. If the miter is effectively beveled, it is only
// supported when using an AA stroke.
inline static bool allowed_stroke(const SkStrokeRec& stroke, GrAA aa, bool* isMiter) {
SkASSERT(stroke.getStyle() == SkStrokeRec::kStroke_Style ||
stroke.getStyle() == SkStrokeRec::kHairline_Style);
// For hairlines, make bevel and round joins appear the same as mitered ones.
@ -29,18 +35,216 @@ inline static bool allowed_stroke(const SkStrokeRec& stroke, bool* isMiter) {
}
if (stroke.getJoin() == SkPaint::kBevel_Join) {
*isMiter = false;
return true;
return aa == GrAA::kYes; // bevel only supported with AA
}
if (stroke.getJoin() == SkPaint::kMiter_Join) {
*isMiter = stroke.getMiter() >= SK_ScalarSqrt2;
return true;
// Supported under non-AA only if it remains mitered
return aa == GrAA::kYes || *isMiter;
}
return false;
}
static void compute_rects(SkRect* devOutside, SkRect* devOutsideAssist, SkRect* devInside,
bool* isDegenerate, const SkMatrix& viewMatrix, const SkRect& rect,
SkScalar strokeWidth, bool miterStroke) {
///////////////////////////////////////////////////////////////////////////////////////////////////
// Non-AA Stroking
///////////////////////////////////////////////////////////////////////////////////////////////////
/* create a triangle strip that strokes the specified rect. There are 8
unique vertices, but we repeat the last 2 to close up. Alternatively we
could use an indices array, and then only send 8 verts, but not sure that
would be faster.
*/
static void init_nonaa_stroke_rect_strip(SkPoint verts[10], const SkRect& rect, SkScalar width) {
const SkScalar rad = SkScalarHalf(width);
verts[0].set(rect.fLeft + rad, rect.fTop + rad);
verts[1].set(rect.fLeft - rad, rect.fTop - rad);
verts[2].set(rect.fRight - rad, rect.fTop + rad);
verts[3].set(rect.fRight + rad, rect.fTop - rad);
verts[4].set(rect.fRight - rad, rect.fBottom - rad);
verts[5].set(rect.fRight + rad, rect.fBottom + rad);
verts[6].set(rect.fLeft + rad, rect.fBottom - rad);
verts[7].set(rect.fLeft - rad, rect.fBottom + rad);
verts[8] = verts[0];
verts[9] = verts[1];
// TODO: we should be catching this higher up the call stack and just draw a single
// non-AA rect
if (2*rad >= rect.width()) {
verts[0].fX = verts[2].fX = verts[4].fX = verts[6].fX = verts[8].fX = rect.centerX();
}
if (2*rad >= rect.height()) {
verts[0].fY = verts[2].fY = verts[4].fY = verts[6].fY = verts[8].fY = rect.centerY();
}
}
class NonAAStrokeRectOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelper;
public:
DEFINE_OP_CLASS_ID
const char* name() const override { return "NonAAStrokeRectOp"; }
void visitProxies(const VisitProxyFunc& func, VisitorType) const override {
fHelper.visitProxies(func);
}
#ifdef SK_DEBUG
SkString dumpInfo() const override {
SkString string;
string.appendf(
"Color: 0x%08x, Rect [L: %.2f, T: %.2f, R: %.2f, B: %.2f], "
"StrokeWidth: %.2f\n",
fColor.toBytes_RGBA(), fRect.fLeft, fRect.fTop, fRect.fRight, fRect.fBottom,
fStrokeWidth);
string += fHelper.dumpInfo();
string += INHERITED::dumpInfo();
return string;
}
#endif
static std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkStrokeRec& stroke,
GrAAType aaType) {
bool isMiter;
if (!allowed_stroke(stroke, GrAA::kNo, &isMiter)) {
return nullptr;
}
Helper::Flags flags = Helper::Flags::kNone;
// Depending on sub-pixel coordinates and the particular GPU, we may lose a corner of
// hairline rects. We jam all the vertices to pixel centers to avoid this, but not
// when MSAA is enabled because it can cause ugly artifacts.
if (stroke.getStyle() == SkStrokeRec::kHairline_Style && aaType != GrAAType::kMSAA) {
flags |= Helper::Flags::kSnapVerticesToPixelCenters;
}
return Helper::FactoryHelper<NonAAStrokeRectOp>(context, std::move(paint), flags,
viewMatrix, rect,
stroke, aaType);
}
NonAAStrokeRectOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color,
Helper::Flags flags, const SkMatrix& viewMatrix, const SkRect& rect,
const SkStrokeRec& stroke, GrAAType aaType)
: INHERITED(ClassID()), fHelper(helperArgs, aaType, flags) {
fColor = color;
fViewMatrix = viewMatrix;
fRect = rect;
// Sort the rect for hairlines
fRect.sort();
fStrokeWidth = stroke.getWidth();
SkScalar rad = SkScalarHalf(fStrokeWidth);
SkRect bounds = rect;
bounds.outset(rad, rad);
// If our caller snaps to pixel centers then we have to round out the bounds
if (flags & Helper::Flags::kSnapVerticesToPixelCenters) {
viewMatrix.mapRect(&bounds);
// We want to be consistent with how we snap non-aa lines. To match what we do in
// GrGLSLVertexShaderBuilder, we first floor all the vertex values and then add half a
// pixel to force us to pixel centers.
bounds.set(SkScalarFloorToScalar(bounds.fLeft),
SkScalarFloorToScalar(bounds.fTop),
SkScalarFloorToScalar(bounds.fRight),
SkScalarFloorToScalar(bounds.fBottom));
bounds.offset(0.5f, 0.5f);
this->setBounds(bounds, HasAABloat::kNo, IsZeroArea::kNo);
} else {
this->setTransformedBounds(bounds, fViewMatrix, HasAABloat::kNo, IsZeroArea::kNo);
}
}
FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override {
return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone,
&fColor);
}
private:
void onPrepareDraws(Target* target) override {
sk_sp<GrGeometryProcessor> gp;
{
using namespace GrDefaultGeoProcFactory;
Color color(fColor);
LocalCoords::Type localCoordsType = fHelper.usesLocalCoords()
? LocalCoords::kUsePosition_Type
: LocalCoords::kUnused_Type;
gp = GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(), color,
Coverage::kSolid_Type, localCoordsType,
fViewMatrix);
}
size_t kVertexStride = gp->vertexStride();
int vertexCount = kVertsPerHairlineRect;
if (fStrokeWidth > 0) {
vertexCount = kVertsPerStrokeRect;
}
const GrBuffer* vertexBuffer;
int firstVertex;
void* verts =
target->makeVertexSpace(kVertexStride, vertexCount, &vertexBuffer, &firstVertex);
if (!verts) {
SkDebugf("Could not allocate vertices\n");
return;
}
SkPoint* vertex = reinterpret_cast<SkPoint*>(verts);
GrPrimitiveType primType;
if (fStrokeWidth > 0) {
primType = GrPrimitiveType::kTriangleStrip;
init_nonaa_stroke_rect_strip(vertex, fRect, fStrokeWidth);
} else {
// hairline
primType = GrPrimitiveType::kLineStrip;
vertex[0].set(fRect.fLeft, fRect.fTop);
vertex[1].set(fRect.fRight, fRect.fTop);
vertex[2].set(fRect.fRight, fRect.fBottom);
vertex[3].set(fRect.fLeft, fRect.fBottom);
vertex[4].set(fRect.fLeft, fRect.fTop);
}
GrMesh* mesh = target->allocMesh(primType);
mesh->setNonIndexedNonInstanced(vertexCount);
mesh->setVertexData(vertexBuffer, firstVertex);
auto pipe = fHelper.makePipeline(target);
target->draw(std::move(gp), pipe.fPipeline, pipe.fFixedDynamicState, mesh);
}
// TODO: override onCombineIfPossible
Helper fHelper;
SkPMColor4f fColor;
SkMatrix fViewMatrix;
SkRect fRect;
SkScalar fStrokeWidth;
const static int kVertsPerHairlineRect = 5;
const static int kVertsPerStrokeRect = 10;
typedef GrMeshDrawOp INHERITED;
};
///////////////////////////////////////////////////////////////////////////////////////////////////
// AA Stroking
///////////////////////////////////////////////////////////////////////////////////////////////////
GR_DECLARE_STATIC_UNIQUE_KEY(gMiterIndexBufferKey);
GR_DECLARE_STATIC_UNIQUE_KEY(gBevelIndexBufferKey);
static void compute_aa_rects(SkRect* devOutside, SkRect* devOutsideAssist, SkRect* devInside,
bool* isDegenerate, const SkMatrix& viewMatrix, const SkRect& rect,
SkScalar strokeWidth, bool miterStroke) {
SkRect devRect;
viewMatrix.mapRect(&devRect, rect);
@ -90,10 +294,10 @@ static void compute_rects(SkRect* devOutside, SkRect* devOutsideAssist, SkRect*
}
}
static sk_sp<GrGeometryProcessor> create_stroke_rect_gp(const GrShaderCaps* shaderCaps,
bool tweakAlphaForCoverage,
const SkMatrix& viewMatrix,
bool usesLocalCoords) {
static sk_sp<GrGeometryProcessor> create_aa_stroke_rect_gp(const GrShaderCaps* shaderCaps,
bool tweakAlphaForCoverage,
const SkMatrix& viewMatrix,
bool usesLocalCoords) {
using namespace GrDefaultGeoProcFactory;
Coverage::Type coverageType;
@ -111,8 +315,6 @@ static sk_sp<GrGeometryProcessor> create_stroke_rect_gp(const GrShaderCaps* shad
viewMatrix);
}
namespace {
class AAStrokeRectOp final : public GrMeshDrawOp {
private:
using Helper = GrSimpleMeshDrawOpHelper;
@ -148,7 +350,7 @@ public:
const SkRect& rect,
const SkStrokeRec& stroke) {
bool isMiter;
if (!allowed_stroke(stroke, &isMiter)) {
if (!allowed_stroke(stroke, GrAA::kYes, &isMiter)) {
return nullptr;
}
return Helper::FactoryHelper<AAStrokeRectOp>(context, std::move(paint), viewMatrix, rect,
@ -163,8 +365,8 @@ public:
, fViewMatrix(viewMatrix) {
fMiterStroke = isMiter;
RectInfo& info = fRects.push_back();
compute_rects(&info.fDevOutside, &info.fDevOutsideAssist, &info.fDevInside,
&info.fDegenerate, viewMatrix, rect, stroke.getWidth(), isMiter);
compute_aa_rects(&info.fDevOutside, &info.fDevOutsideAssist, &info.fDevInside,
&info.fDegenerate, viewMatrix, rect, stroke.getWidth(), isMiter);
info.fColor = color;
if (isMiter) {
this->setBounds(info.fDevOutside, HasAABloat::kYes, IsZeroArea::kNo);
@ -254,13 +456,11 @@ private:
typedef GrMeshDrawOp INHERITED;
};
} // anonymous namespace
void AAStrokeRectOp::onPrepareDraws(Target* target) {
sk_sp<GrGeometryProcessor> gp(create_stroke_rect_gp(target->caps().shaderCaps(),
fHelper.compatibleWithAlphaAsCoverage(),
this->viewMatrix(),
fHelper.usesLocalCoords()));
sk_sp<GrGeometryProcessor> gp(create_aa_stroke_rect_gp(target->caps().shaderCaps(),
fHelper.compatibleWithAlphaAsCoverage(),
this->viewMatrix(),
fHelper.usesLocalCoords()));
if (!gp) {
SkDebugf("Couldn't create GrGeometryProcessor\n");
return;
@ -520,12 +720,31 @@ void AAStrokeRectOp::generateAAStrokeRectGeometry(GrVertexWriter& vertices,
}
}
namespace GrRectOpFactory {
} // anonymous namespace
std::unique_ptr<GrDrawOp> MakeAAFillNestedRects(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect rects[2]) {
namespace GrStrokeRectOp {
std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkStrokeRec& stroke) {
if (aaType == GrAAType::kCoverage) {
// The AA op only supports axis-aligned rectangles
if (!viewMatrix.rectStaysRect()) {
return nullptr;
}
return AAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, stroke);
} else {
return NonAAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, stroke, aaType);
}
}
std::unique_ptr<GrDrawOp> MakeNested(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect rects[2]) {
SkASSERT(viewMatrix.rectStaysRect());
SkASSERT(!rects[0].isEmpty() && !rects[1].isEmpty());
@ -536,28 +755,35 @@ std::unique_ptr<GrDrawOp> MakeAAFillNestedRects(GrContext* context,
if (devOutside.isEmpty()) {
return nullptr;
}
return MakeAAFill(context, std::move(paint), viewMatrix, rects[0]);
return GrFillRectOp::Make(context, std::move(paint), GrAAType::kCoverage, viewMatrix,
rects[0]);
}
return AAStrokeRectOp::Make(context, std::move(paint), viewMatrix, devOutside, devInside);
}
std::unique_ptr<GrDrawOp> MakeAAStroke(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkStrokeRec& stroke) {
return AAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, stroke);
}
} // namespace GrRectOpFactory
///////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace GrStrokeRectOp
#if GR_TEST_UTILS
#include "GrDrawOpTest.h"
GR_DRAW_OP_TEST_DEFINE(NonAAStrokeRectOp) {
SkMatrix viewMatrix = GrTest::TestMatrix(random);
SkRect rect = GrTest::TestRect(random);
SkScalar strokeWidth = random->nextBool() ? 0.0f : 2.0f;
SkPaint strokePaint;
strokePaint.setStrokeWidth(strokeWidth);
strokePaint.setStyle(SkPaint::kStroke_Style);
strokePaint.setStrokeJoin(SkPaint::kMiter_Join);
SkStrokeRec strokeRec(strokePaint);
GrAAType aaType = GrAAType::kNone;
if (fsaaType == GrFSAAType::kUnifiedMSAA) {
aaType = random->nextBool() ? GrAAType::kMSAA : GrAAType::kNone;
}
return NonAAStrokeRectOp::Make(context, std::move(paint), viewMatrix, rect, strokeRec, aaType);
}
GR_DRAW_OP_TEST_DEFINE(AAStrokeRectOp) {
bool miterStroke = random->nextBool();
@ -572,7 +798,7 @@ GR_DRAW_OP_TEST_DEFINE(AAStrokeRectOp) {
rec.setStrokeParams(SkPaint::kButt_Cap,
miterStroke ? SkPaint::kMiter_Join : SkPaint::kBevel_Join, 1.f);
SkMatrix matrix = GrTest::TestMatrixRectStaysRect(random);
return GrRectOpFactory::MakeAAStroke(context, std::move(paint), matrix, rect, rec);
return AAStrokeRectOp::Make(context, std::move(paint), matrix, rect, rec);
}
#endif

View File

@ -0,0 +1,44 @@
/*
* 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 GrStrokeRectOp_DEFINED
#define GrStrokeRectOp_DEFINED
#include "GrTypesPriv.h"
class GrDrawOp;
class GrPaint;
class SkMatrix;
struct SkRect;
class SkStrokeRec;
/**
* A set of factory functions for drawing stroked rectangles either coverage-antialiased, or
* non-antialiased. The non-antialiased ops can be used with MSAA. As with other GrDrawOp factories,
* the GrPaint is only consumed by these methods if a valid op is returned. If null is returned then
* the paint is unmodified and may still be used.
*/
namespace GrStrokeRectOp {
std::unique_ptr<GrDrawOp> Make(GrContext* context,
GrPaint&& paint,
GrAAType aaType,
const SkMatrix& viewMatrix,
const SkRect& rect,
const SkStrokeRec& stroke);
// rects[0] == outer rectangle, rects[1] == inner rectangle. Null return means there is nothing to
// draw rather than failure. The area between the rectangles will be filled by the paint, and it
// will be anti-aliased with coverage AA. viewMatrix.rectStaysRect() must be true.
std::unique_ptr<GrDrawOp> MakeNested(GrContext* context,
GrPaint&& paint,
const SkMatrix& viewMatrix,
const SkRect rects[2]);
} // namespace GrStrokeRectOp
#endif // GrStrokeRectOp_DEFINED

View File

@ -138,9 +138,9 @@ DEF_GPUTEST(SoftwarePathRendererCacheTest, reporter, /* options */) {
return new GrSoftwarePathRenderer(ctx->contextPriv().proxyProvider(), true);
};
// Software path renderer creates a mask texture, but also renders with a non-AA rect, which
// refs the quad index buffer.
const int kExpectedResources = 2;
// Software path renderer creates a mask texture and renders with a non-AA rect, but the flush
// only contains a single quad so GrFillRectOp doesn't need to use the shared index buffer.
const int kExpectedResources = 1;
test_path(reporter, create_concave_path, createPR, kExpectedResources, GrAAType::kCoverage);

View File

@ -19,8 +19,8 @@
#include "GrResourceProvider.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "ops/GrFillRectOp.h"
#include "ops/GrMeshDrawOp.h"
#include "ops/GrRectOpFactory.h"
#include "TestUtils.h"
#include <atomic>
@ -259,9 +259,8 @@ void test_draw_op(GrContext* context,
paint.addColorFragmentProcessor(std::move(fp));
paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
auto op = GrRectOpFactory::MakeNonAAFill(context, std::move(paint), SkMatrix::I(),
SkRect::MakeWH(rtc->width(), rtc->height()),
GrAAType::kNone);
auto op = GrFillRectOp::Make(context, std::move(paint), GrAAType::kNone, SkMatrix::I(),
SkRect::MakeWH(rtc->width(), rtc->height()));
rtc->addDrawOp(GrNoClip(), std::move(op));
}
@ -519,7 +518,7 @@ DEF_GPUTEST_FOR_GL_RENDERING_CONTEXTS(ProcessorOptimizationValidationTest, repor
// violating the optimizations, it's reasonable to expect it to violate requirements on
// a large number of pixels in the image. Sporadic pixel violations are more indicative
// of device errors and represents a separate problem.
#if defined(SK_SKQP_GLOBAL_ERROR_TOLERANCE)
#if defined(SK_BUILD_FOR_SKQP)
static constexpr int kMaxAcceptableFailedPixels = 0; // Strict when running as SKQP
#else
static constexpr int kMaxAcceptableFailedPixels = 2 * kRenderSize; // ~0.7% of the image

View File

@ -672,8 +672,29 @@ static sk_sp<SkSurface> create_gpu_surface_backend_texture(
GrContext* context, int sampleCnt, uint32_t color, GrBackendTexture* outTexture) {
GrGpu* gpu = context->contextPriv().getGpu();
// On Pixel and Pixel2XL's with Adreno 530 and 540s, setting width and height to 10s reliably
// triggers what appears to be a driver race condition where the 10x10 surface from the
// OverdrawSurface_gpu test is reused(?) for this surface created by the SurfacePartialDraw_gpu
// test.
//
// Immediately after creation of this surface, readback shows the correct initial solid color.
// However, sometime before content is rendered into the upper half of the surface, the driver
// presumably cleans up the OverdrawSurface_gpu's memory which corrupts this color buffer. The
// top half of the surface is fine after the partially-covering rectangle is drawn, but the
// untouched bottom half contains random pixel values that trigger asserts in the
// SurfacePartialDraw_gpu test for no longer matching the initial color. Running the
// SurfacePartialDraw_gpu test without the OverdrawSurface_gpu test completes successfully.
//
// Requesting a much larger backend texture size seems to prevent it from reusing the same
// memory and avoids the issue.
#if defined(SK_BUILD_FOR_SKQP)
const int kWidth = 10;
const int kHeight = 10;
#else
const int kWidth = 100;
const int kHeight = 100;
#endif
std::unique_ptr<uint32_t[]> pixels(new uint32_t[kWidth * kHeight]);
sk_memset32(pixels.get(), color, kWidth * kHeight);

View File

@ -290,7 +290,6 @@ const GrUniqueKey& GrCoverageCountingPathRenderer::testingOnly_getStashedAtlasKe
#define DRAW_OP_TEST_ENTRY(Op) Op##__Test
DRAW_OP_TEST_EXTERN(AAConvexPathOp);
DRAW_OP_TEST_EXTERN(AAFillRectOp);
DRAW_OP_TEST_EXTERN(AAFlatteningConvexPathOp);
DRAW_OP_TEST_EXTERN(AAHairlineOp);
DRAW_OP_TEST_EXTERN(AAStrokeRectOp);
@ -303,7 +302,6 @@ DRAW_OP_TEST_EXTERN(FillRectOp);
DRAW_OP_TEST_EXTERN(GrAtlasTextOp);
DRAW_OP_TEST_EXTERN(GrDrawAtlasOp);
DRAW_OP_TEST_EXTERN(GrDrawVerticesOp);
DRAW_OP_TEST_EXTERN(NonAAFillRectOp);
DRAW_OP_TEST_EXTERN(NonAALatticeOp);
DRAW_OP_TEST_EXTERN(NonAAStrokeRectOp);
DRAW_OP_TEST_EXTERN(ShadowRRectOp);
@ -318,7 +316,6 @@ void GrDrawRandomOp(SkRandom* random, GrRenderTargetContext* renderTargetContext
using MakeDrawOpFn = std::unique_ptr<GrDrawOp>(GrPaint&&, SkRandom*, GrContext*, GrFSAAType);
static constexpr MakeDrawOpFn* gFactories[] = {
DRAW_OP_TEST_ENTRY(AAConvexPathOp),
DRAW_OP_TEST_ENTRY(AAFillRectOp),
DRAW_OP_TEST_ENTRY(AAFlatteningConvexPathOp),
DRAW_OP_TEST_ENTRY(AAHairlineOp),
DRAW_OP_TEST_ENTRY(AAStrokeRectOp),
@ -331,7 +328,6 @@ void GrDrawRandomOp(SkRandom* random, GrRenderTargetContext* renderTargetContext
DRAW_OP_TEST_ENTRY(GrAtlasTextOp),
DRAW_OP_TEST_ENTRY(GrDrawAtlasOp),
DRAW_OP_TEST_ENTRY(GrDrawVerticesOp),
DRAW_OP_TEST_ENTRY(NonAAFillRectOp),
DRAW_OP_TEST_ENTRY(NonAALatticeOp),
DRAW_OP_TEST_ENTRY(NonAAStrokeRectOp),
DRAW_OP_TEST_ENTRY(ShadowRRectOp),

View File

@ -23,7 +23,7 @@ skia_use_libheif = false
skia_use_lua = false
skia_use_piex = false
skia_tools_require_resources = true
extra_cflags = [ "-DSK_ENABLE_DUMP_GPU" ]
extra_cflags = [ "-DSK_ENABLE_DUMP_GPU", "-DSK_BUILD_FOR_SKQP" ]
'''
def parse_args():