• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 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 "gl/GrGLPathRendering.h"
9 #include "gl/GrGLUtil.h"
10 #include "gl/GrGLGpu.h"
11 
12 #include "GrGLPath.h"
13 #include "GrGLPathRange.h"
14 #include "GrGLPathRendering.h"
15 
16 #include "SkStream.h"
17 #include "SkTypeface.h"
18 
19 #define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
20 #define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->gpu()->glInterface(), RET, X)
21 
22 // Number of paths to allocate per glGenPaths call. The call can be overly slow on command buffer GL
23 // implementation. The call has a result value, and thus waiting for the call completion is needed.
24 static const GrGLsizei kPathIDPreallocationAmount = 65536;
25 
26 static const GrGLenum gIndexType2GLType[] = {
27     GR_GL_UNSIGNED_BYTE,
28     GR_GL_UNSIGNED_SHORT,
29     GR_GL_UNSIGNED_INT
30 };
31 
32 GR_STATIC_ASSERT(0 == GrPathRange::kU8_PathIndexType);
33 GR_STATIC_ASSERT(1 == GrPathRange::kU16_PathIndexType);
34 GR_STATIC_ASSERT(2 == GrPathRange::kU32_PathIndexType);
35 GR_STATIC_ASSERT(GrPathRange::kU32_PathIndexType == GrPathRange::kLast_PathIndexType);
36 
37 static const GrGLenum gXformType2GLType[] = {
38     GR_GL_NONE,
39     GR_GL_TRANSLATE_X,
40     GR_GL_TRANSLATE_Y,
41     GR_GL_TRANSLATE_2D,
42     GR_GL_TRANSPOSE_AFFINE_2D
43 };
44 
45 GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
46 GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
47 GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
48 GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
49 GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
50 GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
51 
52 #ifdef SK_DEBUG
53 static const GrGLenum gXformType2ComponentCount[] = {
54     0,
55     1,
56     1,
57     2,
58     6
59 };
60 
verify_floats(const float * floats,int count)61 static void verify_floats(const float* floats, int count) {
62     for (int i = 0; i < count; ++i) {
63         SkASSERT(!SkScalarIsNaN(SkFloatToScalar(floats[i])));
64     }
65 }
66 #endif
67 
gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op)68 static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
69     switch (op) {
70         default:
71             SkFAIL("Unexpected path fill.");
72             /* fallthrough */;
73         case GrStencilOp::kIncWrap:
74             return GR_GL_COUNT_UP;
75         case GrStencilOp::kInvert:
76             return GR_GL_INVERT;
77     }
78 }
79 
GrGLPathRendering(GrGLGpu * gpu)80 GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
81     : GrPathRendering(gpu)
82     , fPreallocatedPathCount(0) {
83     const GrGLInterface* glInterface = gpu->glInterface();
84     fCaps.bindFragmentInputSupport =
85         nullptr != glInterface->fFunctions.fBindFragmentInputLocation;
86 }
87 
~GrGLPathRendering()88 GrGLPathRendering::~GrGLPathRendering() {
89     if (fPreallocatedPathCount > 0) {
90         this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
91     }
92 }
93 
disconnect(GrGpu::DisconnectType type)94 void GrGLPathRendering::disconnect(GrGpu::DisconnectType type) {
95     if (GrGpu::DisconnectType::kCleanup == type) {
96         this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
97     };
98     fPreallocatedPathCount = 0;
99 }
100 
resetContext()101 void GrGLPathRendering::resetContext() {
102     fHWProjectionMatrixState.invalidate();
103     // we don't use the model view matrix.
104     GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
105 
106     fHWPathStencilSettings.invalidate();
107 }
108 
createPath(const SkPath & inPath,const GrStyle & style)109 GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStyle& style) {
110     return new GrGLPath(this->gpu(), inPath, style);
111 }
112 
createPathRange(GrPathRange::PathGenerator * pathGenerator,const GrStyle & style)113 GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
114                                                 const GrStyle& style) {
115     return new GrGLPathRange(this->gpu(), pathGenerator, style);
116 }
117 
onStencilPath(const StencilPathArgs & args,const GrPath * path)118 void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
119     GrGLGpu* gpu = this->gpu();
120     SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
121     gpu->flushColorWrite(false);
122     gpu->flushDrawFace(GrDrawFace::kBoth);
123 
124     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fRenderTarget);
125     SkISize size = SkISize::Make(rt->width(), rt->height());
126     this->setProjectionMatrix(*args.fViewMatrix, size, rt->origin());
127     gpu->flushScissor(*args.fScissor, rt->getViewport(), rt->origin());
128     gpu->flushHWAAState(rt, args.fUseHWAA, true);
129     gpu->flushRenderTarget(rt, nullptr);
130 
131     const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
132 
133     this->flushPathStencilSettings(*args.fStencil);
134     SkASSERT(!fHWPathStencilSettings.isTwoSided());
135 
136     GrGLenum fillMode =
137         gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
138     GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
139 
140     if (glPath->shouldFill()) {
141         GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
142     }
143     if (glPath->shouldStroke()) {
144         GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
145     }
146 }
147 
onDrawPath(const GrPipeline & pipeline,const GrPrimitiveProcessor & primProc,const GrStencilSettings & stencilPassSettings,const GrPath * path)148 void GrGLPathRendering::onDrawPath(const GrPipeline& pipeline,
149                                    const GrPrimitiveProcessor& primProc,
150                                    const GrStencilSettings& stencilPassSettings,
151                                    const GrPath* path) {
152     if (!this->gpu()->flushGLState(pipeline, primProc, false)) {
153         return;
154     }
155     const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
156 
157     this->flushPathStencilSettings(stencilPassSettings);
158     SkASSERT(!fHWPathStencilSettings.isTwoSided());
159 
160     GrGLenum fillMode =
161         gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
162     GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
163 
164     if (glPath->shouldStroke()) {
165         if (glPath->shouldFill()) {
166             GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
167         }
168         GL_CALL(StencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask,
169                                            GR_GL_BOUNDING_BOX));
170     } else {
171         GL_CALL(StencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask,
172                                          GR_GL_BOUNDING_BOX));
173     }
174 }
175 
onDrawPaths(const GrPipeline & pipeline,const GrPrimitiveProcessor & primProc,const GrStencilSettings & stencilPassSettings,const GrPathRange * pathRange,const void * indices,PathIndexType indexType,const float transformValues[],PathTransformType transformType,int count)176 void GrGLPathRendering::onDrawPaths(const GrPipeline& pipeline,
177                                     const GrPrimitiveProcessor& primProc,
178                                     const GrStencilSettings& stencilPassSettings,
179                                     const GrPathRange* pathRange, const void* indices,
180                                     PathIndexType indexType, const float transformValues[],
181                                     PathTransformType transformType, int count) {
182     SkDEBUGCODE(verify_floats(transformValues, gXformType2ComponentCount[transformType] * count));
183 
184     if (!this->gpu()->flushGLState(pipeline, primProc, false)) {
185         return;
186     }
187     this->flushPathStencilSettings(stencilPassSettings);
188     SkASSERT(!fHWPathStencilSettings.isTwoSided());
189 
190 
191     const GrGLPathRange* glPathRange = static_cast<const GrGLPathRange*>(pathRange);
192 
193     GrGLenum fillMode =
194         gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
195     GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
196 
197     if (glPathRange->shouldStroke()) {
198         if (glPathRange->shouldFill()) {
199             GL_CALL(StencilFillPathInstanced(
200                             count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
201                             fillMode, writeMask, gXformType2GLType[transformType],
202                             transformValues));
203         }
204         GL_CALL(StencilThenCoverStrokePathInstanced(
205                             count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
206                             0xffff, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
207                             gXformType2GLType[transformType], transformValues));
208     } else {
209         GL_CALL(StencilThenCoverFillPathInstanced(
210                             count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
211                             fillMode, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
212                             gXformType2GLType[transformType], transformValues));
213     }
214 }
215 
setProgramPathFragmentInputTransform(GrGLuint program,GrGLint location,GrGLenum genMode,GrGLint components,const SkMatrix & matrix)216 void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
217                                                              GrGLenum genMode, GrGLint components,
218                                                              const SkMatrix& matrix) {
219     float coefficients[3 * 3];
220     SkASSERT(components >= 1 && components <= 3);
221 
222     coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
223     coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
224     coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
225 
226     if (components >= 2) {
227         coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
228         coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
229         coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
230     }
231 
232     if (components >= 3) {
233         coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
234         coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
235         coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
236     }
237     SkDEBUGCODE(verify_floats(coefficients, components * 3));
238 
239     GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
240 }
241 
setProjectionMatrix(const SkMatrix & matrix,const SkISize & renderTargetSize,GrSurfaceOrigin renderTargetOrigin)242 void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
243                                             const SkISize& renderTargetSize,
244                                             GrSurfaceOrigin renderTargetOrigin) {
245 
246     SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport());
247 
248     if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
249         renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
250         matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
251         return;
252     }
253 
254     fHWProjectionMatrixState.fViewMatrix = matrix;
255     fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
256     fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
257 
258     float glMatrix[4 * 4];
259     fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
260     SkDEBUGCODE(verify_floats(glMatrix, SK_ARRAY_COUNT(glMatrix)));
261     GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
262 }
263 
genPaths(GrGLsizei range)264 GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
265     SkASSERT(range > 0);
266     GrGLuint firstID;
267     if (fPreallocatedPathCount >= range) {
268         firstID = fFirstPreallocatedPathID;
269         fPreallocatedPathCount -= range;
270         fFirstPreallocatedPathID += range;
271         return firstID;
272     }
273     // Allocate range + the amount to fill up preallocation amount. If succeed, either join with
274     // the existing preallocation range or delete the existing and use the new (potentially partial)
275     // preallocation range.
276     GrGLsizei allocAmount = range + (kPathIDPreallocationAmount - fPreallocatedPathCount);
277     if (allocAmount >= range) {
278         GL_CALL_RET(firstID, GenPaths(allocAmount));
279 
280         if (firstID != 0) {
281             if (fPreallocatedPathCount > 0 &&
282                 firstID == fFirstPreallocatedPathID + fPreallocatedPathCount) {
283                 firstID = fFirstPreallocatedPathID;
284                 fPreallocatedPathCount += allocAmount - range;
285                 fFirstPreallocatedPathID += range;
286                 return firstID;
287             }
288 
289             if (allocAmount > range) {
290                 if (fPreallocatedPathCount > 0) {
291                     this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
292                 }
293                 fFirstPreallocatedPathID = firstID + range;
294                 fPreallocatedPathCount = allocAmount - range;
295             }
296             // Special case: if allocAmount == range, we have full preallocated range.
297             return firstID;
298         }
299     }
300     // Failed to allocate with preallocation. Remove existing preallocation and try to allocate just
301     // the range.
302     if (fPreallocatedPathCount > 0) {
303         this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
304         fPreallocatedPathCount = 0;
305     }
306 
307     GL_CALL_RET(firstID, GenPaths(range));
308     if (firstID == 0) {
309         SkDebugf("Warning: Failed to allocate path\n");
310     }
311     return firstID;
312 }
313 
deletePaths(GrGLuint path,GrGLsizei range)314 void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
315     GL_CALL(DeletePaths(path, range));
316 }
317 
flushPathStencilSettings(const GrStencilSettings & stencilSettings)318 void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
319     if (fHWPathStencilSettings != stencilSettings) {
320         SkASSERT(stencilSettings.isValid());
321         // Just the func, ref, and mask is set here. The op and write mask are params to the call
322         // that draws the path to the SB (glStencilFillPath)
323         uint16_t ref = stencilSettings.front().fRef;
324         GrStencilTest test = stencilSettings.front().fTest;
325         uint16_t testMask = stencilSettings.front().fTestMask;
326 
327         if (!fHWPathStencilSettings.isValid() ||
328             ref != fHWPathStencilSettings.front().fRef ||
329             test != fHWPathStencilSettings.front().fTest ||
330             testMask != fHWPathStencilSettings.front().fTestMask) {
331             GL_CALL(PathStencilFunc(GrToGLStencilFunc(test), ref, testMask));
332         }
333         fHWPathStencilSettings = stencilSettings;
334     }
335 }
336 
gpu()337 inline GrGLGpu* GrGLPathRendering::gpu() {
338     return static_cast<GrGLGpu*>(fGpu);
339 }
340