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); |
+ } |
+} |