OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2015 Google Inc. | 3 * Copyright 2015 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "GrAARectRenderer.h" | 9 #include "GrAARectRenderer.h" |
10 #include "GrBatch.h" | 10 #include "GrBatch.h" |
11 #include "GrBatchTest.h" | 11 #include "GrBatchTest.h" |
12 #include "GrDefaultGeoProcFactory.h" | 12 #include "GrDefaultGeoProcFactory.h" |
13 #include "GrDrawContext.h" | 13 #include "GrDrawContext.h" |
14 #include "GrOvalRenderer.h" | 14 #include "GrOvalRenderer.h" |
15 #include "GrPathRenderer.h" | 15 #include "GrPathRenderer.h" |
| 16 #include "SkGr.h" |
| 17 #include "SkMaskFilter.h" |
| 18 #include "SkPaint.h" |
16 | 19 |
17 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext) | 20 #define ASSERT_OWNED_RESOURCE(R) SkASSERT(!(R) || (R)->getContext() == fContext) |
18 #define RETURN_IF_ABANDONED if (!fDrawTarget) { return; } | 21 #define RETURN_IF_ABANDONED if (!fDrawTarget) { return; } |
19 #define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; } | 22 #define RETURN_FALSE_IF_ABANDONED if (!fDrawTarget) { return false; } |
20 #define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return NULL; } | 23 #define RETURN_NULL_IF_ABANDONED if (!fDrawTarget) { return NULL; } |
21 | 24 |
22 class AutoCheckFlush { | 25 class AutoCheckFlush { |
23 public: | 26 public: |
24 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} | 27 AutoCheckFlush(GrContext* context) : fContext(context) { SkASSERT(context);
} |
25 ~AutoCheckFlush() { fContext->flushIfNecessary(); } | 28 ~AutoCheckFlush() { fContext->flushIfNecessary(); } |
(...skipping 1009 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1035 ovalRect, | 1038 ovalRect, |
1036 strokeInfo)) { | 1039 strokeInfo)) { |
1037 return; | 1040 return; |
1038 } | 1041 } |
1039 } | 1042 } |
1040 } | 1043 } |
1041 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, pai
nt.isAntiAlias(), | 1044 this->internalDrawPath(fDrawTarget, &pipelineBuilder, viewMatrix, color, pai
nt.isAntiAlias(), |
1042 path, strokeInfo); | 1045 path, strokeInfo); |
1043 } | 1046 } |
1044 | 1047 |
| 1048 static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& r
ect) { |
| 1049 return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBo
unds, rect); |
| 1050 } |
| 1051 |
| 1052 // Draw a mask using the supplied paint. Since the coverage/geometry |
| 1053 // is already burnt into the mask this boils down to a rect draw. |
| 1054 // Return true if the mask was successfully drawn. |
| 1055 static bool draw_mask(GrDrawContext* drawContext, |
| 1056 GrRenderTarget* rt, |
| 1057 const GrClip& clip, |
| 1058 const SkMatrix& viewMatrix, |
| 1059 const SkRect& maskRect, |
| 1060 GrPaint* grp, |
| 1061 GrTexture* mask) { |
| 1062 SkMatrix matrix; |
| 1063 matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop); |
| 1064 matrix.postIDiv(mask->width(), mask->height()); |
| 1065 |
| 1066 grp->addCoverageProcessor(GrSimpleTextureEffect::Create(mask, matrix, |
| 1067 kDevice_GrCoordSet))
->unref(); |
| 1068 |
| 1069 SkMatrix inverse; |
| 1070 if (!viewMatrix.invert(&inverse)) { |
| 1071 return false; |
| 1072 } |
| 1073 drawContext->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), mas
kRect, inverse); |
| 1074 return true; |
| 1075 } |
| 1076 |
| 1077 static bool draw_with_mask_filter(GrDrawContext* drawContext, |
| 1078 GrTextureProvider* textureProvider, |
| 1079 GrRenderTarget* rt, |
| 1080 const GrClip& clipData, |
| 1081 const SkMatrix& viewMatrix, |
| 1082 const SkPath& devPath, |
| 1083 SkMaskFilter* filter, |
| 1084 const SkIRect& clipBounds, |
| 1085 GrPaint* grp, |
| 1086 SkPaint::Style style) { |
| 1087 SkMask srcM, dstM; |
| 1088 |
| 1089 if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM, |
| 1090 SkMask::kComputeBoundsAndRenderImage_CreateMode, sty
le)) { |
| 1091 return false; |
| 1092 } |
| 1093 SkAutoMaskFreeImage autoSrc(srcM.fImage); |
| 1094 |
| 1095 if (!filter->filterMask(&dstM, srcM, viewMatrix, NULL)) { |
| 1096 return false; |
| 1097 } |
| 1098 // this will free-up dstM when we're done (allocated in filterMask()) |
| 1099 SkAutoMaskFreeImage autoDst(dstM.fImage); |
| 1100 |
| 1101 if (clip_bounds_quick_reject(clipBounds, dstM.fBounds)) { |
| 1102 return false; |
| 1103 } |
| 1104 |
| 1105 // we now have a device-aligned 8bit mask in dstM, ready to be drawn using |
| 1106 // the current clip (and identity matrix) and GrPaint settings |
| 1107 GrSurfaceDesc desc; |
| 1108 desc.fWidth = dstM.fBounds.width(); |
| 1109 desc.fHeight = dstM.fBounds.height(); |
| 1110 desc.fConfig = kAlpha_8_GrPixelConfig; |
| 1111 |
| 1112 SkAutoTUnref<GrTexture> texture(textureProvider->refScratchTexture( |
| 1113 desc, GrTextureProvider::kApprox_ScratchTexMatch)); |
| 1114 if (!texture) { |
| 1115 return false; |
| 1116 } |
| 1117 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, |
| 1118 dstM.fImage, dstM.fRowBytes); |
| 1119 |
| 1120 SkRect maskRect = SkRect::Make(dstM.fBounds); |
| 1121 |
| 1122 return draw_mask(drawContext, rt, clipData, viewMatrix, maskRect, grp, textu
re); |
| 1123 } |
| 1124 |
| 1125 // Create a mask of 'devPath' and place the result in 'mask'. |
| 1126 static GrTexture* create_mask_GPU(GrContext* context, |
| 1127 const SkRect& maskRect, |
| 1128 const SkPath& devPath, |
| 1129 const GrStrokeInfo& strokeInfo, |
| 1130 bool doAA, |
| 1131 int sampleCnt) { |
| 1132 GrSurfaceDesc desc; |
| 1133 desc.fFlags = kRenderTarget_GrSurfaceFlag; |
| 1134 desc.fWidth = SkScalarCeilToInt(maskRect.width()); |
| 1135 desc.fHeight = SkScalarCeilToInt(maskRect.height()); |
| 1136 desc.fSampleCnt = doAA ? sampleCnt : 0; |
| 1137 // We actually only need A8, but it often isn't supported as a |
| 1138 // render target so default to RGBA_8888 |
| 1139 desc.fConfig = kRGBA_8888_GrPixelConfig; |
| 1140 |
| 1141 if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, |
| 1142 desc.fSampleCnt > 0)) { |
| 1143 desc.fConfig = kAlpha_8_GrPixelConfig; |
| 1144 } |
| 1145 |
| 1146 GrTexture* mask = context->textureProvider()->refScratchTexture( |
| 1147 desc, GrTextureProvider::kApprox_ScratchTexMatch); |
| 1148 if (NULL == mask) { |
| 1149 return NULL; |
| 1150 } |
| 1151 |
| 1152 SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height()); |
| 1153 |
| 1154 GrDrawContext* drawContext = context->drawContext(); |
| 1155 if (!drawContext) { |
| 1156 return NULL; |
| 1157 } |
| 1158 |
| 1159 drawContext->clear(mask->asRenderTarget(), NULL, 0x0, true); |
| 1160 |
| 1161 GrPaint tempPaint; |
| 1162 tempPaint.setAntiAlias(doAA); |
| 1163 tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op); |
| 1164 |
| 1165 // setup new clip |
| 1166 GrClip clip(clipRect); |
| 1167 |
| 1168 // Draw the mask into maskTexture with the path's top-left at the origin usi
ng tempPaint. |
| 1169 SkMatrix translate; |
| 1170 translate.setTranslate(-maskRect.fLeft, -maskRect.fTop); |
| 1171 drawContext->drawPath(mask->asRenderTarget(), clip, tempPaint, translate, de
vPath, strokeInfo); |
| 1172 return mask; |
| 1173 } |
| 1174 |
| 1175 void GrDrawContext::drawPathFull(GrContext* context, |
| 1176 GrRenderTarget* renderTarget, |
| 1177 const GrClip& clip, |
| 1178 const SkPath& origSrcPath, |
| 1179 const SkPaint& paint, |
| 1180 const SkMatrix& origViewMatrix, |
| 1181 const SkMatrix* prePathMatrix, |
| 1182 const SkIRect& clipBounds, |
| 1183 bool pathIsMutable) { |
| 1184 SkASSERT(!pathIsMutable || origSrcPath.isVolatile()); |
| 1185 |
| 1186 GrStrokeInfo strokeInfo(paint); |
| 1187 |
| 1188 // If we have a prematrix, apply it to the path, optimizing for the case |
| 1189 // where the original path can in fact be modified in place (even though |
| 1190 // its parameter type is const). |
| 1191 SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath); |
| 1192 SkTLazy<SkPath> tmpPath; |
| 1193 SkTLazy<SkPath> effectPath; |
| 1194 SkPathEffect* pathEffect = paint.getPathEffect(); |
| 1195 |
| 1196 SkMatrix viewMatrix = origViewMatrix; |
| 1197 |
| 1198 if (prePathMatrix) { |
| 1199 // stroking, path effects, and blurs are supposed to be applied *after*
the prePathMatrix. |
| 1200 // The pre-path-matrix also should not affect shading. |
| 1201 if (NULL == paint.getMaskFilter() && NULL == pathEffect && NULL == paint
.getShader() && |
| 1202 (strokeInfo.isFillStyle() || strokeInfo.isHairlineStyle())) { |
| 1203 viewMatrix.preConcat(*prePathMatrix); |
| 1204 } else { |
| 1205 SkPath* result = pathPtr; |
| 1206 |
| 1207 if (!pathIsMutable) { |
| 1208 result = tmpPath.init(); |
| 1209 result->setIsVolatile(true); |
| 1210 pathIsMutable = true; |
| 1211 } |
| 1212 // should I push prePathMatrix on our MV stack temporarily, instead |
| 1213 // of applying it here? See SkDraw.cpp |
| 1214 pathPtr->transform(*prePathMatrix, result); |
| 1215 pathPtr = result; |
| 1216 } |
| 1217 } |
| 1218 // at this point we're done with prePathMatrix |
| 1219 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;) |
| 1220 |
| 1221 GrPaint grPaint; |
| 1222 if (!SkPaint2GrPaint(context, renderTarget, paint, viewMatrix, true, &grPain
t)) { |
| 1223 return; |
| 1224 } |
| 1225 |
| 1226 const SkRect* cullRect = NULL; // TODO: what is our bounds? |
| 1227 if (!strokeInfo.isDashed() && pathEffect && pathEffect->filterPath(effectPat
h.init(), *pathPtr, |
| 1228 &strokeIn
fo, cullRect)) { |
| 1229 pathPtr = effectPath.get(); |
| 1230 pathIsMutable = true; |
| 1231 } |
| 1232 |
| 1233 if (paint.getMaskFilter()) { |
| 1234 if (!strokeInfo.isHairlineStyle()) { |
| 1235 SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init(); |
| 1236 if (strokeInfo.isDashed()) { |
| 1237 if (pathEffect->filterPath(strokedPath, *pathPtr, &strokeInfo, c
ullRect)) { |
| 1238 pathPtr = strokedPath; |
| 1239 pathIsMutable = true; |
| 1240 } |
| 1241 strokeInfo.removeDash(); |
| 1242 } |
| 1243 if (strokeInfo.applyToPath(strokedPath, *pathPtr)) { |
| 1244 pathPtr = strokedPath; |
| 1245 pathIsMutable = true; |
| 1246 strokeInfo.setFillStyle(); |
| 1247 } |
| 1248 } |
| 1249 |
| 1250 // avoid possibly allocating a new path in transform if we can |
| 1251 SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init(); |
| 1252 if (!pathIsMutable) { |
| 1253 devPathPtr->setIsVolatile(true); |
| 1254 } |
| 1255 |
| 1256 // transform the path into device space |
| 1257 pathPtr->transform(viewMatrix, devPathPtr); |
| 1258 |
| 1259 SkRect maskRect; |
| 1260 if (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(), |
| 1261 clipBounds, |
| 1262 viewMatrix, |
| 1263 &maskRect)) { |
| 1264 SkIRect finalIRect; |
| 1265 maskRect.roundOut(&finalIRect); |
| 1266 if (clip_bounds_quick_reject(clipBounds, finalIRect)) { |
| 1267 // clipped out |
| 1268 return; |
| 1269 } |
| 1270 |
| 1271 if (paint.getMaskFilter()->directFilterMaskGPU(context, |
| 1272 renderTarget, |
| 1273 &grPaint, |
| 1274 clip, |
| 1275 viewMatrix, |
| 1276 strokeInfo, |
| 1277 *devPathPtr)) { |
| 1278 // the mask filter was able to draw itself directly, so there's
nothing |
| 1279 // left to do. |
| 1280 return; |
| 1281 } |
| 1282 |
| 1283 |
| 1284 SkAutoTUnref<GrTexture> mask(create_mask_GPU(context, |
| 1285 maskRect, |
| 1286 *devPathPtr, |
| 1287 strokeInfo, |
| 1288 grPaint.isAntiAlias(), |
| 1289 renderTarget->numSample
s())); |
| 1290 if (mask) { |
| 1291 GrTexture* filtered; |
| 1292 |
| 1293 if (paint.getMaskFilter()->filterMaskGPU(mask, viewMatrix, maskR
ect, |
| 1294 &filtered, true)) { |
| 1295 // filterMaskGPU gives us ownership of a ref to the result |
| 1296 SkAutoTUnref<GrTexture> atu(filtered); |
| 1297 if (draw_mask(this, |
| 1298 renderTarget, |
| 1299 clip, |
| 1300 viewMatrix, |
| 1301 maskRect, |
| 1302 &grPaint, |
| 1303 filtered)) { |
| 1304 // This path is completely drawn |
| 1305 return; |
| 1306 } |
| 1307 } |
| 1308 } |
| 1309 } |
| 1310 |
| 1311 // draw the mask on the CPU - this is a fallthrough path in case the |
| 1312 // GPU path fails |
| 1313 SkPaint::Style style = strokeInfo.isHairlineStyle() ? SkPaint::kStroke_S
tyle : |
| 1314 SkPaint::kFill_Sty
le; |
| 1315 draw_with_mask_filter(this, context->textureProvider(), renderTarget, |
| 1316 clip, viewMatrix, *devPathPtr, |
| 1317 paint.getMaskFilter(), clipBounds, &grPaint, style
); |
| 1318 return; |
| 1319 } |
| 1320 |
| 1321 this->drawPath(renderTarget, clip, grPaint, viewMatrix, *pathPtr, strokeInfo
); |
| 1322 } |
| 1323 |
| 1324 |
1045 void GrDrawContext::internalDrawPath(GrDrawTarget* target, | 1325 void GrDrawContext::internalDrawPath(GrDrawTarget* target, |
1046 GrPipelineBuilder* pipelineBuilder, | 1326 GrPipelineBuilder* pipelineBuilder, |
1047 const SkMatrix& viewMatrix, | 1327 const SkMatrix& viewMatrix, |
1048 GrColor color, | 1328 GrColor color, |
1049 bool useAA, | 1329 bool useAA, |
1050 const SkPath& path, | 1330 const SkPath& path, |
1051 const GrStrokeInfo& strokeInfo) { | 1331 const GrStrokeInfo& strokeInfo) { |
1052 RETURN_IF_ABANDONED | 1332 RETURN_IF_ABANDONED |
1053 SkASSERT(!path.isEmpty()); | 1333 SkASSERT(!path.isEmpty()); |
1054 | 1334 |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1262 return DrawVerticesBatch::Create(geometry, type, viewMatrix, | 1542 return DrawVerticesBatch::Create(geometry, type, viewMatrix, |
1263 positions.begin(), vertexCount, | 1543 positions.begin(), vertexCount, |
1264 indices.begin(), hasIndices ? vertexCount :
0, | 1544 indices.begin(), hasIndices ? vertexCount :
0, |
1265 colors.begin(), | 1545 colors.begin(), |
1266 texCoords.begin(), | 1546 texCoords.begin(), |
1267 bounds); | 1547 bounds); |
1268 } | 1548 } |
1269 | 1549 |
1270 #endif | 1550 #endif |
1271 | 1551 |
OLD | NEW |