Line data Source code
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 :
61 0 : static void verify_floats(const float* floats, int count) {
62 0 : for (int i = 0; i < count; ++i) {
63 0 : SkASSERT(!SkScalarIsNaN(SkFloatToScalar(floats[i])));
64 : }
65 0 : }
66 : #endif
67 :
68 0 : static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
69 0 : switch (op) {
70 : default:
71 0 : SkFAIL("Unexpected path fill.");
72 : /* fallthrough */;
73 : case GrStencilOp::kIncWrap:
74 0 : return GR_GL_COUNT_UP;
75 : case GrStencilOp::kInvert:
76 0 : return GR_GL_INVERT;
77 : }
78 : }
79 :
80 0 : GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
81 : : GrPathRendering(gpu)
82 0 : , fPreallocatedPathCount(0) {
83 0 : const GrGLInterface* glInterface = gpu->glInterface();
84 0 : fCaps.bindFragmentInputSupport =
85 0 : nullptr != glInterface->fFunctions.fBindFragmentInputLocation;
86 0 : }
87 :
88 0 : GrGLPathRendering::~GrGLPathRendering() {
89 0 : if (fPreallocatedPathCount > 0) {
90 0 : this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
91 : }
92 0 : }
93 :
94 0 : void GrGLPathRendering::disconnect(GrGpu::DisconnectType type) {
95 0 : if (GrGpu::DisconnectType::kCleanup == type) {
96 0 : this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
97 : };
98 0 : fPreallocatedPathCount = 0;
99 0 : }
100 :
101 0 : void GrGLPathRendering::resetContext() {
102 0 : fHWProjectionMatrixState.invalidate();
103 : // we don't use the model view matrix.
104 0 : GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
105 :
106 0 : fHWPathStencilSettings.invalidate();
107 0 : }
108 :
109 0 : GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStyle& style) {
110 0 : return new GrGLPath(this->gpu(), inPath, style);
111 : }
112 :
113 0 : GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
114 : const GrStyle& style) {
115 0 : return new GrGLPathRange(this->gpu(), pathGenerator, style);
116 : }
117 :
118 0 : void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
119 0 : GrGLGpu* gpu = this->gpu();
120 0 : SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
121 0 : gpu->flushColorWrite(false);
122 0 : gpu->flushDrawFace(GrDrawFace::kBoth);
123 :
124 0 : GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fRenderTarget);
125 0 : SkISize size = SkISize::Make(rt->width(), rt->height());
126 0 : this->setProjectionMatrix(*args.fViewMatrix, size, rt->origin());
127 0 : gpu->flushScissor(*args.fScissor, rt->getViewport(), rt->origin());
128 0 : gpu->flushHWAAState(rt, args.fUseHWAA, true);
129 0 : gpu->flushRenderTarget(rt, nullptr);
130 :
131 0 : const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
132 :
133 0 : this->flushPathStencilSettings(*args.fStencil);
134 0 : SkASSERT(!fHWPathStencilSettings.isTwoSided());
135 :
136 : GrGLenum fillMode =
137 0 : gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
138 0 : GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
139 :
140 0 : if (glPath->shouldFill()) {
141 0 : GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
142 : }
143 0 : if (glPath->shouldStroke()) {
144 0 : GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
145 : }
146 0 : }
147 :
148 0 : void GrGLPathRendering::onDrawPath(const GrPipeline& pipeline,
149 : const GrPrimitiveProcessor& primProc,
150 : const GrStencilSettings& stencilPassSettings,
151 : const GrPath* path) {
152 0 : if (!this->gpu()->flushGLState(pipeline, primProc, false)) {
153 0 : return;
154 : }
155 0 : const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
156 :
157 0 : this->flushPathStencilSettings(stencilPassSettings);
158 0 : SkASSERT(!fHWPathStencilSettings.isTwoSided());
159 :
160 : GrGLenum fillMode =
161 0 : gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
162 0 : GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
163 :
164 0 : if (glPath->shouldStroke()) {
165 0 : if (glPath->shouldFill()) {
166 0 : GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
167 : }
168 0 : GL_CALL(StencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask,
169 : GR_GL_BOUNDING_BOX));
170 : } else {
171 0 : GL_CALL(StencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask,
172 : GR_GL_BOUNDING_BOX));
173 : }
174 : }
175 :
176 0 : 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 0 : SkDEBUGCODE(verify_floats(transformValues, gXformType2ComponentCount[transformType] * count));
183 :
184 0 : if (!this->gpu()->flushGLState(pipeline, primProc, false)) {
185 0 : return;
186 : }
187 0 : this->flushPathStencilSettings(stencilPassSettings);
188 0 : SkASSERT(!fHWPathStencilSettings.isTwoSided());
189 :
190 :
191 0 : const GrGLPathRange* glPathRange = static_cast<const GrGLPathRange*>(pathRange);
192 :
193 : GrGLenum fillMode =
194 0 : gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
195 0 : GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
196 :
197 0 : if (glPathRange->shouldStroke()) {
198 0 : if (glPathRange->shouldFill()) {
199 0 : GL_CALL(StencilFillPathInstanced(
200 : count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
201 : fillMode, writeMask, gXformType2GLType[transformType],
202 : transformValues));
203 : }
204 0 : 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 0 : 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 :
216 0 : void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
217 : GrGLenum genMode, GrGLint components,
218 : const SkMatrix& matrix) {
219 : float coefficients[3 * 3];
220 0 : SkASSERT(components >= 1 && components <= 3);
221 :
222 0 : coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
223 0 : coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
224 0 : coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
225 :
226 0 : if (components >= 2) {
227 0 : coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
228 0 : coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
229 0 : coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
230 : }
231 :
232 0 : if (components >= 3) {
233 0 : coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
234 0 : coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
235 0 : coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
236 : }
237 0 : SkDEBUGCODE(verify_floats(coefficients, components * 3));
238 :
239 0 : GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
240 0 : }
241 :
242 0 : void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
243 : const SkISize& renderTargetSize,
244 : GrSurfaceOrigin renderTargetOrigin) {
245 :
246 0 : SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport());
247 :
248 0 : if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
249 0 : renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
250 0 : matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
251 0 : return;
252 : }
253 :
254 0 : fHWProjectionMatrixState.fViewMatrix = matrix;
255 0 : fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
256 0 : fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
257 :
258 : float glMatrix[4 * 4];
259 0 : fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
260 0 : SkDEBUGCODE(verify_floats(glMatrix, SK_ARRAY_COUNT(glMatrix)));
261 0 : GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
262 : }
263 :
264 0 : GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
265 0 : SkASSERT(range > 0);
266 : GrGLuint firstID;
267 0 : if (fPreallocatedPathCount >= range) {
268 0 : firstID = fFirstPreallocatedPathID;
269 0 : fPreallocatedPathCount -= range;
270 0 : fFirstPreallocatedPathID += range;
271 0 : 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 0 : GrGLsizei allocAmount = range + (kPathIDPreallocationAmount - fPreallocatedPathCount);
277 0 : if (allocAmount >= range) {
278 0 : GL_CALL_RET(firstID, GenPaths(allocAmount));
279 :
280 0 : if (firstID != 0) {
281 0 : if (fPreallocatedPathCount > 0 &&
282 0 : firstID == fFirstPreallocatedPathID + fPreallocatedPathCount) {
283 0 : firstID = fFirstPreallocatedPathID;
284 0 : fPreallocatedPathCount += allocAmount - range;
285 0 : fFirstPreallocatedPathID += range;
286 0 : return firstID;
287 : }
288 :
289 0 : if (allocAmount > range) {
290 0 : if (fPreallocatedPathCount > 0) {
291 0 : this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
292 : }
293 0 : fFirstPreallocatedPathID = firstID + range;
294 0 : fPreallocatedPathCount = allocAmount - range;
295 : }
296 : // Special case: if allocAmount == range, we have full preallocated range.
297 0 : return firstID;
298 : }
299 : }
300 : // Failed to allocate with preallocation. Remove existing preallocation and try to allocate just
301 : // the range.
302 0 : if (fPreallocatedPathCount > 0) {
303 0 : this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
304 0 : fPreallocatedPathCount = 0;
305 : }
306 :
307 0 : GL_CALL_RET(firstID, GenPaths(range));
308 0 : if (firstID == 0) {
309 0 : SkDebugf("Warning: Failed to allocate path\n");
310 : }
311 0 : return firstID;
312 : }
313 :
314 0 : void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
315 0 : GL_CALL(DeletePaths(path, range));
316 0 : }
317 :
318 0 : void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
319 0 : if (fHWPathStencilSettings != stencilSettings) {
320 0 : 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 0 : uint16_t ref = stencilSettings.front().fRef;
324 0 : GrStencilTest test = stencilSettings.front().fTest;
325 0 : uint16_t testMask = stencilSettings.front().fTestMask;
326 :
327 0 : if (!fHWPathStencilSettings.isValid() ||
328 0 : ref != fHWPathStencilSettings.front().fRef ||
329 0 : test != fHWPathStencilSettings.front().fTest ||
330 0 : testMask != fHWPathStencilSettings.front().fTestMask) {
331 0 : GL_CALL(PathStencilFunc(GrToGLStencilFunc(test), ref, testMask));
332 : }
333 0 : fHWPathStencilSettings = stencilSettings;
334 : }
335 0 : }
336 :
337 0 : inline GrGLGpu* GrGLPathRendering::gpu() {
338 0 : return static_cast<GrGLGpu*>(fGpu);
339 : }
|