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:
parent
46f40f4247
commit
72ab3461b7
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
|
@ -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
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
44
src/gpu/ops/GrStrokeRectOp.h
Normal file
44
src/gpu/ops/GrStrokeRectOp.h
Normal 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
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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),
|
||||
|
@ -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():
|
||||
|
Loading…
Reference in New Issue
Block a user