blob: 7fb85352fb5b00aa2db7283745666ba44f3ccd8f [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
52static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
53 switch (op) {
54 default:
55 SkFAIL("Unexpected path fill.");
56 /* fallthrough */;
57 case kIncClamp_StencilOp:
58 return GR_GL_COUNT_UP;
59 case kInvert_StencilOp:
60 return GR_GL_INVERT;
61 }
62}
cdaltonc7103a12014-08-11 14:05:05 -070063
bsalomon861e1032014-12-16 07:33:49 -080064GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
kkinnunen702501d2016-01-13 23:36:45 -080065 : GrPathRendering(gpu)
66 , fPreallocatedPathCount(0) {
kkinnunen6bb6d402015-07-14 10:59:23 -070067 const GrGLInterface* glInterface = gpu->glInterface();
68 fCaps.bindFragmentInputSupport =
halcanary96fcdcc2015-08-27 07:41:13 -070069 nullptr != glInterface->fFunctions.fBindFragmentInputLocation;
cdaltonc7103a12014-08-11 14:05:05 -070070}
71
72GrGLPathRendering::~GrGLPathRendering() {
kkinnunen702501d2016-01-13 23:36:45 -080073 if (fPreallocatedPathCount > 0) {
74 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
75 }
cdaltonc7103a12014-08-11 14:05:05 -070076}
77
78void GrGLPathRendering::abandonGpuResources() {
kkinnunen702501d2016-01-13 23:36:45 -080079 fPreallocatedPathCount = 0;
cdaltonc7103a12014-08-11 14:05:05 -070080}
81
kkinnunenccdaa042014-08-20 01:36:23 -070082void GrGLPathRendering::resetContext() {
83 fHWProjectionMatrixState.invalidate();
84 // we don't use the model view matrix.
jvanverth50530632015-04-27 10:36:27 -070085 GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
kkinnunenccdaa042014-08-20 01:36:23 -070086
kkinnunenccdaa042014-08-20 01:36:23 -070087 fHWPathStencilSettings.invalidate();
88}
89
kkinnunen50b58e62015-05-18 23:02:07 -070090GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStrokeInfo& stroke) {
halcanary385fe4d2015-08-26 13:07:48 -070091 return new GrGLPath(this->gpu(), inPath, stroke);
kkinnunenccdaa042014-08-20 01:36:23 -070092}
93
cdalton855d83f2014-09-18 13:51:53 -070094GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
kkinnunen50b58e62015-05-18 23:02:07 -070095 const GrStrokeInfo& stroke) {
halcanary385fe4d2015-08-26 13:07:48 -070096 return new GrGLPathRange(this->gpu(), pathGenerator, stroke);
cdalton855d83f2014-09-18 13:51:53 -070097}
98
kkinnunencabe20c2015-06-01 01:37:26 -070099void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
100 GrGLGpu* gpu = this->gpu();
101 SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
102 gpu->flushColorWrite(false);
103 gpu->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace);
104
105 GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fRenderTarget);
106 SkISize size = SkISize::Make(rt->width(), rt->height());
107 this->setProjectionMatrix(*args.fViewMatrix, size, rt->origin());
108 gpu->flushScissor(*args.fScissor, rt->getViewport(), rt->origin());
cdalton7e806f32015-11-11 15:16:07 -0800109 gpu->flushHWAAState(rt, args.fUseHWAA);
halcanary96fcdcc2015-08-27 07:41:13 -0700110 gpu->flushRenderTarget(rt, nullptr);
kkinnunencabe20c2015-06-01 01:37:26 -0700111
kkinnunen50b58e62015-05-18 23:02:07 -0700112 const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
kkinnunen5b653572014-08-20 04:13:27 -0700113
kkinnunencabe20c2015-06-01 01:37:26 -0700114 this->flushPathStencilSettings(*args.fStencil);
kkinnunen5b653572014-08-20 04:13:27 -0700115 SkASSERT(!fHWPathStencilSettings.isTwoSided());
116
kkinnunen50b58e62015-05-18 23:02:07 -0700117 GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
118 fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
joshualitt92e496f2014-10-31 13:56:50 -0700119 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
120
kkinnunen50b58e62015-05-18 23:02:07 -0700121 if (glPath->shouldFill()) {
122 GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
joshualitt92e496f2014-10-31 13:56:50 -0700123 }
kkinnunen50b58e62015-05-18 23:02:07 -0700124 if (glPath->shouldStroke()) {
125 GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
joshualitt92e496f2014-10-31 13:56:50 -0700126 }
127}
128
kkinnunencabe20c2015-06-01 01:37:26 -0700129void GrGLPathRendering::onDrawPath(const DrawPathArgs& args, const GrPath* path) {
130 if (!this->gpu()->flushGLState(args)) {
131 return;
132 }
kkinnunen50b58e62015-05-18 23:02:07 -0700133 const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
joshualitt92e496f2014-10-31 13:56:50 -0700134
kkinnunencabe20c2015-06-01 01:37:26 -0700135 this->flushPathStencilSettings(*args.fStencil);
joshualitt92e496f2014-10-31 13:56:50 -0700136 SkASSERT(!fHWPathStencilSettings.isTwoSided());
137
kkinnunen50b58e62015-05-18 23:02:07 -0700138 GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
139 fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
kkinnunen5b653572014-08-20 04:13:27 -0700140 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
141
kkinnunen50b58e62015-05-18 23:02:07 -0700142 if (glPath->shouldStroke()) {
143 if (glPath->shouldFill()) {
144 GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
kkinnunen5b653572014-08-20 04:13:27 -0700145 }
kkinnunencfe62e32015-07-01 02:58:50 -0700146 GL_CALL(StencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask,
147 GR_GL_BOUNDING_BOX));
joshualitt92e496f2014-10-31 13:56:50 -0700148 } else {
kkinnunencfe62e32015-07-01 02:58:50 -0700149 GL_CALL(StencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask,
150 GR_GL_BOUNDING_BOX));
kkinnunen5b653572014-08-20 04:13:27 -0700151 }
152}
153
kkinnunencabe20c2015-06-01 01:37:26 -0700154void GrGLPathRendering::onDrawPaths(const DrawPathArgs& args, const GrPathRange* pathRange,
155 const void* indices, PathIndexType indexType,
156 const float transformValues[], PathTransformType transformType,
157 int count) {
158 if (!this->gpu()->flushGLState(args)) {
159 return;
160 }
161 this->flushPathStencilSettings(*args.fStencil);
162 SkASSERT(!fHWPathStencilSettings.isTwoSided());
163
kkinnunen5b653572014-08-20 04:13:27 -0700164
kkinnunen50b58e62015-05-18 23:02:07 -0700165 const GrGLPathRange* glPathRange = static_cast<const GrGLPathRange*>(pathRange);
kkinnunen5b653572014-08-20 04:13:27 -0700166
kkinnunen5b653572014-08-20 04:13:27 -0700167 GrGLenum fillMode =
168 gr_stencil_op_to_gl_path_rendering_fill_mode(
169 fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
170 GrGLint writeMask =
171 fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
172
kkinnunen50b58e62015-05-18 23:02:07 -0700173 if (glPathRange->shouldStroke()) {
174 if (glPathRange->shouldFill()) {
kkinnunen5b653572014-08-20 04:13:27 -0700175 GL_CALL(StencilFillPathInstanced(
kkinnunen50b58e62015-05-18 23:02:07 -0700176 count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
177 fillMode, writeMask, gXformType2GLType[transformType],
178 transformValues));
kkinnunen5b653572014-08-20 04:13:27 -0700179 }
kkinnunencfe62e32015-07-01 02:58:50 -0700180 GL_CALL(StencilThenCoverStrokePathInstanced(
kkinnunen50b58e62015-05-18 23:02:07 -0700181 count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
cdalton55b24af2014-11-25 11:00:56 -0800182 0xffff, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
kkinnunencfe62e32015-07-01 02:58:50 -0700183 gXformType2GLType[transformType], transformValues));
joshualitt92e496f2014-10-31 13:56:50 -0700184 } else {
kkinnunencfe62e32015-07-01 02:58:50 -0700185 GL_CALL(StencilThenCoverFillPathInstanced(
kkinnunen50b58e62015-05-18 23:02:07 -0700186 count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
cdalton55b24af2014-11-25 11:00:56 -0800187 fillMode, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
kkinnunencfe62e32015-07-01 02:58:50 -0700188 gXformType2GLType[transformType], transformValues));
kkinnunen5b653572014-08-20 04:13:27 -0700189 }
190}
191
kkinnunen5b653572014-08-20 04:13:27 -0700192void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
193 GrGLenum genMode, GrGLint components,
194 const SkMatrix& matrix) {
egdaniel018fb622015-10-28 07:26:40 -0700195 float coefficients[3 * 3];
kkinnunen5b653572014-08-20 04:13:27 -0700196 SkASSERT(components >= 1 && components <= 3);
kkinnunenccdaa042014-08-20 01:36:23 -0700197
kkinnunen5b653572014-08-20 04:13:27 -0700198 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
199 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
200 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
kkinnunenccdaa042014-08-20 01:36:23 -0700201
kkinnunen5b653572014-08-20 04:13:27 -0700202 if (components >= 2) {
203 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
204 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
205 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
kkinnunenccdaa042014-08-20 01:36:23 -0700206 }
kkinnunenccdaa042014-08-20 01:36:23 -0700207
kkinnunen5b653572014-08-20 04:13:27 -0700208 if (components >= 3) {
209 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
210 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
211 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
kkinnunenccdaa042014-08-20 01:36:23 -0700212 }
kkinnunenccdaa042014-08-20 01:36:23 -0700213
kkinnunen5b653572014-08-20 04:13:27 -0700214 GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700215}
216
217void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
joshualittee2af952014-12-30 09:04:15 -0800218 const SkISize& renderTargetSize,
219 GrSurfaceOrigin renderTargetOrigin) {
kkinnunenccdaa042014-08-20 01:36:23 -0700220
kkinnunencabe20c2015-06-01 01:37:26 -0700221 SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport());
kkinnunenccdaa042014-08-20 01:36:23 -0700222
223 if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
224 renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
225 matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
226 return;
227 }
228
229 fHWProjectionMatrixState.fViewMatrix = matrix;
230 fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
231 fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
232
egdaniel018fb622015-10-28 07:26:40 -0700233 float glMatrix[4 * 4];
kkinnunenccdaa042014-08-20 01:36:23 -0700234 fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
jvanverth50530632015-04-27 10:36:27 -0700235 GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
kkinnunenccdaa042014-08-20 01:36:23 -0700236}
237
cdaltonc7103a12014-08-11 14:05:05 -0700238GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
kkinnunen702501d2016-01-13 23:36:45 -0800239 SkASSERT(range > 0);
240 GrGLuint firstID;
241 if (fPreallocatedPathCount >= range) {
242 firstID = fFirstPreallocatedPathID;
243 fPreallocatedPathCount -= range;
244 fFirstPreallocatedPathID += range;
245 return firstID;
246 }
247 // Allocate range + the amount to fill up preallocation amount. If succeed, either join with
248 // the existing preallocation range or delete the existing and use the new (potentially partial)
249 // preallocation range.
250 GrGLsizei allocAmount = range + (kPathIDPreallocationAmount - fPreallocatedPathCount);
251 if (allocAmount >= range) {
252 GL_CALL_RET(firstID, GenPaths(allocAmount));
253
254 if (firstID != 0) {
255 if (fPreallocatedPathCount > 0 &&
256 firstID == fFirstPreallocatedPathID + fPreallocatedPathCount) {
257 firstID = fFirstPreallocatedPathID;
258 fPreallocatedPathCount += allocAmount - range;
259 fFirstPreallocatedPathID += range;
260 return firstID;
261 }
262
263 if (allocAmount > range) {
264 if (fPreallocatedPathCount > 0) {
265 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
266 }
267 fFirstPreallocatedPathID = firstID + range;
268 fPreallocatedPathCount = allocAmount - range;
269 }
270 // Special case: if allocAmount == range, we have full preallocated range.
271 return firstID;
272 }
273 }
274 // Failed to allocate with preallocation. Remove existing preallocation and try to allocate just
275 // the range.
276 if (fPreallocatedPathCount > 0) {
277 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
278 fPreallocatedPathCount = 0;
cdaltonc7103a12014-08-11 14:05:05 -0700279 }
280
kkinnunen702501d2016-01-13 23:36:45 -0800281 GL_CALL_RET(firstID, GenPaths(range));
282 if (firstID == 0) {
283 SkDebugf("Warning: Failed to allocate path\n");
cdaltonc7103a12014-08-11 14:05:05 -0700284 }
kkinnunen702501d2016-01-13 23:36:45 -0800285 return firstID;
cdaltonc7103a12014-08-11 14:05:05 -0700286}
287
kkinnunen5b653572014-08-20 04:13:27 -0700288void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
kkinnunen702501d2016-01-13 23:36:45 -0800289 GL_CALL(DeletePaths(path, range));
cdaltonc7103a12014-08-11 14:05:05 -0700290}
291
joshualitt92e496f2014-10-31 13:56:50 -0700292void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
293 if (fHWPathStencilSettings != stencilSettings) {
kkinnunen1517f932016-01-25 06:07:26 -0800294 SkASSERT(stencilSettings.isValid());
kkinnunen5b653572014-08-20 04:13:27 -0700295 // Just the func, ref, and mask is set here. The op and write mask are params to the call
296 // that draws the path to the SB (glStencilFillPath)
kkinnunen1517f932016-01-25 06:07:26 -0800297 const GrStencilSettings::Face kFront_Face = GrStencilSettings::kFront_Face;
298 GrStencilFunc func = stencilSettings.func(kFront_Face);
299 uint16_t funcRef = stencilSettings.funcRef(kFront_Face);
300 uint16_t funcMask = stencilSettings.funcMask(kFront_Face);
kkinnunen5b653572014-08-20 04:13:27 -0700301
kkinnunen1517f932016-01-25 06:07:26 -0800302 if (!fHWPathStencilSettings.isValid() ||
303 func != fHWPathStencilSettings.func(kFront_Face) ||
304 funcRef != fHWPathStencilSettings.funcRef(kFront_Face) ||
305 funcMask != fHWPathStencilSettings.funcMask(kFront_Face)) {
306 GL_CALL(PathStencilFunc(GrToGLStencilFunc(func), funcRef, funcMask));
307 }
joshualitt92e496f2014-10-31 13:56:50 -0700308 fHWPathStencilSettings = stencilSettings;
kkinnunen5b653572014-08-20 04:13:27 -0700309 }
cdaltonc7103a12014-08-11 14:05:05 -0700310}
311
kkinnunencabe20c2015-06-01 01:37:26 -0700312inline GrGLGpu* GrGLPathRendering::gpu() {
313 return static_cast<GrGLGpu*>(fGpu);
314}