blob: 58783cef0417915335539c3239da8b8878c612c5 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/gl/GrGLGpu.h"
9#include "src/gpu/gl/GrGLPathRendering.h"
10#include "src/gpu/gl/GrGLUtil.h"
cdaltonc7103a12014-08-11 14:05:05 -070011
Greg Danielf91aeb22019-06-18 09:58:02 -040012#include "src/gpu/GrRenderTargetProxy.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/gl/GrGLPath.h"
14#include "src/gpu/gl/GrGLPathRendering.h"
kkinnunenccdaa042014-08-20 01:36:23 -070015
Mike Kleinc0bd9f92019-04-23 12:05:21 -050016#include "include/core/SkStream.h"
17#include "include/core/SkTypeface.h"
cdalton855d83f2014-09-18 13:51:53 -070018
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
kkinnunenccdaa042014-08-20 01:36:23 -070026GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
27GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
28GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
29GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
30GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
31GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
32
kkinnunen68c63b32016-03-04 00:12:33 -080033#ifdef SK_DEBUG
kkinnunen68c63b32016-03-04 00:12:33 -080034
35static 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
kkinnunenccdaa042014-08-20 01:36:23 -070042static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
43 switch (op) {
44 default:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -040045 SK_ABORT("Unexpected path fill.");
Brian Salomon23356442018-11-30 15:33:19 -050046 /* fallthrough */
cdalton193d9cf2016-05-12 11:52:02 -070047 case GrStencilOp::kIncWrap:
kkinnunenccdaa042014-08-20 01:36:23 -070048 return GR_GL_COUNT_UP;
cdalton93a379b2016-05-11 13:58:08 -070049 case GrStencilOp::kInvert:
kkinnunenccdaa042014-08-20 01:36:23 -070050 return GR_GL_INVERT;
51 }
52}
cdaltonc7103a12014-08-11 14:05:05 -070053
bsalomon861e1032014-12-16 07:33:49 -080054GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
kkinnunen702501d2016-01-13 23:36:45 -080055 : GrPathRendering(gpu)
56 , fPreallocatedPathCount(0) {
kkinnunen6bb6d402015-07-14 10:59:23 -070057 const GrGLInterface* glInterface = gpu->glInterface();
Mike Klein76343302017-06-22 13:15:13 -070058 fCaps.bindFragmentInputSupport = (bool)glInterface->fFunctions.fBindFragmentInputLocation;
cdaltonc7103a12014-08-11 14:05:05 -070059}
60
61GrGLPathRendering::~GrGLPathRendering() {
kkinnunen702501d2016-01-13 23:36:45 -080062 if (fPreallocatedPathCount > 0) {
63 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
64 }
cdaltonc7103a12014-08-11 14:05:05 -070065}
66
bsalomon6e2aad42016-04-01 11:54:31 -070067void GrGLPathRendering::disconnect(GrGpu::DisconnectType type) {
68 if (GrGpu::DisconnectType::kCleanup == type) {
69 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
Brian Salomon23356442018-11-30 15:33:19 -050070 }
kkinnunen702501d2016-01-13 23:36:45 -080071 fPreallocatedPathCount = 0;
cdaltonc7103a12014-08-11 14:05:05 -070072}
73
kkinnunenccdaa042014-08-20 01:36:23 -070074void GrGLPathRendering::resetContext() {
75 fHWProjectionMatrixState.invalidate();
76 // we don't use the model view matrix.
jvanverth50530632015-04-27 10:36:27 -070077 GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
kkinnunenccdaa042014-08-20 01:36:23 -070078
kkinnunenccdaa042014-08-20 01:36:23 -070079 fHWPathStencilSettings.invalidate();
80}
81
Robert Phillips67d52cf2017-06-05 13:38:13 -040082sk_sp<GrPath> GrGLPathRendering::createPath(const SkPath& inPath, const GrStyle& style) {
83 return sk_make_sp<GrGLPath>(this->gpu(), inPath, style);
kkinnunenccdaa042014-08-20 01:36:23 -070084}
85
kkinnunencabe20c2015-06-01 01:37:26 -070086void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
87 GrGLGpu* gpu = this->gpu();
88 SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
89 gpu->flushColorWrite(false);
kkinnunencabe20c2015-06-01 01:37:26 -070090
Brian Salomonfd98c2c2018-07-31 17:25:29 -040091 GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fProxy->peekRenderTarget());
kkinnunencabe20c2015-06-01 01:37:26 -070092 SkISize size = SkISize::Make(rt->width(), rt->height());
Chris Daltonc8ece3d2018-07-30 15:03:45 -060093 this->setProjectionMatrix(*args.fViewMatrix, size, args.fProxy->origin());
Greg Danielacd66b42019-05-22 16:29:12 -040094 gpu->flushScissor(*args.fScissor, rt->width(), rt->height(), args.fProxy->origin());
Chris Dalton4c56b032019-03-04 12:28:42 -070095 gpu->flushHWAAState(rt, args.fUseHWAA);
Chris Daltonc8ece3d2018-07-30 15:03:45 -060096 gpu->flushRenderTarget(rt);
kkinnunencabe20c2015-06-01 01:37:26 -070097
kkinnunen50b58e62015-05-18 23:02:07 -070098 const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
kkinnunen5b653572014-08-20 04:13:27 -070099
kkinnunencabe20c2015-06-01 01:37:26 -0700100 this->flushPathStencilSettings(*args.fStencil);
kkinnunen5b653572014-08-20 04:13:27 -0700101
cdalton93a379b2016-05-11 13:58:08 -0700102 GrGLenum fillMode =
Chris Dalton71713f62019-04-18 12:41:03 -0600103 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.frontAndBack().fPassOp);
104 GrGLint writeMask = fHWPathStencilSettings.frontAndBack().fWriteMask;
joshualitt92e496f2014-10-31 13:56:50 -0700105
kkinnunen50b58e62015-05-18 23:02:07 -0700106 if (glPath->shouldFill()) {
107 GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
joshualitt92e496f2014-10-31 13:56:50 -0700108 }
kkinnunen50b58e62015-05-18 23:02:07 -0700109 if (glPath->shouldStroke()) {
110 GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
joshualitt92e496f2014-10-31 13:56:50 -0700111 }
112}
113
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500114void GrGLPathRendering::onDrawPath(GrRenderTarget* renderTarget, GrSurfaceOrigin origin,
115 const GrPrimitiveProcessor& primProc,
Brian Salomonff168d92018-06-23 15:17:27 -0400116 const GrPipeline& pipeline,
Brian Salomon49348902018-06-26 09:12:38 -0400117 const GrPipeline::FixedDynamicState& fixedDynamicState,
cdalton193d9cf2016-05-12 11:52:02 -0700118 const GrStencilSettings& stencilPassSettings,
stephana1dc17212016-04-25 07:01:22 -0700119 const GrPath* path) {
Robert Phillipsd0fe8752019-01-31 14:13:59 -0500120 if (!this->gpu()->flushGLState(renderTarget, origin, primProc, pipeline,
121 &fixedDynamicState, nullptr, 1, false)) {
stephana1dc17212016-04-25 07:01:22 -0700122 return;
123 }
124 const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
125
cdalton193d9cf2016-05-12 11:52:02 -0700126 this->flushPathStencilSettings(stencilPassSettings);
stephana1dc17212016-04-25 07:01:22 -0700127
cdalton93a379b2016-05-11 13:58:08 -0700128 GrGLenum fillMode =
Chris Dalton71713f62019-04-18 12:41:03 -0600129 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.frontAndBack().fPassOp);
130 GrGLint writeMask = fHWPathStencilSettings.frontAndBack().fWriteMask;
stephana1dc17212016-04-25 07:01:22 -0700131
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
kkinnunen5b653572014-08-20 04:13:27 -0700144void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
145 GrGLenum genMode, GrGLint components,
146 const SkMatrix& matrix) {
egdaniel018fb622015-10-28 07:26:40 -0700147 float coefficients[3 * 3];
kkinnunen5b653572014-08-20 04:13:27 -0700148 SkASSERT(components >= 1 && components <= 3);
kkinnunenccdaa042014-08-20 01:36:23 -0700149
kkinnunen5b653572014-08-20 04:13:27 -0700150 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
151 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
152 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
kkinnunenccdaa042014-08-20 01:36:23 -0700153
kkinnunen5b653572014-08-20 04:13:27 -0700154 if (components >= 2) {
155 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
156 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
157 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
kkinnunenccdaa042014-08-20 01:36:23 -0700158 }
kkinnunenccdaa042014-08-20 01:36:23 -0700159
kkinnunen5b653572014-08-20 04:13:27 -0700160 if (components >= 3) {
161 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
162 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
163 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
kkinnunenccdaa042014-08-20 01:36:23 -0700164 }
kkinnunen68c63b32016-03-04 00:12:33 -0800165 SkDEBUGCODE(verify_floats(coefficients, components * 3));
kkinnunenccdaa042014-08-20 01:36:23 -0700166
kkinnunen5b653572014-08-20 04:13:27 -0700167 GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700168}
169
170void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
joshualittee2af952014-12-30 09:04:15 -0800171 const SkISize& renderTargetSize,
172 GrSurfaceOrigin renderTargetOrigin) {
kkinnunenccdaa042014-08-20 01:36:23 -0700173
kkinnunencabe20c2015-06-01 01:37:26 -0700174 SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport());
kkinnunenccdaa042014-08-20 01:36:23 -0700175
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
egdaniel018fb622015-10-28 07:26:40 -0700186 float glMatrix[4 * 4];
kkinnunenccdaa042014-08-20 01:36:23 -0700187 fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
kkinnunen68c63b32016-03-04 00:12:33 -0800188 SkDEBUGCODE(verify_floats(glMatrix, SK_ARRAY_COUNT(glMatrix)));
jvanverth50530632015-04-27 10:36:27 -0700189 GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
kkinnunenccdaa042014-08-20 01:36:23 -0700190}
191
cdaltonc7103a12014-08-11 14:05:05 -0700192GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
kkinnunen702501d2016-01-13 23:36:45 -0800193 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;
cdaltonc7103a12014-08-11 14:05:05 -0700233 }
234
kkinnunen702501d2016-01-13 23:36:45 -0800235 GL_CALL_RET(firstID, GenPaths(range));
236 if (firstID == 0) {
237 SkDebugf("Warning: Failed to allocate path\n");
cdaltonc7103a12014-08-11 14:05:05 -0700238 }
kkinnunen702501d2016-01-13 23:36:45 -0800239 return firstID;
cdaltonc7103a12014-08-11 14:05:05 -0700240}
241
kkinnunen5b653572014-08-20 04:13:27 -0700242void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
kkinnunen702501d2016-01-13 23:36:45 -0800243 GL_CALL(DeletePaths(path, range));
cdaltonc7103a12014-08-11 14:05:05 -0700244}
245
joshualitt92e496f2014-10-31 13:56:50 -0700246void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
Chris Dalton71713f62019-04-18 12:41:03 -0600247 SkASSERT(!stencilSettings.isTwoSided());
joshualitt92e496f2014-10-31 13:56:50 -0700248 if (fHWPathStencilSettings != stencilSettings) {
kkinnunen1517f932016-01-25 06:07:26 -0800249 SkASSERT(stencilSettings.isValid());
kkinnunen5b653572014-08-20 04:13:27 -0700250 // 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)
Chris Dalton71713f62019-04-18 12:41:03 -0600252 uint16_t ref = stencilSettings.frontAndBack().fRef;
253 GrStencilTest test = stencilSettings.frontAndBack().fTest;
254 uint16_t testMask = stencilSettings.frontAndBack().fTestMask;
kkinnunen5b653572014-08-20 04:13:27 -0700255
kkinnunen1517f932016-01-25 06:07:26 -0800256 if (!fHWPathStencilSettings.isValid() ||
Chris Dalton71713f62019-04-18 12:41:03 -0600257 ref != fHWPathStencilSettings.frontAndBack().fRef ||
258 test != fHWPathStencilSettings.frontAndBack().fTest ||
259 testMask != fHWPathStencilSettings.frontAndBack().fTestMask) {
cdalton93a379b2016-05-11 13:58:08 -0700260 GL_CALL(PathStencilFunc(GrToGLStencilFunc(test), ref, testMask));
kkinnunen1517f932016-01-25 06:07:26 -0800261 }
joshualitt92e496f2014-10-31 13:56:50 -0700262 fHWPathStencilSettings = stencilSettings;
kkinnunen5b653572014-08-20 04:13:27 -0700263 }
cdaltonc7103a12014-08-11 14:05:05 -0700264}
265
kkinnunencabe20c2015-06-01 01:37:26 -0700266inline GrGLGpu* GrGLPathRendering::gpu() {
267 return static_cast<GrGLGpu*>(fGpu);
268}