blob: d907e86559fc1bee0f520736f18f23e54974d11a [file] [log] [blame]
cdaltonc7103a12014-08-11 14:05:05 -07001/*
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"
cdaltonc7103a12014-08-11 14:05:05 -07009#include "gl/GrGLUtil.h"
jvanverth39edf762014-12-22 11:44:19 -080010#include "gl/GrGLGpu.h"
cdaltonc7103a12014-08-11 14:05:05 -070011
kkinnunenccdaa042014-08-20 01:36:23 -070012#include "GrGLPath.h"
13#include "GrGLPathRange.h"
14#include "GrGLPathRendering.h"
15
cdalton855d83f2014-09-18 13:51:53 -070016#include "SkStream.h"
17#include "SkTypeface.h"
18
kkinnunencabe20c2015-06-01 01:37:26 -070019#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)
kkinnunenccdaa042014-08-20 01:36:23 -070021
kkinnunen702501d2016-01-13 23:36:45 -080022// 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.
24static const GrGLsizei kPathIDPreallocationAmount = 65536;
kkinnunenccdaa042014-08-20 01:36:23 -070025
cdalton55b24af2014-11-25 11:00:56 -080026static const GrGLenum gIndexType2GLType[] = {
27 GR_GL_UNSIGNED_BYTE,
28 GR_GL_UNSIGNED_SHORT,
29 GR_GL_UNSIGNED_INT
30};
31
32GR_STATIC_ASSERT(0 == GrPathRange::kU8_PathIndexType);
33GR_STATIC_ASSERT(1 == GrPathRange::kU16_PathIndexType);
34GR_STATIC_ASSERT(2 == GrPathRange::kU32_PathIndexType);
35GR_STATIC_ASSERT(GrPathRange::kU32_PathIndexType == GrPathRange::kLast_PathIndexType);
36
kkinnunenccdaa042014-08-20 01:36:23 -070037static 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
45GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
46GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
47GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
48GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
49GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
50GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
51
kkinnunen68c63b32016-03-04 00:12:33 -080052#ifdef SK_DEBUG
53static const GrGLenum gXformType2ComponentCount[] = {
54 0,
55 1,
56 1,
57 2,
58 6
59};
60
61static void verify_floats(const float* floats, int count) {
62 for (int i = 0; i < count; ++i) {
63 SkASSERT(!SkScalarIsNaN(SkFloatToScalar(floats[i])));
64 }
65}
66#endif
67
kkinnunenccdaa042014-08-20 01:36:23 -070068static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
69 switch (op) {
70 default:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -040071 SK_ABORT("Unexpected path fill.");
kkinnunenccdaa042014-08-20 01:36:23 -070072 /* fallthrough */;
cdalton193d9cf2016-05-12 11:52:02 -070073 case GrStencilOp::kIncWrap:
kkinnunenccdaa042014-08-20 01:36:23 -070074 return GR_GL_COUNT_UP;
cdalton93a379b2016-05-11 13:58:08 -070075 case GrStencilOp::kInvert:
kkinnunenccdaa042014-08-20 01:36:23 -070076 return GR_GL_INVERT;
77 }
78}
cdaltonc7103a12014-08-11 14:05:05 -070079
bsalomon861e1032014-12-16 07:33:49 -080080GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
kkinnunen702501d2016-01-13 23:36:45 -080081 : GrPathRendering(gpu)
82 , fPreallocatedPathCount(0) {
kkinnunen6bb6d402015-07-14 10:59:23 -070083 const GrGLInterface* glInterface = gpu->glInterface();
Mike Klein76343302017-06-22 13:15:13 -070084 fCaps.bindFragmentInputSupport = (bool)glInterface->fFunctions.fBindFragmentInputLocation;
cdaltonc7103a12014-08-11 14:05:05 -070085}
86
87GrGLPathRendering::~GrGLPathRendering() {
kkinnunen702501d2016-01-13 23:36:45 -080088 if (fPreallocatedPathCount > 0) {
89 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
90 }
cdaltonc7103a12014-08-11 14:05:05 -070091}
92
bsalomon6e2aad42016-04-01 11:54:31 -070093void GrGLPathRendering::disconnect(GrGpu::DisconnectType type) {
94 if (GrGpu::DisconnectType::kCleanup == type) {
95 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
96 };
kkinnunen702501d2016-01-13 23:36:45 -080097 fPreallocatedPathCount = 0;
cdaltonc7103a12014-08-11 14:05:05 -070098}
99
kkinnunenccdaa042014-08-20 01:36:23 -0700100void GrGLPathRendering::resetContext() {
101 fHWProjectionMatrixState.invalidate();
102 // we don't use the model view matrix.
jvanverth50530632015-04-27 10:36:27 -0700103 GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
kkinnunenccdaa042014-08-20 01:36:23 -0700104
kkinnunenccdaa042014-08-20 01:36:23 -0700105 fHWPathStencilSettings.invalidate();
106}
107
Robert Phillips67d52cf2017-06-05 13:38:13 -0400108sk_sp<GrPath> GrGLPathRendering::createPath(const SkPath& inPath, const GrStyle& style) {
109 return sk_make_sp<GrGLPath>(this->gpu(), inPath, style);
kkinnunenccdaa042014-08-20 01:36:23 -0700110}
111
Robert Phillips67d52cf2017-06-05 13:38:13 -0400112sk_sp<GrPathRange> GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
113 const GrStyle& style) {
114 return sk_make_sp<GrGLPathRange>(this->gpu(), pathGenerator, style);
cdalton855d83f2014-09-18 13:51:53 -0700115}
116
kkinnunencabe20c2015-06-01 01:37:26 -0700117void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
118 GrGLGpu* gpu = this->gpu();
119 SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
120 gpu->flushColorWrite(false);
kkinnunencabe20c2015-06-01 01:37:26 -0700121
Robert Phillips7311b402017-07-27 12:01:46 -0400122 GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fProxy->priv().peekRenderTarget());
kkinnunencabe20c2015-06-01 01:37:26 -0700123 SkISize size = SkISize::Make(rt->width(), rt->height());
Robert Phillips7311b402017-07-27 12:01:46 -0400124 this->setProjectionMatrix(*args.fViewMatrix, size, args.fProxy->origin());
125 gpu->flushScissor(*args.fScissor, rt->getViewport(), args.fProxy->origin());
cdaltonaf8bc7d2016-02-05 09:35:20 -0800126 gpu->flushHWAAState(rt, args.fUseHWAA, true);
halcanary96fcdcc2015-08-27 07:41:13 -0700127 gpu->flushRenderTarget(rt, nullptr);
kkinnunencabe20c2015-06-01 01:37:26 -0700128
kkinnunen50b58e62015-05-18 23:02:07 -0700129 const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
kkinnunen5b653572014-08-20 04:13:27 -0700130
kkinnunencabe20c2015-06-01 01:37:26 -0700131 this->flushPathStencilSettings(*args.fStencil);
kkinnunen5b653572014-08-20 04:13:27 -0700132 SkASSERT(!fHWPathStencilSettings.isTwoSided());
133
cdalton93a379b2016-05-11 13:58:08 -0700134 GrGLenum fillMode =
135 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
136 GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
joshualitt92e496f2014-10-31 13:56:50 -0700137
kkinnunen50b58e62015-05-18 23:02:07 -0700138 if (glPath->shouldFill()) {
139 GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
joshualitt92e496f2014-10-31 13:56:50 -0700140 }
kkinnunen50b58e62015-05-18 23:02:07 -0700141 if (glPath->shouldStroke()) {
142 GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
joshualitt92e496f2014-10-31 13:56:50 -0700143 }
144}
145
stephana1dc17212016-04-25 07:01:22 -0700146void GrGLPathRendering::onDrawPath(const GrPipeline& pipeline,
147 const GrPrimitiveProcessor& primProc,
cdalton193d9cf2016-05-12 11:52:02 -0700148 const GrStencilSettings& stencilPassSettings,
stephana1dc17212016-04-25 07:01:22 -0700149 const GrPath* path) {
bsalomon2eda5b32016-09-21 10:53:24 -0700150 if (!this->gpu()->flushGLState(pipeline, primProc, false)) {
stephana1dc17212016-04-25 07:01:22 -0700151 return;
152 }
153 const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
154
cdalton193d9cf2016-05-12 11:52:02 -0700155 this->flushPathStencilSettings(stencilPassSettings);
stephana1dc17212016-04-25 07:01:22 -0700156 SkASSERT(!fHWPathStencilSettings.isTwoSided());
157
cdalton93a379b2016-05-11 13:58:08 -0700158 GrGLenum fillMode =
159 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
160 GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
stephana1dc17212016-04-25 07:01:22 -0700161
162 if (glPath->shouldStroke()) {
163 if (glPath->shouldFill()) {
164 GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
165 }
166 GL_CALL(StencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask,
167 GR_GL_BOUNDING_BOX));
168 } else {
169 GL_CALL(StencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask,
170 GR_GL_BOUNDING_BOX));
171 }
172}
173
egdaniel0e1853c2016-03-17 11:35:45 -0700174void GrGLPathRendering::onDrawPaths(const GrPipeline& pipeline,
175 const GrPrimitiveProcessor& primProc,
cdalton193d9cf2016-05-12 11:52:02 -0700176 const GrStencilSettings& stencilPassSettings,
177 const GrPathRange* pathRange, const void* indices,
178 PathIndexType indexType, const float transformValues[],
179 PathTransformType transformType, int count) {
kkinnunen68c63b32016-03-04 00:12:33 -0800180 SkDEBUGCODE(verify_floats(transformValues, gXformType2ComponentCount[transformType] * count));
181
bsalomon2eda5b32016-09-21 10:53:24 -0700182 if (!this->gpu()->flushGLState(pipeline, primProc, false)) {
kkinnunencabe20c2015-06-01 01:37:26 -0700183 return;
184 }
cdalton193d9cf2016-05-12 11:52:02 -0700185 this->flushPathStencilSettings(stencilPassSettings);
kkinnunencabe20c2015-06-01 01:37:26 -0700186 SkASSERT(!fHWPathStencilSettings.isTwoSided());
187
kkinnunen5b653572014-08-20 04:13:27 -0700188
kkinnunen50b58e62015-05-18 23:02:07 -0700189 const GrGLPathRange* glPathRange = static_cast<const GrGLPathRange*>(pathRange);
kkinnunen5b653572014-08-20 04:13:27 -0700190
kkinnunen5b653572014-08-20 04:13:27 -0700191 GrGLenum fillMode =
cdalton93a379b2016-05-11 13:58:08 -0700192 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp);
193 GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask;
kkinnunen5b653572014-08-20 04:13:27 -0700194
kkinnunen50b58e62015-05-18 23:02:07 -0700195 if (glPathRange->shouldStroke()) {
196 if (glPathRange->shouldFill()) {
kkinnunen5b653572014-08-20 04:13:27 -0700197 GL_CALL(StencilFillPathInstanced(
kkinnunen50b58e62015-05-18 23:02:07 -0700198 count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
199 fillMode, writeMask, gXformType2GLType[transformType],
200 transformValues));
kkinnunen5b653572014-08-20 04:13:27 -0700201 }
kkinnunencfe62e32015-07-01 02:58:50 -0700202 GL_CALL(StencilThenCoverStrokePathInstanced(
kkinnunen50b58e62015-05-18 23:02:07 -0700203 count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
cdalton55b24af2014-11-25 11:00:56 -0800204 0xffff, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
kkinnunencfe62e32015-07-01 02:58:50 -0700205 gXformType2GLType[transformType], transformValues));
joshualitt92e496f2014-10-31 13:56:50 -0700206 } else {
kkinnunencfe62e32015-07-01 02:58:50 -0700207 GL_CALL(StencilThenCoverFillPathInstanced(
kkinnunen50b58e62015-05-18 23:02:07 -0700208 count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
cdalton55b24af2014-11-25 11:00:56 -0800209 fillMode, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
kkinnunencfe62e32015-07-01 02:58:50 -0700210 gXformType2GLType[transformType], transformValues));
kkinnunen5b653572014-08-20 04:13:27 -0700211 }
212}
213
kkinnunen5b653572014-08-20 04:13:27 -0700214void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
215 GrGLenum genMode, GrGLint components,
216 const SkMatrix& matrix) {
egdaniel018fb622015-10-28 07:26:40 -0700217 float coefficients[3 * 3];
kkinnunen5b653572014-08-20 04:13:27 -0700218 SkASSERT(components >= 1 && components <= 3);
kkinnunenccdaa042014-08-20 01:36:23 -0700219
kkinnunen5b653572014-08-20 04:13:27 -0700220 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
221 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
222 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
kkinnunenccdaa042014-08-20 01:36:23 -0700223
kkinnunen5b653572014-08-20 04:13:27 -0700224 if (components >= 2) {
225 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
226 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
227 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
kkinnunenccdaa042014-08-20 01:36:23 -0700228 }
kkinnunenccdaa042014-08-20 01:36:23 -0700229
kkinnunen5b653572014-08-20 04:13:27 -0700230 if (components >= 3) {
231 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
232 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
233 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
kkinnunenccdaa042014-08-20 01:36:23 -0700234 }
kkinnunen68c63b32016-03-04 00:12:33 -0800235 SkDEBUGCODE(verify_floats(coefficients, components * 3));
kkinnunenccdaa042014-08-20 01:36:23 -0700236
kkinnunen5b653572014-08-20 04:13:27 -0700237 GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700238}
239
240void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
joshualittee2af952014-12-30 09:04:15 -0800241 const SkISize& renderTargetSize,
242 GrSurfaceOrigin renderTargetOrigin) {
kkinnunenccdaa042014-08-20 01:36:23 -0700243
kkinnunencabe20c2015-06-01 01:37:26 -0700244 SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport());
kkinnunenccdaa042014-08-20 01:36:23 -0700245
246 if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
247 renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
248 matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
249 return;
250 }
251
252 fHWProjectionMatrixState.fViewMatrix = matrix;
253 fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
254 fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
255
egdaniel018fb622015-10-28 07:26:40 -0700256 float glMatrix[4 * 4];
kkinnunenccdaa042014-08-20 01:36:23 -0700257 fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
kkinnunen68c63b32016-03-04 00:12:33 -0800258 SkDEBUGCODE(verify_floats(glMatrix, SK_ARRAY_COUNT(glMatrix)));
jvanverth50530632015-04-27 10:36:27 -0700259 GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
kkinnunenccdaa042014-08-20 01:36:23 -0700260}
261
cdaltonc7103a12014-08-11 14:05:05 -0700262GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
kkinnunen702501d2016-01-13 23:36:45 -0800263 SkASSERT(range > 0);
264 GrGLuint firstID;
265 if (fPreallocatedPathCount >= range) {
266 firstID = fFirstPreallocatedPathID;
267 fPreallocatedPathCount -= range;
268 fFirstPreallocatedPathID += range;
269 return firstID;
270 }
271 // Allocate range + the amount to fill up preallocation amount. If succeed, either join with
272 // the existing preallocation range or delete the existing and use the new (potentially partial)
273 // preallocation range.
274 GrGLsizei allocAmount = range + (kPathIDPreallocationAmount - fPreallocatedPathCount);
275 if (allocAmount >= range) {
276 GL_CALL_RET(firstID, GenPaths(allocAmount));
277
278 if (firstID != 0) {
279 if (fPreallocatedPathCount > 0 &&
280 firstID == fFirstPreallocatedPathID + fPreallocatedPathCount) {
281 firstID = fFirstPreallocatedPathID;
282 fPreallocatedPathCount += allocAmount - range;
283 fFirstPreallocatedPathID += range;
284 return firstID;
285 }
286
287 if (allocAmount > range) {
288 if (fPreallocatedPathCount > 0) {
289 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
290 }
291 fFirstPreallocatedPathID = firstID + range;
292 fPreallocatedPathCount = allocAmount - range;
293 }
294 // Special case: if allocAmount == range, we have full preallocated range.
295 return firstID;
296 }
297 }
298 // Failed to allocate with preallocation. Remove existing preallocation and try to allocate just
299 // the range.
300 if (fPreallocatedPathCount > 0) {
301 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
302 fPreallocatedPathCount = 0;
cdaltonc7103a12014-08-11 14:05:05 -0700303 }
304
kkinnunen702501d2016-01-13 23:36:45 -0800305 GL_CALL_RET(firstID, GenPaths(range));
306 if (firstID == 0) {
307 SkDebugf("Warning: Failed to allocate path\n");
cdaltonc7103a12014-08-11 14:05:05 -0700308 }
kkinnunen702501d2016-01-13 23:36:45 -0800309 return firstID;
cdaltonc7103a12014-08-11 14:05:05 -0700310}
311
kkinnunen5b653572014-08-20 04:13:27 -0700312void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
kkinnunen702501d2016-01-13 23:36:45 -0800313 GL_CALL(DeletePaths(path, range));
cdaltonc7103a12014-08-11 14:05:05 -0700314}
315
joshualitt92e496f2014-10-31 13:56:50 -0700316void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
317 if (fHWPathStencilSettings != stencilSettings) {
kkinnunen1517f932016-01-25 06:07:26 -0800318 SkASSERT(stencilSettings.isValid());
kkinnunen5b653572014-08-20 04:13:27 -0700319 // Just the func, ref, and mask is set here. The op and write mask are params to the call
320 // that draws the path to the SB (glStencilFillPath)
cdalton93a379b2016-05-11 13:58:08 -0700321 uint16_t ref = stencilSettings.front().fRef;
322 GrStencilTest test = stencilSettings.front().fTest;
323 uint16_t testMask = stencilSettings.front().fTestMask;
kkinnunen5b653572014-08-20 04:13:27 -0700324
kkinnunen1517f932016-01-25 06:07:26 -0800325 if (!fHWPathStencilSettings.isValid() ||
cdalton93a379b2016-05-11 13:58:08 -0700326 ref != fHWPathStencilSettings.front().fRef ||
327 test != fHWPathStencilSettings.front().fTest ||
328 testMask != fHWPathStencilSettings.front().fTestMask) {
329 GL_CALL(PathStencilFunc(GrToGLStencilFunc(test), ref, testMask));
kkinnunen1517f932016-01-25 06:07:26 -0800330 }
joshualitt92e496f2014-10-31 13:56:50 -0700331 fHWPathStencilSettings = stencilSettings;
kkinnunen5b653572014-08-20 04:13:27 -0700332 }
cdaltonc7103a12014-08-11 14:05:05 -0700333}
334
kkinnunencabe20c2015-06-01 01:37:26 -0700335inline GrGLGpu* GrGLPathRendering::gpu() {
336 return static_cast<GrGLGpu*>(fGpu);
337}