OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2015 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
| 7 |
| 8 #include "GrDrawRect.h" |
| 9 |
| 10 #include "GrContext.h" |
| 11 #include "GrDrawContext.h" |
| 12 #include "GrClip.h" |
| 13 #include "GrDrawTarget.h" |
| 14 #include "GrRenderTarget.h" |
| 15 #include "GrStrokeInfo.h" |
| 16 #include "SkColorFilter.h" |
| 17 #include "SkImageFilter.h" |
| 18 #include "SkGr.h" |
| 19 #include "SkMatrix.h" |
| 20 #include "SkMaskFilter.h" |
| 21 #include "SkPaint.h" |
| 22 #include "SkRect.h" |
| 23 #include "SkShader.h" |
| 24 #include "SkXfermode.h" |
| 25 #include "batches/GrRectBatchFactory.h" |
| 26 |
| 27 enum RectBatchType { |
| 28 kAAStroke_RectBatchType, |
| 29 kAAFill_RectBatchType, |
| 30 kNonAAFill_RectBatchType, |
| 31 kNonAAStroke_RectBatchType, |
| 32 }; |
| 33 |
| 34 /* |
| 35 * GrDrawRectSnap rules: |
| 36 * 1) We don't handle mask filters, because they can be multiple draws, though w
e could handle |
| 37 * a subset |
| 38 * 2) We don't handle image filters for the same reason |
| 39 * 3) We don't handle color filters, because they aren't very common, and they d
on't always multiply |
| 40 * As a result we can end up doing optimizations which can't be trivially rec
onstructed in the |
| 41 * fast path |
| 42 * 5) We only handle shaders which have the same pointer, though we can and shou
ld do a little bit |
| 43 * more analysis here |
| 44 * TODO compute short shader keys for the cases we care about |
| 45 * 6) We don't bother looking at the clip, aside from wide open or same clip gen
eration |
| 46 * 7) We only handle src over, we might be able to handle other blend modes, but
we have to be |
| 47 * careful about not breaking things, especially re: optimizations |
| 48 * |
| 49 * TODO don't try to snap if we got an override color |
| 50 */ |
| 51 class GrDrawRectSnap : public GrDrawSnap { |
| 52 public: |
| 53 GrDrawRectSnap(const SkPaint& paint, |
| 54 const GrClip& clip, |
| 55 RectBatchType type, |
| 56 bool snapToPixelCenter) |
| 57 : fShader(SkSafeRef(paint.getShader())) |
| 58 , fType(type) |
| 59 , fClipType(clip.clipType()) |
| 60 , fClipGenID(fClipType == GrClip::kClipStack_ClipType ? |
| 61 clip.clipStack()->getTopmostGenID() : |
| 62 -1) |
| 63 , fSnapToPixelCenters(snapToPixelCenter) |
| 64 , fIsDither(paint.isDither()) { |
| 65 fClassID = GrDrawRect::ClassID(); |
| 66 } |
| 67 |
| 68 bool canBatch(const SkPaint& paint, |
| 69 const GrClip& clip, |
| 70 RectBatchType type, |
| 71 bool snapToPixelCenters) const { |
| 72 return fType == type && |
| 73 !paint.getXfermode() && |
| 74 !paint.getImageFilter() && |
| 75 !paint.getMaskFilter() && |
| 76 !paint.getColorFilter() && |
| 77 paint.getShader() == fShader && |
| 78 paint.isDither() == fIsDither && |
| 79 fClipType == clip.clipType() && |
| 80 (fClipType == GrClip::kWideOpen_ClipType || |
| 81 (fClipType == GrClip::kClipStack_ClipType && |
| 82 fClipGenID == clip.clipStack()->getTopmostGenID())) && |
| 83 fSnapToPixelCenters == snapToPixelCenters; |
| 84 } |
| 85 |
| 86 // we only bother fast pathing kSrcOver_Mode, though we could do quite a bit
more |
| 87 static bool CanSnap(const SkPaint& paint) { |
| 88 return !paint.getXfermode() && |
| 89 !paint.getColorFilter() && |
| 90 !paint.getMaskFilter() && |
| 91 !paint.getImageFilter(); |
| 92 } |
| 93 |
| 94 private: |
| 95 SkAutoTUnref<SkShader> fShader; |
| 96 RectBatchType fType; |
| 97 GrClip::ClipType fClipType; |
| 98 int32_t fClipGenID; |
| 99 bool fSnapToPixelCenters; |
| 100 bool fIsDither; |
| 101 |
| 102 typedef GrDrawSnap INHERITED; |
| 103 }; |
| 104 |
| 105 inline static RectBatchType compute_rect_batch_type(bool useAA, SkScalar width)
{ |
| 106 if (useAA) { |
| 107 if (width >= 0) { |
| 108 return kAAStroke_RectBatchType; |
| 109 } else { |
| 110 return kAAFill_RectBatchType; |
| 111 } |
| 112 } else if (width >= 0) { |
| 113 return kNonAAStroke_RectBatchType; |
| 114 } else { |
| 115 return kNonAAFill_RectBatchType; |
| 116 } |
| 117 } |
| 118 |
| 119 inline static bool attempt_fastpath(GrDrawContext* drawContext, |
| 120 const SkPaint& paint, |
| 121 const GrClip& clip, |
| 122 GrColor color, |
| 123 const SkMatrix& viewMatrix, |
| 124 const SkRect& rect, |
| 125 const GrStrokeInfo& strokeInfo, |
| 126 RectBatchType batchType, |
| 127 bool snapToPixelCenters, |
| 128 const GrRenderTarget* rt) { |
| 129 GrBatch* lastBatch = drawContext->lastBatch(); |
| 130 if (!lastBatch) { |
| 131 return false; |
| 132 } |
| 133 |
| 134 const GrDrawSnap* lastSnap = lastBatch->getDrawSnap(); |
| 135 if (!lastSnap) { |
| 136 return false; |
| 137 } |
| 138 |
| 139 if (lastSnap->classID() != GrDrawRect::ClassID()) { |
| 140 return false; |
| 141 } |
| 142 |
| 143 // TODO remove this and the RT arg when we have multidrawbuffer |
| 144 // This downcast is safe because we only have drawbatches |
| 145 const GrDrawBatch* drawBatch = reinterpret_cast<const GrDrawBatch*>(lastBatc
h); |
| 146 if (rt != drawBatch->pipeline()->getRenderTarget()) { |
| 147 return false; |
| 148 } |
| 149 |
| 150 const GrDrawRectSnap* lastSnapCast = static_cast<const GrDrawRectSnap*>(last
Snap); |
| 151 if (lastSnapCast->canBatch(paint, clip, batchType, snapToPixelCenters)) { |
| 152 switch (batchType) { |
| 153 case kAAStroke_RectBatchType: |
| 154 if (GrAAStrokeRectBatch::Append(lastBatch, color, viewMatrix, re
ct, |
| 155 strokeInfo)) { |
| 156 return true; |
| 157 } |
| 158 break; |
| 159 case kAAFill_RectBatchType: |
| 160 if (GrAAFillRectBatch::Append(lastBatch, color, viewMatrix, rect
)) { |
| 161 return true; |
| 162 } |
| 163 break; |
| 164 case kNonAAFill_RectBatchType: |
| 165 if (GrNonAAFillRectBatch::Append(lastBatch, color, viewMatrix, r
ect, |
| 166 nullptr, nullptr)) { |
| 167 return true; |
| 168 } |
| 169 break; |
| 170 case kNonAAStroke_RectBatchType: |
| 171 // GrNonAAStrokeRectBatch doesn't batch yet |
| 172 break; |
| 173 } |
| 174 } |
| 175 |
| 176 return false; |
| 177 } |
| 178 |
| 179 void GrDrawRect::execute(GrDrawContext* drawContext) const { |
| 180 const SkPaint& paint = *fPaint; |
| 181 const GrClip& clip = *fClip; |
| 182 const SkMatrix& viewMatrix = *fViewMatrix; |
| 183 const SkRect& rect = *fRect; |
| 184 |
| 185 SkScalar width = nullptr == fStrokeInfo ? -1 : fStrokeInfo->getWidth(); |
| 186 |
| 187 bool needAA = fPaint->isAntiAlias() && !fRenderTarget->isUnifiedMultisampled
(); |
| 188 |
| 189 // The fill path can handle rotation but not skew |
| 190 // The stroke path needs the rect to remain axis aligned (no rotation or ske
w) |
| 191 // None of our AA draw rect calls can handle perspective yet |
| 192 bool canApplyAA = width >= 0 ? viewMatrix.rectStaysRect() : viewMatrix.prese
rvesRightAngles(); |
| 193 bool useAA = needAA && canApplyAA; |
| 194 |
| 195 // Non-AA hairlines are snapped to pixel centers to make which pixels are hi
t deterministic |
| 196 bool snapToPixelCenters = !useAA && (0 == width && !fRenderTarget->isUnified
Multisampled()); |
| 197 |
| 198 // TODO we also do this on the paint, do we need to? |
| 199 SkColor paintColor = paint.getColor(); |
| 200 if (fPaint->getColorFilter() && !paint.getShader()) { |
| 201 paintColor = paint.getColorFilter()->filterColor(paintColor); |
| 202 } |
| 203 GrColor color = SkColor2GrColor(paintColor); |
| 204 |
| 205 RectBatchType batchType = compute_rect_batch_type(useAA, width); |
| 206 if (attempt_fastpath(drawContext, *fPaint, clip, color, viewMatrix, rect, *f
StrokeInfo, |
| 207 batchType, snapToPixelCenters, fRenderTarget)) { |
| 208 return; |
| 209 } |
| 210 |
| 211 SkAutoTUnref<GrDrawBatch> batch; |
| 212 switch (batchType) { |
| 213 case kAAStroke_RectBatchType: |
| 214 batch.reset(GrRectBatchFactory::CreateAAStroke(color, viewMatrix, re
ct, *fStrokeInfo)); |
| 215 break; |
| 216 case kAAFill_RectBatchType: |
| 217 batch.reset(GrRectBatchFactory::CreateAAFill(color, viewMatrix, rect
)); |
| 218 break; |
| 219 case kNonAAFill_RectBatchType: |
| 220 batch.reset(GrRectBatchFactory::CreateNonAAFill(color, viewMatrix, r
ect, nullptr, |
| 221 nullptr)); |
| 222 break; |
| 223 case kNonAAStroke_RectBatchType: |
| 224 batch.reset(GrRectBatchFactory::CreateNonAAStroke(color, viewMatrix,
rect, width, |
| 225 snapToPixelCenters
)); |
| 226 break; |
| 227 } |
| 228 |
| 229 GrPaint grPaint; |
| 230 if (!SkPaint2GrPaint(fContext, paint, viewMatrix, true, &grPaint)) { |
| 231 return; |
| 232 } |
| 233 |
| 234 GrPipelineBuilder pipelineBuilder(grPaint, fRenderTarget, clip); |
| 235 |
| 236 // Depending on sub-pixel coordinates and the particular GPU, we may lose a
corner of |
| 237 // hairline rects. We jam all the vertices to pixel centers to avoid this, b
ut not when MSAA |
| 238 // is enabled because it can cause ugly artifacts. |
| 239 pipelineBuilder.setState(GrPipelineBuilder::kSnapVerticesToPixelCenters_Flag
, |
| 240 snapToPixelCenters); |
| 241 drawContext->drawBatch(pipelineBuilder, batch); |
| 242 if (GrDrawRectSnap::CanSnap(paint)) { |
| 243 batch->initSnapStorage<GrDrawRectSnap>(paint, clip, batchType, snapToPix
elCenters); |
| 244 } |
| 245 } |
OLD | NEW |