• 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 "src/gpu/gl/GrGLGpu.h"
9 #include "src/gpu/gl/GrGLPathRendering.h"
10 #include "src/gpu/gl/GrGLUtil.h"
11 
12 #include "src/gpu/GrRenderTargetProxy.h"
13 #include "src/gpu/gl/GrGLPath.h"
14 #include "src/gpu/gl/GrGLPathRendering.h"
15 
16 #include "include/core/SkStream.h"
17 #include "include/core/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 GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
27 GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
28 GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
29 GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
30 GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
31 GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
32 
33 #ifdef SK_DEBUG
34 
verify_floats(const float * floats,int count)35 static void verify_floats(const float* floats, int count) {
36     for (int i = 0; i < count; ++i) {
37         SkASSERT(!SkScalarIsNaN(SkFloatToScalar(floats[i])));
38     }
39 }
40 #endif
41 
gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op)42 static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
43     switch (op) {
44         default:
45             SK_ABORT("Unexpected path fill.");
46             /* fallthrough */
47         case GrStencilOp::kIncWrap:
48             return GR_GL_COUNT_UP;
49         case GrStencilOp::kInvert:
50             return GR_GL_INVERT;
51     }
52 }
53 
GrGLPathRendering(GrGLGpu * gpu)54 GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
55     : GrPathRendering(gpu)
56     , fPreallocatedPathCount(0) {
57     const GrGLInterface* glInterface = gpu->glInterface();
58     fCaps.bindFragmentInputSupport = (bool)glInterface->fFunctions.fBindFragmentInputLocation;
59 }
60 
~GrGLPathRendering()61 GrGLPathRendering::~GrGLPathRendering() {
62     if (fPreallocatedPathCount > 0) {
63         this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
64     }
65 }
66 
disconnect(GrGpu::DisconnectType type)67 void GrGLPathRendering::disconnect(GrGpu::DisconnectType type) {
68     if (GrGpu::DisconnectType::kCleanup == type) {
69         this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
70     }
71     fPreallocatedPathCount = 0;
72 }
73 
resetContext()74 void GrGLPathRendering::resetContext() {
75     fHWProjectionMatrixState.invalidate();
76     // we don't use the model view matrix.
77     GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
78 
79     fHWPathStencilSettings.invalidate();
80 }
81 
createPath(const SkPath & inPath,const GrStyle & style)82 sk_sp<GrPath> GrGLPathRendering::createPath(const SkPath& inPath, const GrStyle& style) {
83     return sk_make_sp<GrGLPath>(this->gpu(), inPath, style);
84 }
85 
onStencilPath(const StencilPathArgs & args,const GrPath * path)86 void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
87     GrGLGpu* gpu = this->gpu();
88     SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
89     gpu->flushColorWrite(false);
90 
91     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fProxy->peekRenderTarget());
92     SkISize size = SkISize::Make(rt->width(), rt->height());
93     this->setProjectionMatrix(*args.fViewMatrix, size, args.fProxy->origin());
94     gpu->flushScissor(*args.fScissor, rt->width(), rt->height(), args.fProxy->origin());
95     gpu->flushHWAAState(rt, args.fUseHWAA);
96     gpu->flushRenderTarget(rt);
97 
98     const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
99 
100     this->flushPathStencilSettings(*args.fStencil);
101 
102     GrGLenum fillMode =
103         gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.frontAndBack().fPassOp);
104     GrGLint writeMask = fHWPathStencilSettings.frontAndBack().fWriteMask;
105 
106     if (glPath->shouldFill()) {
107         GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
108     }
109     if (glPath->shouldStroke()) {
110         GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
111     }
112 }
113 
onDrawPath(GrRenderTarget * renderTarget,GrSurfaceOrigin origin,const GrPrimitiveProcessor & primProc,const GrPipeline & pipeline,const GrPipeline::FixedDynamicState & fixedDynamicState,const GrStencilSettings & stencilPassSettings,const GrPath * path)114 void GrGLPathRendering::onDrawPath(GrRenderTarget* renderTarget, GrSurfaceOrigin origin,
115                                    const GrPrimitiveProcessor& primProc,
116                                    const GrPipeline& pipeline,
117                                    const GrPipeline::FixedDynamicState& fixedDynamicState,
118                                    const GrStencilSettings& stencilPassSettings,
119                                    const GrPath* path) {
120     if (!this->gpu()->flushGLState(renderTarget, origin, primProc, pipeline,
121                                    &fixedDynamicState, nullptr, 1, false)) {
122         return;
123     }
124     const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
125 
126     this->flushPathStencilSettings(stencilPassSettings);
127 
128     GrGLenum fillMode =
129         gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.frontAndBack().fPassOp);
130     GrGLint writeMask = fHWPathStencilSettings.frontAndBack().fWriteMask;
131 
132     if (glPath->shouldStroke()) {
133         if (glPath->shouldFill()) {
134             GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
135         }
136         GL_CALL(StencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask,
137                                            GR_GL_BOUNDING_BOX));
138     } else {
139         GL_CALL(StencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask,
140                                          GR_GL_BOUNDING_BOX));
141     }
142 }
143 
setProgramPathFragmentInputTransform(GrGLuint program,GrGLint location,GrGLenum genMode,GrGLint components,const SkMatrix & matrix)144 void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
145                                                              GrGLenum genMode, GrGLint components,
146                                                              const SkMatrix& matrix) {
147     float coefficients[3 * 3];
148     SkASSERT(components >= 1 && components <= 3);
149 
150     coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
151     coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
152     coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
153 
154     if (components >= 2) {
155         coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
156         coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
157         coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
158     }
159 
160     if (components >= 3) {
161         coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
162         coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
163         coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
164     }
165     SkDEBUGCODE(verify_floats(coefficients, components * 3));
166 
167     GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
168 }
169 
setProjectionMatrix(const SkMatrix & matrix,const SkISize & renderTargetSize,GrSurfaceOrigin renderTargetOrigin)170 void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
171                                             const SkISize& renderTargetSize,
172                                             GrSurfaceOrigin renderTargetOrigin) {
173 
174     SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport());
175 
176     if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
177         renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
178         matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
179         return;
180     }
181 
182     fHWProjectionMatrixState.fViewMatrix = matrix;
183     fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
184     fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
185 
186     float glMatrix[4 * 4];
187     fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
188     SkDEBUGCODE(verify_floats(glMatrix, SK_ARRAY_COUNT(glMatrix)));
189     GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
190 }
191 
genPaths(GrGLsizei range)192 GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
193     SkASSERT(range > 0);
194     GrGLuint firstID;
195     if (fPreallocatedPathCount >= range) {
196         firstID = fFirstPreallocatedPathID;
197         fPreallocatedPathCount -= range;
198         fFirstPreallocatedPathID += range;
199         return firstID;
200     }
201     // Allocate range + the amount to fill up preallocation amount. If succeed, either join with
202     // the existing preallocation range or delete the existing and use the new (potentially partial)
203     // preallocation range.
204     GrGLsizei allocAmount = range + (kPathIDPreallocationAmount - fPreallocatedPathCount);
205     if (allocAmount >= range) {
206         GL_CALL_RET(firstID, GenPaths(allocAmount));
207 
208         if (firstID != 0) {
209             if (fPreallocatedPathCount > 0 &&
210                 firstID == fFirstPreallocatedPathID + fPreallocatedPathCount) {
211                 firstID = fFirstPreallocatedPathID;
212                 fPreallocatedPathCount += allocAmount - range;
213                 fFirstPreallocatedPathID += range;
214                 return firstID;
215             }
216 
217             if (allocAmount > range) {
218                 if (fPreallocatedPathCount > 0) {
219                     this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
220                 }
221                 fFirstPreallocatedPathID = firstID + range;
222                 fPreallocatedPathCount = allocAmount - range;
223             }
224             // Special case: if allocAmount == range, we have full preallocated range.
225             return firstID;
226         }
227     }
228     // Failed to allocate with preallocation. Remove existing preallocation and try to allocate just
229     // the range.
230     if (fPreallocatedPathCount > 0) {
231         this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
232         fPreallocatedPathCount = 0;
233     }
234 
235     GL_CALL_RET(firstID, GenPaths(range));
236     if (firstID == 0) {
237         SkDebugf("Warning: Failed to allocate path\n");
238     }
239     return firstID;
240 }
241 
deletePaths(GrGLuint path,GrGLsizei range)242 void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
243     GL_CALL(DeletePaths(path, range));
244 }
245 
flushPathStencilSettings(const GrStencilSettings & stencilSettings)246 void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
247     SkASSERT(!stencilSettings.isTwoSided());
248     if (fHWPathStencilSettings != stencilSettings) {
249         SkASSERT(stencilSettings.isValid());
250         // Just the func, ref, and mask is set here. The op and write mask are params to the call
251         // that draws the path to the SB (glStencilFillPath)
252         uint16_t ref = stencilSettings.frontAndBack().fRef;
253         GrStencilTest test = stencilSettings.frontAndBack().fTest;
254         uint16_t testMask = stencilSettings.frontAndBack().fTestMask;
255 
256         if (!fHWPathStencilSettings.isValid() ||
257             ref != fHWPathStencilSettings.frontAndBack().fRef ||
258             test != fHWPathStencilSettings.frontAndBack().fTest ||
259             testMask != fHWPathStencilSettings.frontAndBack().fTestMask) {
260             GL_CALL(PathStencilFunc(GrToGLStencilFunc(test), ref, testMask));
261         }
262         fHWPathStencilSettings = stencilSettings;
263     }
264 }
265 
gpu()266 inline GrGLGpu* GrGLPathRendering::gpu() {
267     return static_cast<GrGLGpu*>(fGpu);
268 }
269