| Index: src/gpu/draws/GrDrawRect.cpp
|
| diff --git a/src/gpu/draws/GrDrawRect.cpp b/src/gpu/draws/GrDrawRect.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..74d1956d493effeaad542fb582295b0fb1c59728
|
| --- /dev/null
|
| +++ b/src/gpu/draws/GrDrawRect.cpp
|
| @@ -0,0 +1,245 @@
|
| +/*
|
| + * 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 "GrDrawRect.h"
|
| +
|
| +#include "GrContext.h"
|
| +#include "GrDrawContext.h"
|
| +#include "GrClip.h"
|
| +#include "GrDrawTarget.h"
|
| +#include "GrRenderTarget.h"
|
| +#include "GrStrokeInfo.h"
|
| +#include "SkColorFilter.h"
|
| +#include "SkImageFilter.h"
|
| +#include "SkGr.h"
|
| +#include "SkMatrix.h"
|
| +#include "SkMaskFilter.h"
|
| +#include "SkPaint.h"
|
| +#include "SkRect.h"
|
| +#include "SkShader.h"
|
| +#include "SkXfermode.h"
|
| +#include "batches/GrRectBatchFactory.h"
|
| +
|
| +enum RectBatchType {
|
| + kAAStroke_RectBatchType,
|
| + kAAFill_RectBatchType,
|
| + kNonAAFill_RectBatchType,
|
| + kNonAAStroke_RectBatchType,
|
| +};
|
| +
|
| +/*
|
| + * GrDrawRectSnap rules:
|
| + * 1) We don't handle mask filters, because they can be multiple draws, though we could handle
|
| + * a subset
|
| + * 2) We don't handle image filters for the same reason
|
| + * 3) We don't handle color filters, because they aren't very common, and they don't always multiply
|
| + * As a result we can end up doing optimizations which can't be trivially reconstructed in the
|
| + * fast path
|
| + * 5) We only handle shaders which have the same pointer, though we can and should do a little bit
|
| + * more analysis here
|
| + * TODO compute short shader keys for the cases we care about
|
| + * 6) We don't bother looking at the clip, aside from wide open or same clip generation
|
| + * 7) We only handle src over, we might be able to handle other blend modes, but we have to be
|
| + * careful about not breaking things, especially re: optimizations
|
| + *
|
| + * TODO don't try to snap if we got an override color
|
| + */
|
| +class GrDrawRectSnap : public GrDrawSnap {
|
| +public:
|
| + GrDrawRectSnap(const SkPaint& paint,
|
| + const GrClip& clip,
|
| + RectBatchType type,
|
| + bool snapToPixelCenter)
|
| + : fShader(SkSafeRef(paint.getShader()))
|
| + , fType(type)
|
| + , fClipType(clip.clipType())
|
| + , fClipGenID(fClipType == GrClip::kClipStack_ClipType ?
|
| + clip.clipStack()->getTopmostGenID() :
|
| + -1)
|
| + , fSnapToPixelCenters(snapToPixelCenter)
|
| + , fIsDither(paint.isDither()) {
|
| + fClassID = GrDrawRect::ClassID();
|
| + }
|
| +
|
| + bool canBatch(const SkPaint& paint,
|
| + const GrClip& clip,
|
| + RectBatchType type,
|
| + bool snapToPixelCenters) const {
|
| + return fType == type &&
|
| + !paint.getXfermode() &&
|
| + !paint.getImageFilter() &&
|
| + !paint.getMaskFilter() &&
|
| + !paint.getColorFilter() &&
|
| + paint.getShader() == fShader &&
|
| + paint.isDither() == fIsDither &&
|
| + fClipType == clip.clipType() &&
|
| + (fClipType == GrClip::kWideOpen_ClipType ||
|
| + (fClipType == GrClip::kClipStack_ClipType &&
|
| + fClipGenID == clip.clipStack()->getTopmostGenID())) &&
|
| + fSnapToPixelCenters == snapToPixelCenters;
|
| + }
|
| +
|
| + // we only bother fast pathing kSrcOver_Mode, though we could do quite a bit more
|
| + static bool CanSnap(const SkPaint& paint) {
|
| + return !paint.getXfermode() &&
|
| + !paint.getColorFilter() &&
|
| + !paint.getMaskFilter() &&
|
| + !paint.getImageFilter();
|
| + }
|
| +
|
| +private:
|
| + SkAutoTUnref<SkShader> fShader;
|
| + RectBatchType fType;
|
| + GrClip::ClipType fClipType;
|
| + int32_t fClipGenID;
|
| + bool fSnapToPixelCenters;
|
| + bool fIsDither;
|
| +
|
| + typedef GrDrawSnap INHERITED;
|
| +};
|
| +
|
| +inline static RectBatchType compute_rect_batch_type(bool useAA, SkScalar width) {
|
| + if (useAA) {
|
| + if (width >= 0) {
|
| + return kAAStroke_RectBatchType;
|
| + } else {
|
| + return kAAFill_RectBatchType;
|
| + }
|
| + } else if (width >= 0) {
|
| + return kNonAAStroke_RectBatchType;
|
| + } else {
|
| + return kNonAAFill_RectBatchType;
|
| + }
|
| +}
|
| +
|
| +inline static bool attempt_fastpath(GrDrawContext* drawContext,
|
| + const SkPaint& paint,
|
| + const GrClip& clip,
|
| + GrColor color,
|
| + const SkMatrix& viewMatrix,
|
| + const SkRect& rect,
|
| + const GrStrokeInfo& strokeInfo,
|
| + RectBatchType batchType,
|
| + bool snapToPixelCenters,
|
| + const GrRenderTarget* rt) {
|
| + GrBatch* lastBatch = drawContext->lastBatch();
|
| + if (!lastBatch) {
|
| + return false;
|
| + }
|
| +
|
| + const GrDrawSnap* lastSnap = lastBatch->getDrawSnap();
|
| + if (!lastSnap) {
|
| + return false;
|
| + }
|
| +
|
| + if (lastSnap->classID() != GrDrawRect::ClassID()) {
|
| + return false;
|
| + }
|
| +
|
| + // TODO remove this and the RT arg when we have multidrawbuffer
|
| + // This downcast is safe because we only have drawbatches
|
| + const GrDrawBatch* drawBatch = reinterpret_cast<const GrDrawBatch*>(lastBatch);
|
| + if (rt != drawBatch->pipeline()->getRenderTarget()) {
|
| + return false;
|
| + }
|
| +
|
| + const GrDrawRectSnap* lastSnapCast = static_cast<const GrDrawRectSnap*>(lastSnap);
|
| + if (lastSnapCast->canBatch(paint, clip, batchType, snapToPixelCenters)) {
|
| + switch (batchType) {
|
| + case kAAStroke_RectBatchType:
|
| + if (GrAAStrokeRectBatch::Append(lastBatch, color, viewMatrix, rect,
|
| + strokeInfo)) {
|
| + return true;
|
| + }
|
| + break;
|
| + case kAAFill_RectBatchType:
|
| + if (GrAAFillRectBatch::Append(lastBatch, color, viewMatrix, rect)) {
|
| + return true;
|
| + }
|
| + break;
|
| + case kNonAAFill_RectBatchType:
|
| + if (GrNonAAFillRectBatch::Append(lastBatch, color, viewMatrix, rect,
|
| + nullptr, nullptr)) {
|
| + return true;
|
| + }
|
| + break;
|
| + case kNonAAStroke_RectBatchType:
|
| + // GrNonAAStrokeRectBatch doesn't batch yet
|
| + break;
|
| + }
|
| + }
|
| +
|
| + return false;
|
| +}
|
| +
|
| +void GrDrawRect::execute(GrDrawContext* drawContext) const {
|
| + const SkPaint& paint = *fPaint;
|
| + const GrClip& clip = *fClip;
|
| + const SkMatrix& viewMatrix = *fViewMatrix;
|
| + const SkRect& rect = *fRect;
|
| +
|
| + SkScalar width = nullptr == fStrokeInfo ? -1 : fStrokeInfo->getWidth();
|
| +
|
| + bool needAA = fPaint->isAntiAlias() && !fRenderTarget->isUnifiedMultisampled();
|
| +
|
| + // The fill path can handle rotation but not skew
|
| + // The stroke path needs the rect to remain axis aligned (no rotation or skew)
|
| + // None of our AA draw rect calls can handle perspective yet
|
| + bool canApplyAA = width >= 0 ? viewMatrix.rectStaysRect() : viewMatrix.preservesRightAngles();
|
| + bool useAA = needAA && canApplyAA;
|
| +
|
| + // Non-AA hairlines are snapped to pixel centers to make which pixels are hit deterministic
|
| + bool snapToPixelCenters = !useAA && (0 == width && !fRenderTarget->isUnifiedMultisampled());
|
| +
|
| + // TODO we also do this on the paint, do we need to?
|
| + SkColor paintColor = paint.getColor();
|
| + if (fPaint->getColorFilter() && !paint.getShader()) {
|
| + paintColor = paint.getColorFilter()->filterColor(paintColor);
|
| + }
|
| + GrColor color = SkColor2GrColor(paintColor);
|
| +
|
| + RectBatchType batchType = compute_rect_batch_type(useAA, width);
|
| + if (attempt_fastpath(drawContext, *fPaint, clip, color, viewMatrix, rect, *fStrokeInfo,
|
| + batchType, snapToPixelCenters, fRenderTarget)) {
|
| + return;
|
| + }
|
| +
|
| + SkAutoTUnref<GrDrawBatch> batch;
|
| + switch (batchType) {
|
| + case kAAStroke_RectBatchType:
|
| + batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, rect, *fStrokeInfo));
|
| + break;
|
| + case kAAFill_RectBatchType:
|
| + batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect));
|
| + break;
|
| + case kNonAAFill_RectBatchType:
|
| + batch.reset(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, rect, nullptr,
|
| + nullptr));
|
| + break;
|
| + case kNonAAStroke_RectBatchType:
|
| + batch.reset(GrRectBatchFactory::CreateNonAAStroke(color, viewMatrix, rect, width,
|
| + snapToPixelCenters));
|
| + break;
|
| + }
|
| +
|
| + GrPaint grPaint;
|
| + if (!SkPaint2GrPaint(fContext, paint, viewMatrix, true, &grPaint)) {
|
| + return;
|
| + }
|
| +
|
| + GrPipelineBuilder pipelineBuilder(grPaint, fRenderTarget, clip);
|
| +
|
| + // 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.
|
| + pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag,
|
| + snapToPixelCenters);
|
| + drawContext->drawBatch(pipelineBuilder, batch);
|
| + if (GrDrawRectSnap::CanSnap(paint)) {
|
| + batch->initSnapStorage<GrDrawRectSnap>(paint, clip, batchType, snapToPixelCenters);
|
| + }
|
| +}
|
|
|