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
24static const GrGLenum gIndexType2GLType[] = {
25    GR_GL_UNSIGNED_BYTE,
26    GR_GL_UNSIGNED_SHORT,
27    GR_GL_UNSIGNED_INT
28};
29
30GR_STATIC_ASSERT(0 == GrPathRange::kU8_PathIndexType);
31GR_STATIC_ASSERT(1 == GrPathRange::kU16_PathIndexType);
32GR_STATIC_ASSERT(2 == GrPathRange::kU32_PathIndexType);
33GR_STATIC_ASSERT(GrPathRange::kU32_PathIndexType == GrPathRange::kLast_PathIndexType);
34
35static 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
43GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
44GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
45GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
46GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
47GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
48GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
49
50static 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
62GrGLPathRendering::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
78GrGLPathRendering::~GrGLPathRendering() {
79}
80
81void GrGLPathRendering::abandonGpuResources() {
82    fPathNameAllocator.reset(NULL);
83}
84
85void 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
94GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
95    return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke));
96}
97
98GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
99                                                const SkStrokeRec& stroke) {
100    return SkNEW_ARGS(GrGLPathRange, (fGpu, pathGenerator, stroke));
101}
102
103GrPathRange* 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
154void 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
174void 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
196void 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
233void 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
259void 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
280GrGLuint 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
306void 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
331void 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
344inline 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
354inline 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
364inline 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
379inline 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