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 
gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op)52 static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
53     switch (op) {
54         default:
55             SkFAIL("Unexpected path fill.");
56             /* fallthrough */;
57         case kIncClamp_StencilOp:
58             return GR_GL_COUNT_UP;
59         case kInvert_StencilOp:
60             return GR_GL_INVERT;
61     }
62 }
63 
GrGLPathRendering(GrGLGpu * gpu)64 GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
65     : GrPathRendering(gpu)
66     , fPreallocatedPathCount(0) {
67     const GrGLInterface* glInterface = gpu->glInterface();
68     fCaps.bindFragmentInputSupport =
69         nullptr != glInterface->fFunctions.fBindFragmentInputLocation;
70 }
71 
~GrGLPathRendering()72 GrGLPathRendering::~GrGLPathRendering() {
73     if (fPreallocatedPathCount > 0) {
74         this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
75     }
76 }
77 
abandonGpuResources()78 void GrGLPathRendering::abandonGpuResources() {
79     fPreallocatedPathCount = 0;
80 }
81 
resetContext()82 void GrGLPathRendering::resetContext() {
83     fHWProjectionMatrixState.invalidate();
84     // we don't use the model view matrix.
85     GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
86 
87     fHWPathStencilSettings.invalidate();
88 }
89 
createPath(const SkPath & inPath,const GrStrokeInfo & stroke)90 GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStrokeInfo& stroke) {
91     return new GrGLPath(this->gpu(), inPath, stroke);
92 }
93 
createPathRange(GrPathRange::PathGenerator * pathGenerator,const GrStrokeInfo & stroke)94 GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
95                                                 const GrStrokeInfo& stroke) {
96     return new GrGLPathRange(this->gpu(), pathGenerator, stroke);
97 }
98 
onStencilPath(const StencilPathArgs & args,const GrPath * path)99 void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
100     GrGLGpu* gpu = this->gpu();
101     SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
102     gpu->flushColorWrite(false);
103     gpu->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace);
104 
105     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fRenderTarget);
106     SkISize size = SkISize::Make(rt->width(), rt->height());
107     this->setProjectionMatrix(*args.fViewMatrix, size, rt->origin());
108     gpu->flushScissor(*args.fScissor, rt->getViewport(), rt->origin());
109     gpu->flushHWAAState(rt, args.fUseHWAA, true);
110     gpu->flushRenderTarget(rt, nullptr);
111 
112     const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
113 
114     this->flushPathStencilSettings(*args.fStencil);
115     SkASSERT(!fHWPathStencilSettings.isTwoSided());
116 
117     GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
118         fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
119     GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
120 
121     if (glPath->shouldFill()) {
122         GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
123     }
124     if (glPath->shouldStroke()) {
125         GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
126     }
127 }
128 
onDrawPath(const DrawPathArgs & args,const GrPath * path)129 void GrGLPathRendering::onDrawPath(const DrawPathArgs& args, const GrPath* path) {
130     if (!this->gpu()->flushGLState(args)) {
131         return;
132     }
133     const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
134 
135     this->flushPathStencilSettings(*args.fStencil);
136     SkASSERT(!fHWPathStencilSettings.isTwoSided());
137 
138     GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
139         fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
140     GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
141 
142     if (glPath->shouldStroke()) {
143         if (glPath->shouldFill()) {
144             GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
145         }
146         GL_CALL(StencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask,
147                                            GR_GL_BOUNDING_BOX));
148     } else {
149         GL_CALL(StencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask,
150                                          GR_GL_BOUNDING_BOX));
151     }
152 }
153 
onDrawPaths(const DrawPathArgs & args,const GrPathRange * pathRange,const void * indices,PathIndexType indexType,const float transformValues[],PathTransformType transformType,int count)154 void GrGLPathRendering::onDrawPaths(const DrawPathArgs& args, const GrPathRange* pathRange,
155                                     const void* indices, PathIndexType indexType,
156                                     const float transformValues[], PathTransformType transformType,
157                                     int count) {
158     if (!this->gpu()->flushGLState(args)) {
159         return;
160     }
161     this->flushPathStencilSettings(*args.fStencil);
162     SkASSERT(!fHWPathStencilSettings.isTwoSided());
163 
164 
165     const GrGLPathRange* glPathRange = static_cast<const GrGLPathRange*>(pathRange);
166 
167     GrGLenum fillMode =
168         gr_stencil_op_to_gl_path_rendering_fill_mode(
169             fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
170     GrGLint writeMask =
171         fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
172 
173     if (glPathRange->shouldStroke()) {
174         if (glPathRange->shouldFill()) {
175             GL_CALL(StencilFillPathInstanced(
176                             count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
177                             fillMode, writeMask, gXformType2GLType[transformType],
178                             transformValues));
179         }
180         GL_CALL(StencilThenCoverStrokePathInstanced(
181                             count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
182                             0xffff, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
183                             gXformType2GLType[transformType], transformValues));
184     } else {
185         GL_CALL(StencilThenCoverFillPathInstanced(
186                             count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
187                             fillMode, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
188                             gXformType2GLType[transformType], transformValues));
189     }
190 }
191 
setProgramPathFragmentInputTransform(GrGLuint program,GrGLint location,GrGLenum genMode,GrGLint components,const SkMatrix & matrix)192 void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
193                                                              GrGLenum genMode, GrGLint components,
194                                                              const SkMatrix& matrix) {
195     float coefficients[3 * 3];
196     SkASSERT(components >= 1 && components <= 3);
197 
198     coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
199     coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
200     coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
201 
202     if (components >= 2) {
203         coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
204         coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
205         coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
206     }
207 
208     if (components >= 3) {
209         coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
210         coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
211         coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
212     }
213 
214     GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
215 }
216 
setProjectionMatrix(const SkMatrix & matrix,const SkISize & renderTargetSize,GrSurfaceOrigin renderTargetOrigin)217 void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
218                                             const SkISize& renderTargetSize,
219                                             GrSurfaceOrigin renderTargetOrigin) {
220 
221     SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport());
222 
223     if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
224         renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
225         matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
226         return;
227     }
228 
229     fHWProjectionMatrixState.fViewMatrix = matrix;
230     fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
231     fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
232 
233     float glMatrix[4 * 4];
234     fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
235     GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
236 }
237 
genPaths(GrGLsizei range)238 GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
239     SkASSERT(range > 0);
240     GrGLuint firstID;
241     if (fPreallocatedPathCount >= range) {
242         firstID = fFirstPreallocatedPathID;
243         fPreallocatedPathCount -= range;
244         fFirstPreallocatedPathID += range;
245         return firstID;
246     }
247     // Allocate range + the amount to fill up preallocation amount. If succeed, either join with
248     // the existing preallocation range or delete the existing and use the new (potentially partial)
249     // preallocation range.
250     GrGLsizei allocAmount = range + (kPathIDPreallocationAmount - fPreallocatedPathCount);
251     if (allocAmount >= range) {
252         GL_CALL_RET(firstID, GenPaths(allocAmount));
253 
254         if (firstID != 0) {
255             if (fPreallocatedPathCount > 0 &&
256                 firstID == fFirstPreallocatedPathID + fPreallocatedPathCount) {
257                 firstID = fFirstPreallocatedPathID;
258                 fPreallocatedPathCount += allocAmount - range;
259                 fFirstPreallocatedPathID += range;
260                 return firstID;
261             }
262 
263             if (allocAmount > range) {
264                 if (fPreallocatedPathCount > 0) {
265                     this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
266                 }
267                 fFirstPreallocatedPathID = firstID + range;
268                 fPreallocatedPathCount = allocAmount - range;
269             }
270             // Special case: if allocAmount == range, we have full preallocated range.
271             return firstID;
272         }
273     }
274     // Failed to allocate with preallocation. Remove existing preallocation and try to allocate just
275     // the range.
276     if (fPreallocatedPathCount > 0) {
277         this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
278         fPreallocatedPathCount = 0;
279     }
280 
281     GL_CALL_RET(firstID, GenPaths(range));
282     if (firstID == 0) {
283         SkDebugf("Warning: Failed to allocate path\n");
284     }
285     return firstID;
286 }
287 
deletePaths(GrGLuint path,GrGLsizei range)288 void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
289     GL_CALL(DeletePaths(path, range));
290 }
291 
flushPathStencilSettings(const GrStencilSettings & stencilSettings)292 void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
293     if (fHWPathStencilSettings != stencilSettings) {
294         SkASSERT(stencilSettings.isValid());
295         // Just the func, ref, and mask is set here. The op and write mask are params to the call
296         // that draws the path to the SB (glStencilFillPath)
297         const GrStencilSettings::Face kFront_Face = GrStencilSettings::kFront_Face;
298         GrStencilFunc func = stencilSettings.func(kFront_Face);
299         uint16_t funcRef = stencilSettings.funcRef(kFront_Face);
300         uint16_t funcMask = stencilSettings.funcMask(kFront_Face);
301 
302         if (!fHWPathStencilSettings.isValid() ||
303             func != fHWPathStencilSettings.func(kFront_Face) ||
304             funcRef != fHWPathStencilSettings.funcRef(kFront_Face) ||
305             funcMask != fHWPathStencilSettings.funcMask(kFront_Face)) {
306             GL_CALL(PathStencilFunc(GrToGLStencilFunc(func), funcRef, funcMask));
307         }
308         fHWPathStencilSettings = stencilSettings;
309     }
310 }
311 
gpu()312 inline GrGLGpu* GrGLPathRendering::gpu() {
313     return static_cast<GrGLGpu*>(fGpu);
314 }
315