GrGLPath.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * Copyright 2012 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. #include "src/gpu/GrStyle.h"
  8. #include "src/gpu/gl/GrGLGpu.h"
  9. #include "src/gpu/gl/GrGLPath.h"
  10. #include "src/gpu/gl/GrGLPathRendering.h"
  11. namespace {
  12. inline GrGLubyte verb_to_gl_path_cmd(SkPath::Verb verb) {
  13. static const GrGLubyte gTable[] = {
  14. GR_GL_MOVE_TO,
  15. GR_GL_LINE_TO,
  16. GR_GL_QUADRATIC_CURVE_TO,
  17. GR_GL_CONIC_CURVE_TO,
  18. GR_GL_CUBIC_CURVE_TO,
  19. GR_GL_CLOSE_PATH,
  20. };
  21. GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
  22. GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
  23. GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
  24. GR_STATIC_ASSERT(3 == SkPath::kConic_Verb);
  25. GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb);
  26. GR_STATIC_ASSERT(5 == SkPath::kClose_Verb);
  27. SkASSERT(verb >= 0 && (size_t)verb < SK_ARRAY_COUNT(gTable));
  28. return gTable[verb];
  29. }
  30. #ifdef SK_DEBUG
  31. inline int num_coords(SkPath::Verb verb) {
  32. static const int gTable[] = {
  33. 2, // move
  34. 2, // line
  35. 4, // quad
  36. 5, // conic
  37. 6, // cubic
  38. 0, // close
  39. };
  40. GR_STATIC_ASSERT(0 == SkPath::kMove_Verb);
  41. GR_STATIC_ASSERT(1 == SkPath::kLine_Verb);
  42. GR_STATIC_ASSERT(2 == SkPath::kQuad_Verb);
  43. GR_STATIC_ASSERT(3 == SkPath::kConic_Verb);
  44. GR_STATIC_ASSERT(4 == SkPath::kCubic_Verb);
  45. GR_STATIC_ASSERT(5 == SkPath::kClose_Verb);
  46. SkASSERT(verb >= 0 && (size_t)verb < SK_ARRAY_COUNT(gTable));
  47. return gTable[verb];
  48. }
  49. #endif
  50. inline GrGLenum join_to_gl_join(SkPaint::Join join) {
  51. static GrGLenum gSkJoinsToGrGLJoins[] = {
  52. GR_GL_MITER_REVERT,
  53. GR_GL_ROUND,
  54. GR_GL_BEVEL
  55. };
  56. return gSkJoinsToGrGLJoins[join];
  57. GR_STATIC_ASSERT(0 == SkPaint::kMiter_Join);
  58. GR_STATIC_ASSERT(1 == SkPaint::kRound_Join);
  59. GR_STATIC_ASSERT(2 == SkPaint::kBevel_Join);
  60. GR_STATIC_ASSERT(SK_ARRAY_COUNT(gSkJoinsToGrGLJoins) == SkPaint::kJoinCount);
  61. }
  62. inline GrGLenum cap_to_gl_cap(SkPaint::Cap cap) {
  63. static GrGLenum gSkCapsToGrGLCaps[] = {
  64. GR_GL_FLAT,
  65. GR_GL_ROUND,
  66. GR_GL_SQUARE
  67. };
  68. return gSkCapsToGrGLCaps[cap];
  69. GR_STATIC_ASSERT(0 == SkPaint::kButt_Cap);
  70. GR_STATIC_ASSERT(1 == SkPaint::kRound_Cap);
  71. GR_STATIC_ASSERT(2 == SkPaint::kSquare_Cap);
  72. GR_STATIC_ASSERT(SK_ARRAY_COUNT(gSkCapsToGrGLCaps) == SkPaint::kCapCount);
  73. }
  74. #ifdef SK_DEBUG
  75. inline void verify_floats(const float* floats, int count) {
  76. for (int i = 0; i < count; ++i) {
  77. SkASSERT(!SkScalarIsNaN(SkFloatToScalar(floats[i])));
  78. }
  79. }
  80. #endif
  81. inline void points_to_coords(const SkPoint points[], size_t first_point, size_t amount,
  82. GrGLfloat coords[]) {
  83. for (size_t i = 0; i < amount; ++i) {
  84. coords[i * 2] = SkScalarToFloat(points[first_point + i].fX);
  85. coords[i * 2 + 1] = SkScalarToFloat(points[first_point + i].fY);
  86. }
  87. }
  88. template<bool checkForDegenerates>
  89. inline bool init_path_object_for_general_path(GrGLGpu* gpu, GrGLuint pathID,
  90. const SkPath& skPath) {
  91. SkDEBUGCODE(int numCoords = 0);
  92. int verbCnt = skPath.countVerbs();
  93. int pointCnt = skPath.countPoints();
  94. int minCoordCnt = pointCnt * 2;
  95. SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
  96. SkSTArray<16, GrGLfloat, true> pathCoords(minCoordCnt);
  97. bool lastVerbWasMove = true; // A path with just "close;" means "moveto(0,0); close;"
  98. SkPoint points[4];
  99. SkPath::RawIter iter(skPath);
  100. SkPath::Verb verb;
  101. while ((verb = iter.next(points)) != SkPath::kDone_Verb) {
  102. pathCommands.push_back(verb_to_gl_path_cmd(verb));
  103. GrGLfloat coords[6];
  104. int coordsForVerb;
  105. switch (verb) {
  106. case SkPath::kMove_Verb:
  107. if (checkForDegenerates) {
  108. lastVerbWasMove = true;
  109. }
  110. points_to_coords(points, 0, 1, coords);
  111. coordsForVerb = 2;
  112. break;
  113. case SkPath::kLine_Verb:
  114. if (checkForDegenerates) {
  115. if (SkPath::IsLineDegenerate(points[0], points[1], true)) {
  116. return false;
  117. }
  118. lastVerbWasMove = false;
  119. }
  120. points_to_coords(points, 1, 1, coords);
  121. coordsForVerb = 2;
  122. break;
  123. case SkPath::kConic_Verb:
  124. if (checkForDegenerates) {
  125. if (SkPath::IsQuadDegenerate(points[0], points[1], points[2], true)) {
  126. return false;
  127. }
  128. lastVerbWasMove = false;
  129. }
  130. points_to_coords(points, 1, 2, coords);
  131. coords[4] = SkScalarToFloat(iter.conicWeight());
  132. coordsForVerb = 5;
  133. break;
  134. case SkPath::kQuad_Verb:
  135. if (checkForDegenerates) {
  136. if (SkPath::IsQuadDegenerate(points[0], points[1], points[2], true)) {
  137. return false;
  138. }
  139. lastVerbWasMove = false;
  140. }
  141. points_to_coords(points, 1, 2, coords);
  142. coordsForVerb = 4;
  143. break;
  144. case SkPath::kCubic_Verb:
  145. if (checkForDegenerates) {
  146. if (SkPath::IsCubicDegenerate(points[0], points[1], points[2], points[3],
  147. true)) {
  148. return false;
  149. }
  150. lastVerbWasMove = false;
  151. }
  152. points_to_coords(points, 1, 3, coords);
  153. coordsForVerb = 6;
  154. break;
  155. case SkPath::kClose_Verb:
  156. if (checkForDegenerates) {
  157. if (lastVerbWasMove) {
  158. // Interpret "move(x,y);close;" as "move(x,y);lineto(x,y);close;".
  159. // which produces a degenerate segment.
  160. return false;
  161. }
  162. }
  163. continue;
  164. default:
  165. SkASSERT(false); // Not reached.
  166. continue;
  167. }
  168. SkDEBUGCODE(numCoords += num_coords(verb));
  169. SkDEBUGCODE(verify_floats(coords, coordsForVerb));
  170. pathCoords.push_back_n(coordsForVerb, coords);
  171. }
  172. SkASSERT(verbCnt == pathCommands.count());
  173. SkASSERT(numCoords == pathCoords.count());
  174. GR_GL_CALL(gpu->glInterface(),
  175. PathCommands(pathID, pathCommands.count(), pathCommands.begin(),
  176. pathCoords.count(), GR_GL_FLOAT, pathCoords.begin()));
  177. return true;
  178. }
  179. /*
  180. * For now paths only natively support winding and even odd fill types
  181. */
  182. static GrPathRendering::FillType convert_skpath_filltype(SkPath::FillType fill) {
  183. switch (fill) {
  184. default:
  185. SK_ABORT("Incomplete Switch\n");
  186. case SkPath::kWinding_FillType:
  187. case SkPath::kInverseWinding_FillType:
  188. return GrPathRendering::kWinding_FillType;
  189. case SkPath::kEvenOdd_FillType:
  190. case SkPath::kInverseEvenOdd_FillType:
  191. return GrPathRendering::kEvenOdd_FillType;
  192. }
  193. }
  194. } // namespace
  195. bool GrGLPath::InitPathObjectPathDataCheckingDegenerates(GrGLGpu* gpu, GrGLuint pathID,
  196. const SkPath& skPath) {
  197. return init_path_object_for_general_path<true>(gpu, pathID, skPath);
  198. }
  199. void GrGLPath::InitPathObjectPathData(GrGLGpu* gpu,
  200. GrGLuint pathID,
  201. const SkPath& skPath) {
  202. SkASSERT(!skPath.isEmpty());
  203. #if 1 // SK_SCALAR_IS_FLOAT
  204. // This branch does type punning, converting SkPoint* to GrGLfloat*.
  205. if ((skPath.getSegmentMasks() & SkPath::kConic_SegmentMask) == 0) {
  206. int verbCnt = skPath.countVerbs();
  207. int pointCnt = skPath.countPoints();
  208. int coordCnt = pointCnt * 2;
  209. SkSTArray<16, GrGLubyte, true> pathCommands(verbCnt);
  210. SkSTArray<16, GrGLfloat, true> pathCoords(coordCnt);
  211. static_assert(sizeof(SkPoint) == sizeof(GrGLfloat) * 2, "sk_point_not_two_floats");
  212. pathCommands.resize_back(verbCnt);
  213. pathCoords.resize_back(coordCnt);
  214. skPath.getPoints(reinterpret_cast<SkPoint*>(&pathCoords[0]), pointCnt);
  215. skPath.getVerbs(&pathCommands[0], verbCnt);
  216. SkDEBUGCODE(int verbCoordCnt = 0);
  217. for (int i = 0; i < verbCnt; ++i) {
  218. SkPath::Verb v = static_cast<SkPath::Verb>(pathCommands[i]);
  219. pathCommands[i] = verb_to_gl_path_cmd(v);
  220. SkDEBUGCODE(verbCoordCnt += num_coords(v));
  221. }
  222. SkASSERT(verbCnt == pathCommands.count());
  223. SkASSERT(verbCoordCnt == pathCoords.count());
  224. SkDEBUGCODE(verify_floats(&pathCoords[0], pathCoords.count()));
  225. GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, pathCommands.count(), &pathCommands[0],
  226. pathCoords.count(), GR_GL_FLOAT,
  227. &pathCoords[0]));
  228. return;
  229. }
  230. #endif
  231. SkAssertResult(init_path_object_for_general_path<false>(gpu, pathID, skPath));
  232. }
  233. void GrGLPath::InitPathObjectStroke(GrGLGpu* gpu, GrGLuint pathID, const SkStrokeRec& stroke) {
  234. SkASSERT(!stroke.isHairlineStyle());
  235. GR_GL_CALL(gpu->glInterface(),
  236. PathParameterf(pathID, GR_GL_PATH_STROKE_WIDTH, SkScalarToFloat(stroke.getWidth())));
  237. GR_GL_CALL(gpu->glInterface(),
  238. PathParameterf(pathID, GR_GL_PATH_MITER_LIMIT, SkScalarToFloat(stroke.getMiter())));
  239. GrGLenum join = join_to_gl_join(stroke.getJoin());
  240. GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_JOIN_STYLE, join));
  241. GrGLenum cap = cap_to_gl_cap(stroke.getCap());
  242. GR_GL_CALL(gpu->glInterface(), PathParameteri(pathID, GR_GL_PATH_END_CAPS, cap));
  243. GR_GL_CALL(gpu->glInterface(), PathParameterf(pathID, GR_GL_PATH_STROKE_BOUND, 0.02f));
  244. }
  245. void GrGLPath::InitPathObjectEmptyPath(GrGLGpu* gpu, GrGLuint pathID) {
  246. GR_GL_CALL(gpu->glInterface(), PathCommands(pathID, 0, nullptr, 0, GR_GL_FLOAT, nullptr));
  247. }
  248. GrGLPath::GrGLPath(GrGLGpu* gpu, const SkPath& origSkPath, const GrStyle& style)
  249. : INHERITED(gpu, origSkPath, style),
  250. fPathID(gpu->glPathRendering()->genPaths(1)) {
  251. if (origSkPath.isEmpty()) {
  252. InitPathObjectEmptyPath(gpu, fPathID);
  253. fShouldStroke = false;
  254. fShouldFill = false;
  255. } else {
  256. const SkPath* skPath = &origSkPath;
  257. SkTLazy<SkPath> tmpPath;
  258. SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
  259. if (style.pathEffect()) {
  260. // Skia stroking and NVPR stroking differ with respect to dashing
  261. // pattern.
  262. // Convert a dashing (or other path effect) to either a stroke or a fill.
  263. if (style.applyPathEffectToPath(tmpPath.init(), &stroke, *skPath, SK_Scalar1)) {
  264. skPath = tmpPath.get();
  265. }
  266. } else {
  267. stroke = style.strokeRec();
  268. }
  269. bool didInit = false;
  270. if (stroke.needToApply() && stroke.getCap() != SkPaint::kButt_Cap) {
  271. // Skia stroking and NVPR stroking differ with respect to stroking
  272. // end caps of empty subpaths.
  273. // Convert stroke to fill if path contains empty subpaths.
  274. didInit = InitPathObjectPathDataCheckingDegenerates(gpu, fPathID, *skPath);
  275. if (!didInit) {
  276. if (!tmpPath.isValid()) {
  277. tmpPath.init();
  278. }
  279. SkAssertResult(stroke.applyToPath(tmpPath.get(), *skPath));
  280. skPath = tmpPath.get();
  281. stroke.setFillStyle();
  282. }
  283. }
  284. if (!didInit) {
  285. InitPathObjectPathData(gpu, fPathID, *skPath);
  286. }
  287. fShouldStroke = stroke.needToApply();
  288. fShouldFill = stroke.isFillStyle() ||
  289. stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style;
  290. fFillType = convert_skpath_filltype(skPath->getFillType());
  291. fBounds = skPath->getBounds();
  292. SkScalar radius = stroke.getInflationRadius();
  293. fBounds.outset(radius, radius);
  294. if (fShouldStroke) {
  295. InitPathObjectStroke(gpu, fPathID, stroke);
  296. }
  297. }
  298. this->registerWithCache(SkBudgeted::kYes);
  299. }
  300. void GrGLPath::onRelease() {
  301. TRACE_EVENT0("skia.gpu", TRACE_FUNC);
  302. if (0 != fPathID) {
  303. static_cast<GrGLGpu*>(this->getGpu())->glPathRendering()->deletePaths(fPathID, 1);
  304. fPathID = 0;
  305. }
  306. INHERITED::onRelease();
  307. }
  308. void GrGLPath::onAbandon() {
  309. fPathID = 0;
  310. INHERITED::onAbandon();
  311. }