blob: 8beb34b5b6bd68dcbfa12191bb9e8a471ef74069 [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 "include/core/SkStream.h"
9#include "include/core/SkTypeface.h"
Michael Ludwigfbe28592020-06-26 16:02:15 -040010#include "src/core/SkMatrixPriv.h"
Chris Dalton2e7ed262020-02-21 15:17:59 -070011#include "src/gpu/GrProgramInfo.h"
12#include "src/gpu/GrRenderTargetProxy.h"
13#include "src/gpu/gl/GrGLGpu.h"
14#include "src/gpu/gl/GrGLPath.h"
15#include "src/gpu/gl/GrGLPathRendering.h"
16#include "src/gpu/gl/GrGLUtil.h"
cdalton855d83f2014-09-18 13:51:53 -070017
kkinnunencabe20c2015-06-01 01:37:26 -070018#define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
19#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->gpu()->glInterface(), RET, X)
kkinnunenccdaa042014-08-20 01:36:23 -070020
kkinnunen702501d2016-01-13 23:36:45 -080021// Number of paths to allocate per glGenPaths call. The call can be overly slow on command buffer GL
22// implementation. The call has a result value, and thus waiting for the call completion is needed.
23static const GrGLsizei kPathIDPreallocationAmount = 65536;
kkinnunenccdaa042014-08-20 01:36:23 -070024
Brian Salomon4dea72a2019-12-18 10:43:10 -050025static_assert(0 == GrPathRendering::kNone_PathTransformType);
26static_assert(1 == GrPathRendering::kTranslateX_PathTransformType);
27static_assert(2 == GrPathRendering::kTranslateY_PathTransformType);
28static_assert(3 == GrPathRendering::kTranslate_PathTransformType);
29static_assert(4 == GrPathRendering::kAffine_PathTransformType);
30static_assert(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
kkinnunenccdaa042014-08-20 01:36:23 -070031
kkinnunen68c63b32016-03-04 00:12:33 -080032#ifdef SK_DEBUG
kkinnunen68c63b32016-03-04 00:12:33 -080033
34static void verify_floats(const float* floats, int count) {
35 for (int i = 0; i < count; ++i) {
36 SkASSERT(!SkScalarIsNaN(SkFloatToScalar(floats[i])));
37 }
38}
39#endif
40
kkinnunenccdaa042014-08-20 01:36:23 -070041static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
42 switch (op) {
43 default:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -040044 SK_ABORT("Unexpected path fill.");
Brian Salomon23356442018-11-30 15:33:19 -050045 /* fallthrough */
cdalton193d9cf2016-05-12 11:52:02 -070046 case GrStencilOp::kIncWrap:
kkinnunenccdaa042014-08-20 01:36:23 -070047 return GR_GL_COUNT_UP;
cdalton93a379b2016-05-11 13:58:08 -070048 case GrStencilOp::kInvert:
kkinnunenccdaa042014-08-20 01:36:23 -070049 return GR_GL_INVERT;
50 }
51}
cdaltonc7103a12014-08-11 14:05:05 -070052
bsalomon861e1032014-12-16 07:33:49 -080053GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
kkinnunen702501d2016-01-13 23:36:45 -080054 : GrPathRendering(gpu)
55 , fPreallocatedPathCount(0) {
kkinnunen6bb6d402015-07-14 10:59:23 -070056 const GrGLInterface* glInterface = gpu->glInterface();
Mike Klein76343302017-06-22 13:15:13 -070057 fCaps.bindFragmentInputSupport = (bool)glInterface->fFunctions.fBindFragmentInputLocation;
cdaltonc7103a12014-08-11 14:05:05 -070058}
59
60GrGLPathRendering::~GrGLPathRendering() {
kkinnunen702501d2016-01-13 23:36:45 -080061 if (fPreallocatedPathCount > 0) {
62 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
63 }
cdaltonc7103a12014-08-11 14:05:05 -070064}
65
bsalomon6e2aad42016-04-01 11:54:31 -070066void GrGLPathRendering::disconnect(GrGpu::DisconnectType type) {
67 if (GrGpu::DisconnectType::kCleanup == type) {
68 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
Brian Salomon23356442018-11-30 15:33:19 -050069 }
kkinnunen702501d2016-01-13 23:36:45 -080070 fPreallocatedPathCount = 0;
cdaltonc7103a12014-08-11 14:05:05 -070071}
72
kkinnunenccdaa042014-08-20 01:36:23 -070073void GrGLPathRendering::resetContext() {
74 fHWProjectionMatrixState.invalidate();
75 // we don't use the model view matrix.
jvanverth50530632015-04-27 10:36:27 -070076 GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
kkinnunenccdaa042014-08-20 01:36:23 -070077
kkinnunenccdaa042014-08-20 01:36:23 -070078 fHWPathStencilSettings.invalidate();
79}
80
Robert Phillips67d52cf2017-06-05 13:38:13 -040081sk_sp<GrPath> GrGLPathRendering::createPath(const SkPath& inPath, const GrStyle& style) {
82 return sk_make_sp<GrGLPath>(this->gpu(), inPath, style);
kkinnunenccdaa042014-08-20 01:36:23 -070083}
84
kkinnunencabe20c2015-06-01 01:37:26 -070085void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
86 GrGLGpu* gpu = this->gpu();
87 SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
88 gpu->flushColorWrite(false);
kkinnunencabe20c2015-06-01 01:37:26 -070089
Brian Salomonfd98c2c2018-07-31 17:25:29 -040090 GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fProxy->peekRenderTarget());
Brian Salomon9f2b86c2019-10-22 10:37:46 -040091 SkISize dimensions = rt->dimensions();
Greg Danielb8d84f82020-02-13 14:25:00 -050092 this->setProjectionMatrix(*args.fViewMatrix, dimensions, args.fOrigin);
93 gpu->flushScissor(*args.fScissor, rt->width(), rt->height(), args.fOrigin);
Chris Dalton4c56b032019-03-04 12:28:42 -070094 gpu->flushHWAAState(rt, args.fUseHWAA);
Chris Daltonc8ece3d2018-07-30 15:03:45 -060095 gpu->flushRenderTarget(rt);
kkinnunencabe20c2015-06-01 01:37:26 -070096
kkinnunen50b58e62015-05-18 23:02:07 -070097 const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
kkinnunen5b653572014-08-20 04:13:27 -070098
kkinnunencabe20c2015-06-01 01:37:26 -070099 this->flushPathStencilSettings(*args.fStencil);
kkinnunen5b653572014-08-20 04:13:27 -0700100
Chris Dalton67d43fe2019-11-05 23:01:21 -0700101 GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
102 fHWPathStencilSettings.singleSidedFace().fPassOp);
103 GrGLint writeMask = fHWPathStencilSettings.singleSidedFace().fWriteMask;
joshualitt92e496f2014-10-31 13:56:50 -0700104
kkinnunen50b58e62015-05-18 23:02:07 -0700105 if (glPath->shouldFill()) {
106 GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
joshualitt92e496f2014-10-31 13:56:50 -0700107 }
kkinnunen50b58e62015-05-18 23:02:07 -0700108 if (glPath->shouldStroke()) {
109 GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
joshualitt92e496f2014-10-31 13:56:50 -0700110 }
111}
112
Chris Dalton304e14d2020-03-17 14:29:06 -0600113void GrGLPathRendering::onDrawPath(const GrStencilSettings& stencilPassSettings,
stephana1dc17212016-04-25 07:01:22 -0700114 const GrPath* path) {
stephana1dc17212016-04-25 07:01:22 -0700115 const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
116
cdalton193d9cf2016-05-12 11:52:02 -0700117 this->flushPathStencilSettings(stencilPassSettings);
stephana1dc17212016-04-25 07:01:22 -0700118
Chris Dalton67d43fe2019-11-05 23:01:21 -0700119 GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
120 fHWPathStencilSettings.singleSidedFace().fPassOp);
121 GrGLint writeMask = fHWPathStencilSettings.singleSidedFace().fWriteMask;
stephana1dc17212016-04-25 07:01:22 -0700122
123 if (glPath->shouldStroke()) {
124 if (glPath->shouldFill()) {
125 GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
126 }
127 GL_CALL(StencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask,
128 GR_GL_BOUNDING_BOX));
129 } else {
130 GL_CALL(StencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask,
131 GR_GL_BOUNDING_BOX));
132 }
133}
134
kkinnunen5b653572014-08-20 04:13:27 -0700135void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
136 GrGLenum genMode, GrGLint components,
137 const SkMatrix& matrix) {
egdaniel018fb622015-10-28 07:26:40 -0700138 float coefficients[3 * 3];
kkinnunen5b653572014-08-20 04:13:27 -0700139 SkASSERT(components >= 1 && components <= 3);
kkinnunenccdaa042014-08-20 01:36:23 -0700140
kkinnunen5b653572014-08-20 04:13:27 -0700141 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
142 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
143 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
kkinnunenccdaa042014-08-20 01:36:23 -0700144
kkinnunen5b653572014-08-20 04:13:27 -0700145 if (components >= 2) {
146 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
147 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
148 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
kkinnunenccdaa042014-08-20 01:36:23 -0700149 }
kkinnunenccdaa042014-08-20 01:36:23 -0700150
kkinnunen5b653572014-08-20 04:13:27 -0700151 if (components >= 3) {
152 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
153 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
154 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
kkinnunenccdaa042014-08-20 01:36:23 -0700155 }
kkinnunen68c63b32016-03-04 00:12:33 -0800156 SkDEBUGCODE(verify_floats(coefficients, components * 3));
kkinnunenccdaa042014-08-20 01:36:23 -0700157
kkinnunen5b653572014-08-20 04:13:27 -0700158 GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700159}
160
161void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
joshualittee2af952014-12-30 09:04:15 -0800162 const SkISize& renderTargetSize,
163 GrSurfaceOrigin renderTargetOrigin) {
kkinnunenccdaa042014-08-20 01:36:23 -0700164
kkinnunencabe20c2015-06-01 01:37:26 -0700165 SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport());
kkinnunenccdaa042014-08-20 01:36:23 -0700166
167 if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
168 renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
Mike Reed2c383152019-12-18 16:47:47 -0500169 SkMatrixPriv::CheapEqual(matrix, fHWProjectionMatrixState.fViewMatrix)) {
kkinnunenccdaa042014-08-20 01:36:23 -0700170 return;
171 }
172
173 fHWProjectionMatrixState.fViewMatrix = matrix;
174 fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
175 fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
176
egdaniel018fb622015-10-28 07:26:40 -0700177 float glMatrix[4 * 4];
Brian Osman0b1e5fc2020-03-18 11:27:10 -0400178 fHWProjectionMatrixState.getRTAdjustedGLMatrix(glMatrix);
kkinnunen68c63b32016-03-04 00:12:33 -0800179 SkDEBUGCODE(verify_floats(glMatrix, SK_ARRAY_COUNT(glMatrix)));
jvanverth50530632015-04-27 10:36:27 -0700180 GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
kkinnunenccdaa042014-08-20 01:36:23 -0700181}
182
cdaltonc7103a12014-08-11 14:05:05 -0700183GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
kkinnunen702501d2016-01-13 23:36:45 -0800184 SkASSERT(range > 0);
185 GrGLuint firstID;
186 if (fPreallocatedPathCount >= range) {
187 firstID = fFirstPreallocatedPathID;
188 fPreallocatedPathCount -= range;
189 fFirstPreallocatedPathID += range;
190 return firstID;
191 }
192 // Allocate range + the amount to fill up preallocation amount. If succeed, either join with
193 // the existing preallocation range or delete the existing and use the new (potentially partial)
194 // preallocation range.
195 GrGLsizei allocAmount = range + (kPathIDPreallocationAmount - fPreallocatedPathCount);
196 if (allocAmount >= range) {
197 GL_CALL_RET(firstID, GenPaths(allocAmount));
198
199 if (firstID != 0) {
200 if (fPreallocatedPathCount > 0 &&
201 firstID == fFirstPreallocatedPathID + fPreallocatedPathCount) {
202 firstID = fFirstPreallocatedPathID;
203 fPreallocatedPathCount += allocAmount - range;
204 fFirstPreallocatedPathID += range;
205 return firstID;
206 }
207
208 if (allocAmount > range) {
209 if (fPreallocatedPathCount > 0) {
210 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
211 }
212 fFirstPreallocatedPathID = firstID + range;
213 fPreallocatedPathCount = allocAmount - range;
214 }
215 // Special case: if allocAmount == range, we have full preallocated range.
216 return firstID;
217 }
218 }
219 // Failed to allocate with preallocation. Remove existing preallocation and try to allocate just
220 // the range.
221 if (fPreallocatedPathCount > 0) {
222 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
223 fPreallocatedPathCount = 0;
cdaltonc7103a12014-08-11 14:05:05 -0700224 }
225
kkinnunen702501d2016-01-13 23:36:45 -0800226 GL_CALL_RET(firstID, GenPaths(range));
227 if (firstID == 0) {
228 SkDebugf("Warning: Failed to allocate path\n");
cdaltonc7103a12014-08-11 14:05:05 -0700229 }
kkinnunen702501d2016-01-13 23:36:45 -0800230 return firstID;
cdaltonc7103a12014-08-11 14:05:05 -0700231}
232
kkinnunen5b653572014-08-20 04:13:27 -0700233void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
kkinnunen702501d2016-01-13 23:36:45 -0800234 GL_CALL(DeletePaths(path, range));
cdaltonc7103a12014-08-11 14:05:05 -0700235}
236
joshualitt92e496f2014-10-31 13:56:50 -0700237void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
Chris Dalton71713f62019-04-18 12:41:03 -0600238 SkASSERT(!stencilSettings.isTwoSided());
joshualitt92e496f2014-10-31 13:56:50 -0700239 if (fHWPathStencilSettings != stencilSettings) {
kkinnunen1517f932016-01-25 06:07:26 -0800240 SkASSERT(stencilSettings.isValid());
kkinnunen5b653572014-08-20 04:13:27 -0700241 // Just the func, ref, and mask is set here. The op and write mask are params to the call
242 // that draws the path to the SB (glStencilFillPath)
Chris Dalton67d43fe2019-11-05 23:01:21 -0700243 uint16_t ref = stencilSettings.singleSidedFace().fRef;
244 GrStencilTest test = stencilSettings.singleSidedFace().fTest;
245 uint16_t testMask = stencilSettings.singleSidedFace().fTestMask;
kkinnunen5b653572014-08-20 04:13:27 -0700246
kkinnunen1517f932016-01-25 06:07:26 -0800247 if (!fHWPathStencilSettings.isValid() ||
Chris Dalton67d43fe2019-11-05 23:01:21 -0700248 ref != fHWPathStencilSettings.singleSidedFace().fRef ||
249 test != fHWPathStencilSettings.singleSidedFace().fTest ||
250 testMask != fHWPathStencilSettings.singleSidedFace().fTestMask) {
cdalton93a379b2016-05-11 13:58:08 -0700251 GL_CALL(PathStencilFunc(GrToGLStencilFunc(test), ref, testMask));
kkinnunen1517f932016-01-25 06:07:26 -0800252 }
joshualitt92e496f2014-10-31 13:56:50 -0700253 fHWPathStencilSettings = stencilSettings;
kkinnunen5b653572014-08-20 04:13:27 -0700254 }
cdaltonc7103a12014-08-11 14:05:05 -0700255}
256
kkinnunencabe20c2015-06-01 01:37:26 -0700257inline GrGLGpu* GrGLPathRendering::gpu() {
258 return static_cast<GrGLGpu*>(fGpu);
259}