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/GrGLNameAllocator.h"
10 #include "gl/GrGLUtil.h"
11 #include "gl/GrGLGpu.h"
12 
13 #include "GrGLPath.h"
14 #include "GrGLPathRange.h"
15 #include "GrGLPathRendering.h"
16 
17 #include "SkStream.h"
18 #include "SkTypeface.h"
19 
20 #define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
21 #define GL_CALL_RET(RET, X) GR_GL_CALL_RET(fGpu->glInterface(), RET, X)
22 
23 
24 static const GrGLenum gIndexType2GLType[] = {
25     GR_GL_UNSIGNED_BYTE,
26     GR_GL_UNSIGNED_SHORT,
27     GR_GL_UNSIGNED_INT
28 };
29 
30 GR_STATIC_ASSERT(0 == GrPathRange::kU8_PathIndexType);
31 GR_STATIC_ASSERT(1 == GrPathRange::kU16_PathIndexType);
32 GR_STATIC_ASSERT(2 == GrPathRange::kU32_PathIndexType);
33 GR_STATIC_ASSERT(GrPathRange::kU32_PathIndexType == GrPathRange::kLast_PathIndexType);
34 
35 static const GrGLenum gXformType2GLType[] = {
36     GR_GL_NONE,
37     GR_GL_TRANSLATE_X,
38     GR_GL_TRANSLATE_Y,
39     GR_GL_TRANSLATE_2D,
40     GR_GL_TRANSPOSE_AFFINE_2D
41 };
42 
43 GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
44 GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
45 GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
46 GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
47 GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
48 GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
49 
gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op)50 static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
51     switch (op) {
52         default:
53             SkFAIL("Unexpected path fill.");
54             /* fallthrough */;
55         case kIncClamp_StencilOp:
56             return GR_GL_COUNT_UP;
57         case kInvert_StencilOp:
58             return GR_GL_INVERT;
59     }
60 }
61 
GrGLPathRendering(GrGLGpu * gpu)62 GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
63     : fGpu(gpu) {
64     const GrGLInterface* glInterface = gpu->glInterface();
65     fCaps.stencilThenCoverSupport =
66         NULL != glInterface->fFunctions.fStencilThenCoverFillPath &&
67         NULL != glInterface->fFunctions.fStencilThenCoverStrokePath &&
68         NULL != glInterface->fFunctions.fStencilThenCoverFillPathInstanced &&
69         NULL != glInterface->fFunctions.fStencilThenCoverStrokePathInstanced;
70     fCaps.fragmentInputGenSupport =
71         NULL != glInterface->fFunctions.fProgramPathFragmentInputGen;
72     fCaps.glyphLoadingSupport =
73         NULL != glInterface->fFunctions.fPathMemoryGlyphIndexArray;
74 
75     SkASSERT(fCaps.fragmentInputGenSupport);
76 }
77 
~GrGLPathRendering()78 GrGLPathRendering::~GrGLPathRendering() {
79 }
80 
abandonGpuResources()81 void GrGLPathRendering::abandonGpuResources() {
82     fPathNameAllocator.reset(NULL);
83 }
84 
resetContext()85 void GrGLPathRendering::resetContext() {
86     fHWProjectionMatrixState.invalidate();
87     // we don't use the model view matrix.
88     GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
89 
90     SkASSERT(fCaps.fragmentInputGenSupport);
91     fHWPathStencilSettings.invalidate();
92 }
93 
createPath(const SkPath & inPath,const SkStrokeRec & stroke)94 GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
95     return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke));
96 }
97 
createPathRange(GrPathRange::PathGenerator * pathGenerator,const SkStrokeRec & stroke)98 GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
99                                                 const SkStrokeRec& stroke) {
100     return SkNEW_ARGS(GrGLPathRange, (fGpu, pathGenerator, stroke));
101 }
102 
createGlyphs(const SkTypeface * typeface,const SkDescriptor * desc,const SkStrokeRec & stroke)103 GrPathRange* GrGLPathRendering::createGlyphs(const SkTypeface* typeface,
104                                              const SkDescriptor* desc,
105                                              const SkStrokeRec& stroke) {
106     if (NULL != desc || !caps().glyphLoadingSupport) {
107         return GrPathRendering::createGlyphs(typeface, desc, stroke);
108     }
109 
110     if (NULL == typeface) {
111         typeface = SkTypeface::GetDefaultTypeface();
112         SkASSERT(NULL != typeface);
113     }
114 
115     int faceIndex;
116     SkAutoTDelete<SkStream> fontStream(typeface->openStream(&faceIndex));
117 
118     const size_t fontDataLength = fontStream->getLength();
119     if (0 == fontDataLength) {
120         return GrPathRendering::createGlyphs(typeface, NULL, stroke);
121     }
122 
123     SkTArray<uint8_t> fontTempBuffer;
124     const void* fontData = fontStream->getMemoryBase();
125     if (NULL == fontData) {
126         // TODO: Find a more efficient way to pass the font data (e.g. open file descriptor).
127         fontTempBuffer.reset(SkToInt(fontDataLength));
128         fontStream->read(&fontTempBuffer.front(), fontDataLength);
129         fontData = &fontTempBuffer.front();
130     }
131 
132     const int numPaths = typeface->countGlyphs();
133     const GrGLuint basePathID = this->genPaths(numPaths);
134     SkAutoTUnref<GrGLPath> templatePath(SkNEW_ARGS(GrGLPath, (fGpu, SkPath(), stroke)));
135 
136     GrGLenum status;
137     GL_CALL_RET(status, PathMemoryGlyphIndexArray(basePathID, GR_GL_STANDARD_FONT_FORMAT,
138                                                   fontDataLength, fontData, faceIndex, 0,
139                                                   numPaths, templatePath->pathID(),
140                                                   SkPaint::kCanonicalTextSizeForPaths));
141 
142     if (GR_GL_FONT_GLYPHS_AVAILABLE != status) {
143         this->deletePaths(basePathID, numPaths);
144         return GrPathRendering::createGlyphs(typeface, NULL, stroke);
145     }
146 
147     // This is a crude approximation. We may want to consider giving this class
148     // a pseudo PathGenerator whose sole purpose is to track the approximate gpu
149     // memory size.
150     const size_t gpuMemorySize = fontDataLength / 4;
151     return SkNEW_ARGS(GrGLPathRange, (fGpu, basePathID, numPaths, gpuMemorySize, stroke));
152 }
153 
stencilPath(const GrPath * path,const GrStencilSettings & stencilSettings)154 void GrGLPathRendering::stencilPath(const GrPath* path, const GrStencilSettings& stencilSettings) {
155     GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
156 
157     this->flushPathStencilSettings(stencilSettings);
158     SkASSERT(!fHWPathStencilSettings.isTwoSided());
159 
160     const SkStrokeRec& stroke = path->getStroke();
161 
162     GrGLenum fillMode =
163         gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
164     GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
165 
166     if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
167         GL_CALL(StencilFillPath(id, fillMode, writeMask));
168     }
169     if (stroke.needToApply()) {
170         GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
171     }
172 }
173 
drawPath(const GrPath * path,const GrStencilSettings & stencilSettings)174 void GrGLPathRendering::drawPath(const GrPath* path, const GrStencilSettings& stencilSettings) {
175     GrGLuint id = static_cast<const GrGLPath*>(path)->pathID();
176 
177     this->flushPathStencilSettings(stencilSettings);
178     SkASSERT(!fHWPathStencilSettings.isTwoSided());
179 
180     const SkStrokeRec& stroke = path->getStroke();
181 
182     GrGLenum fillMode =
183         gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
184     GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
185 
186     if (stroke.needToApply()) {
187         if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
188             GL_CALL(StencilFillPath(id, fillMode, writeMask));
189         }
190         this->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX);
191     } else {
192         this->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX);
193     }
194 }
195 
drawPaths(const GrPathRange * pathRange,const void * indices,PathIndexType indexType,const float transformValues[],PathTransformType transformType,int count,const GrStencilSettings & stencilSettings)196 void GrGLPathRendering::drawPaths(const GrPathRange* pathRange,
197                                   const void* indices, PathIndexType indexType,
198                                   const float transformValues[], PathTransformType transformType,
199                                   int count, const GrStencilSettings& stencilSettings) {
200     SkASSERT(fGpu->caps()->shaderCaps()->pathRenderingSupport());
201 
202     GrGLuint baseID = static_cast<const GrGLPathRange*>(pathRange)->basePathID();
203 
204     this->flushPathStencilSettings(stencilSettings);
205     SkASSERT(!fHWPathStencilSettings.isTwoSided());
206 
207     const SkStrokeRec& stroke = pathRange->getStroke();
208 
209     GrGLenum fillMode =
210         gr_stencil_op_to_gl_path_rendering_fill_mode(
211             fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
212     GrGLint writeMask =
213         fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
214 
215     if (stroke.needToApply()) {
216         if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
217             GL_CALL(StencilFillPathInstanced(
218                             count, gIndexType2GLType[indexType], indices, baseID, fillMode,
219                             writeMask, gXformType2GLType[transformType], transformValues));
220         }
221         this->stencilThenCoverStrokePathInstanced(
222                             count, gIndexType2GLType[indexType], indices, baseID,
223                             0xffff, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
224                             gXformType2GLType[transformType], transformValues);
225     } else {
226         this->stencilThenCoverFillPathInstanced(
227                             count, gIndexType2GLType[indexType], indices, baseID,
228                             fillMode, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
229                             gXformType2GLType[transformType], transformValues);
230     }
231 }
232 
setProgramPathFragmentInputTransform(GrGLuint program,GrGLint location,GrGLenum genMode,GrGLint components,const SkMatrix & matrix)233 void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
234                                                              GrGLenum genMode, GrGLint components,
235                                                              const SkMatrix& matrix) {
236     SkASSERT(caps().fragmentInputGenSupport);
237     GrGLfloat coefficients[3 * 3];
238     SkASSERT(components >= 1 && components <= 3);
239 
240     coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
241     coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
242     coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
243 
244     if (components >= 2) {
245         coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
246         coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
247         coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
248     }
249 
250     if (components >= 3) {
251         coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
252         coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
253         coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
254     }
255 
256     GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
257 }
258 
setProjectionMatrix(const SkMatrix & matrix,const SkISize & renderTargetSize,GrSurfaceOrigin renderTargetOrigin)259 void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
260                                             const SkISize& renderTargetSize,
261                                             GrSurfaceOrigin renderTargetOrigin) {
262 
263     SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport());
264 
265     if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
266         renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
267         matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
268         return;
269     }
270 
271     fHWProjectionMatrixState.fViewMatrix = matrix;
272     fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
273     fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
274 
275     GrGLfloat glMatrix[4 * 4];
276     fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
277     GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
278 }
279 
genPaths(GrGLsizei range)280 GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
281     if (range > 1) {
282         GrGLuint name;
283         GL_CALL_RET(name, GenPaths(range));
284         return name;
285     }
286 
287     if (NULL == fPathNameAllocator.get()) {
288         static const int range = 65536;
289         GrGLuint firstName;
290         GL_CALL_RET(firstName, GenPaths(range));
291         fPathNameAllocator.reset(SkNEW_ARGS(GrGLNameAllocator, (firstName, firstName + range)));
292     }
293 
294     // When allocating names one at a time, pull from a client-side pool of
295     // available names in order to save a round trip to the GL server.
296     GrGLuint name = fPathNameAllocator->allocateName();
297 
298     if (0 == name) {
299         // Our reserved path names are all in use. Fall back on GenPaths.
300         GL_CALL_RET(name, GenPaths(1));
301     }
302 
303     return name;
304 }
305 
deletePaths(GrGLuint path,GrGLsizei range)306 void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
307     if (range > 1) {
308         // It is not supported to delete names in ranges that were allocated
309         // individually using GrGLPathNameAllocator.
310         SkASSERT(NULL == fPathNameAllocator.get() ||
311                  path + range <= fPathNameAllocator->firstName() ||
312                  path >= fPathNameAllocator->endName());
313         GL_CALL(DeletePaths(path, range));
314         return;
315     }
316 
317     if (NULL == fPathNameAllocator.get() ||
318         path < fPathNameAllocator->firstName() ||
319         path >= fPathNameAllocator->endName()) {
320         // If we aren't inside fPathNameAllocator's range then this name was
321         // generated by the GenPaths fallback (or else was never allocated).
322         GL_CALL(DeletePaths(path, 1));
323         return;
324     }
325 
326     // Make the path empty to save memory, but don't free the name in the driver.
327     GL_CALL(PathCommands(path, 0, NULL, 0, GR_GL_FLOAT, NULL));
328     fPathNameAllocator->free(path);
329 }
330 
flushPathStencilSettings(const GrStencilSettings & stencilSettings)331 void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
332     if (fHWPathStencilSettings != stencilSettings) {
333         // Just the func, ref, and mask is set here. The op and write mask are params to the call
334         // that draws the path to the SB (glStencilFillPath)
335         GrGLenum func =
336             GrToGLStencilFunc(stencilSettings.func(GrStencilSettings::kFront_Face));
337         GL_CALL(PathStencilFunc(func, stencilSettings.funcRef(GrStencilSettings::kFront_Face),
338                                 stencilSettings.funcMask(GrStencilSettings::kFront_Face)));
339 
340         fHWPathStencilSettings = stencilSettings;
341     }
342 }
343 
stencilThenCoverFillPath(GrGLuint path,GrGLenum fillMode,GrGLuint mask,GrGLenum coverMode)344 inline void GrGLPathRendering::stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
345                                                      GrGLuint mask, GrGLenum coverMode) {
346     if (caps().stencilThenCoverSupport) {
347         GL_CALL(StencilThenCoverFillPath(path, fillMode, mask, coverMode));
348         return;
349     }
350     GL_CALL(StencilFillPath(path, fillMode, mask));
351     GL_CALL(CoverFillPath(path, coverMode));
352 }
353 
stencilThenCoverStrokePath(GrGLuint path,GrGLint reference,GrGLuint mask,GrGLenum coverMode)354 inline void GrGLPathRendering::stencilThenCoverStrokePath(GrGLuint path, GrGLint reference,
355                                                        GrGLuint mask, GrGLenum coverMode) {
356     if (caps().stencilThenCoverSupport) {
357         GL_CALL(StencilThenCoverStrokePath(path, reference, mask, coverMode));
358         return;
359     }
360     GL_CALL(StencilStrokePath(path, reference, mask));
361     GL_CALL(CoverStrokePath(path, coverMode));
362 }
363 
stencilThenCoverFillPathInstanced(GrGLsizei numPaths,GrGLenum pathNameType,const GrGLvoid * paths,GrGLuint pathBase,GrGLenum fillMode,GrGLuint mask,GrGLenum coverMode,GrGLenum transformType,const GrGLfloat * transformValues)364 inline void GrGLPathRendering::stencilThenCoverFillPathInstanced(
365              GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
366              GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode,
367              GrGLenum transformType, const GrGLfloat *transformValues) {
368     if (caps().stencilThenCoverSupport) {
369         GL_CALL(StencilThenCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, fillMode,
370                                                   mask, coverMode, transformType, transformValues));
371         return;
372     }
373     GL_CALL(StencilFillPathInstanced(numPaths, pathNameType, paths, pathBase,
374                                      fillMode, mask, transformType, transformValues));
375     GL_CALL(CoverFillPathInstanced(numPaths, pathNameType, paths, pathBase,
376                                    coverMode, transformType, transformValues));
377 }
378 
stencilThenCoverStrokePathInstanced(GrGLsizei numPaths,GrGLenum pathNameType,const GrGLvoid * paths,GrGLuint pathBase,GrGLint reference,GrGLuint mask,GrGLenum coverMode,GrGLenum transformType,const GrGLfloat * transformValues)379 inline void GrGLPathRendering::stencilThenCoverStrokePathInstanced(
380         GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
381         GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode,
382         GrGLenum transformType, const GrGLfloat *transformValues) {
383     if (caps().stencilThenCoverSupport) {
384         GL_CALL(StencilThenCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
385                                                     reference, mask, coverMode, transformType,
386                                                     transformValues));
387         return;
388     }
389 
390     GL_CALL(StencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
391                                        reference, mask, transformType, transformValues));
392     GL_CALL(CoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
393                                      coverMode, transformType, transformValues));
394 }
395