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..22b98208dd2aecfe2bcaed771c61f1014d050808 |
--- /dev/null |
+++ b/src/gpu/draws/GrDrawRect.cpp |
@@ -0,0 +1,215 @@ |
+/* |
+ * 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 "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, |
+}; |
+ |
+class GrDrawRectSnap : public GrDrawSnap { |
+public: |
+ GrDrawRectSnap(const SkPaint& paint, |
+ const GrClip& clip, |
+ RectBatchType type, |
+ bool snapToPixelCenter) |
+ : fShader(SkSafeRef(paint.getShader())) |
+ , fMaskFilter(SkSafeRef(paint.getMaskFilter())) |
+ , fImageFilter(SkSafeRef(paint.getImageFilter())) |
+ , fColorFilter(SkSafeRef(paint.getColorFilter())) |
+ , fClipGenID(clip.clipType() != GrClip::kClipStack_ClipType ? |
+ -1 : |
+ clip.clipStack()->getTopmostGenID()) |
+ , fType(type) |
+ , fSnapToPixelCenters(snapToPixelCenter) |
+ , fIsDither(paint.isDither()) { |
+ fClassID = GrDrawRect::ClassID(); |
+ } |
+ |
+ bool canBatch(const SkPaint& paint, |
+ const GrClip& clip, |
+ RectBatchType type, |
+ bool snapToPixelCenters) const { |
+ return paint.getShader() == fShader && |
+ paint.getMaskFilter() == fMaskFilter && |
+ paint.getImageFilter() == fImageFilter && |
+ paint.getColorFilter() == fColorFilter && |
+ paint.isDither() == fIsDither && |
+ fClipGenID != -1 && clip.clipType() == GrClip::kClipStack_ClipType && |
+ fClipGenID == clip.clipStack()->getTopmostGenID() && |
+ fType == type && |
+ fSnapToPixelCenters == snapToPixelCenters; |
+ } |
+ |
+ // we only bother fast pathing kSrcOver_Mode, though we could do quite a bit more |
+ static bool CanSnap(const SkPaint& paint) { |
+ return SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode); |
+ } |
+ |
+private: |
+ SkAutoTUnref<SkShader> fShader; |
+ SkAutoTUnref<SkMaskFilter> fMaskFilter; |
+ SkAutoTUnref<SkImageFilter> fImageFilter; |
+ SkAutoTUnref<SkColorFilter> fColorFilter; |
+ int32_t fClipGenID; |
+ RectBatchType fType; |
+ 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 can_fastpath(GrDrawTarget* drawTarget, |
+ const SkPaint& paint, |
+ const GrClip& clip, |
+ GrColor color, |
+ const SkMatrix& viewMatrix, |
+ const SkRect& rect, |
+ const GrStrokeInfo& strokeInfo, |
+ RectBatchType batchType, |
+ bool snapToPixelCenters) { |
+ GrBatch* lastBatch = drawTarget->lastBatch(); |
+ if (!lastBatch) { |
+ return false; |
+ } |
+ |
+ const GrDrawSnap* lastSnap = lastBatch->drawSnap(); |
+ if (!lastSnap) { |
+ return false; |
+ } |
+ |
+ if (lastSnap->classID() != GrDrawRect::ClassID()) { |
+ 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: |
+ GrAAFillRectBatch::Append(lastBatch, color, viewMatrix, rect); |
+ return true; |
+ 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(GrDrawTarget* drawTarget) 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 (can_fastpath(drawTarget, *fPaint, clip, color, viewMatrix, rect, *fStrokeInfo, batchType, |
+ snapToPixelCenters)) { |
+ 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, fRenderTarget, 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); |
+ drawTarget->drawBatch(pipelineBuilder, batch); |
+ if (GrDrawRectSnap::CanSnap(paint)) { |
+ batch->setDrawSnap(new GrDrawRectSnap(paint, clip, batchType, snapToPixelCenters)); |
+ } |
+} |