blob: eb9f5a86f751a0b483c684478994eb3bfe372d3a [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/GrGLNameAllocator.h"
10#include "gl/GrGLUtil.h"
jvanverth39edf762014-12-22 11:44:19 -080011#include "gl/GrGLGpu.h"
cdaltonc7103a12014-08-11 14:05:05 -070012
kkinnunenccdaa042014-08-20 01:36:23 -070013#include "GrGLPath.h"
14#include "GrGLPathRange.h"
15#include "GrGLPathRendering.h"
16
cdalton855d83f2014-09-18 13:51:53 -070017#include "SkStream.h"
18#include "SkTypeface.h"
19
kkinnunencabe20c2015-06-01 01:37:26 -070020#define GL_CALL(X) GR_GL_CALL(this->gpu()->glInterface(), X)
21#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(this->gpu()->glInterface(), RET, X)
kkinnunenccdaa042014-08-20 01:36:23 -070022
23
cdalton55b24af2014-11-25 11:00:56 -080024static const GrGLenum gIndexType2GLType[] = {
25 GR_GL_UNSIGNED_BYTE,
26 GR_GL_UNSIGNED_SHORT,
27 GR_GL_UNSIGNED_INT
28};
29
30GR_STATIC_ASSERT(0 == GrPathRange::kU8_PathIndexType);
31GR_STATIC_ASSERT(1 == GrPathRange::kU16_PathIndexType);
32GR_STATIC_ASSERT(2 == GrPathRange::kU32_PathIndexType);
33GR_STATIC_ASSERT(GrPathRange::kU32_PathIndexType == GrPathRange::kLast_PathIndexType);
34
kkinnunenccdaa042014-08-20 01:36:23 -070035static const GrGLenum gXformType2GLType[] = {
36 GR_GL_NONE,
37 GR_GL_TRANSLATE_X,
38 GR_GL_TRANSLATE_Y,
39 GR_GL_TRANSLATE_2D,
40 GR_GL_TRANSPOSE_AFFINE_2D
41};
42
43GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
44GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
45GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
46GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
47GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
48GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
49
50static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
51 switch (op) {
52 default:
53 SkFAIL("Unexpected path fill.");
54 /* fallthrough */;
55 case kIncClamp_StencilOp:
56 return GR_GL_COUNT_UP;
57 case kInvert_StencilOp:
58 return GR_GL_INVERT;
59 }
60}
cdaltonc7103a12014-08-11 14:05:05 -070061
bsalomon861e1032014-12-16 07:33:49 -080062GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
kkinnunencabe20c2015-06-01 01:37:26 -070063 : GrPathRendering(gpu) {
jvanverth439f23e2015-06-30 09:40:38 -070064 const GrGLInterface* glInterface = gpu->glInterface();
65 fCaps.stencilThenCoverSupport =
66 NULL != glInterface->fFunctions.fStencilThenCoverFillPath &&
67 NULL != glInterface->fFunctions.fStencilThenCoverStrokePath &&
68 NULL != glInterface->fFunctions.fStencilThenCoverFillPathInstanced &&
69 NULL != glInterface->fFunctions.fStencilThenCoverStrokePathInstanced;
70 fCaps.fragmentInputGenSupport =
71 NULL != glInterface->fFunctions.fProgramPathFragmentInputGen;
72
73 SkASSERT(fCaps.fragmentInputGenSupport);
cdaltonc7103a12014-08-11 14:05:05 -070074}
75
76GrGLPathRendering::~GrGLPathRendering() {
77}
78
79void GrGLPathRendering::abandonGpuResources() {
80 fPathNameAllocator.reset(NULL);
81}
82
kkinnunenccdaa042014-08-20 01:36:23 -070083void GrGLPathRendering::resetContext() {
84 fHWProjectionMatrixState.invalidate();
85 // we don't use the model view matrix.
jvanverth50530632015-04-27 10:36:27 -070086 GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
kkinnunenccdaa042014-08-20 01:36:23 -070087
jvanverth439f23e2015-06-30 09:40:38 -070088 SkASSERT(fCaps.fragmentInputGenSupport);
kkinnunenccdaa042014-08-20 01:36:23 -070089 fHWPathStencilSettings.invalidate();
90}
91
kkinnunen50b58e62015-05-18 23:02:07 -070092GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStrokeInfo& stroke) {
kkinnunencabe20c2015-06-01 01:37:26 -070093 return SkNEW_ARGS(GrGLPath, (this->gpu(), inPath, stroke));
kkinnunenccdaa042014-08-20 01:36:23 -070094}
95
cdalton855d83f2014-09-18 13:51:53 -070096GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
kkinnunen50b58e62015-05-18 23:02:07 -070097 const GrStrokeInfo& stroke) {
kkinnunencabe20c2015-06-01 01:37:26 -070098 return SkNEW_ARGS(GrGLPathRange, (this->gpu(), pathGenerator, stroke));
cdalton855d83f2014-09-18 13:51:53 -070099}
100
kkinnunencabe20c2015-06-01 01:37:26 -0700101void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
102 GrGLGpu* gpu = this->gpu();
103 SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
104 gpu->flushColorWrite(false);
105 gpu->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace);
106
107 GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fRenderTarget);
108 SkISize size = SkISize::Make(rt->width(), rt->height());
109 this->setProjectionMatrix(*args.fViewMatrix, size, rt->origin());
110 gpu->flushScissor(*args.fScissor, rt->getViewport(), rt->origin());
111 gpu->flushHWAAState(rt, args.fUseHWAA);
112 gpu->flushRenderTarget(rt, NULL);
113
kkinnunen50b58e62015-05-18 23:02:07 -0700114 const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
kkinnunen5b653572014-08-20 04:13:27 -0700115
kkinnunencabe20c2015-06-01 01:37:26 -0700116 this->flushPathStencilSettings(*args.fStencil);
kkinnunen5b653572014-08-20 04:13:27 -0700117 SkASSERT(!fHWPathStencilSettings.isTwoSided());
118
kkinnunen50b58e62015-05-18 23:02:07 -0700119 GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
120 fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
joshualitt92e496f2014-10-31 13:56:50 -0700121 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
122
kkinnunen50b58e62015-05-18 23:02:07 -0700123 if (glPath->shouldFill()) {
124 GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
joshualitt92e496f2014-10-31 13:56:50 -0700125 }
kkinnunen50b58e62015-05-18 23:02:07 -0700126 if (glPath->shouldStroke()) {
127 GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
joshualitt92e496f2014-10-31 13:56:50 -0700128 }
129}
130
kkinnunencabe20c2015-06-01 01:37:26 -0700131void GrGLPathRendering::onDrawPath(const DrawPathArgs& args, const GrPath* path) {
132 if (!this->gpu()->flushGLState(args)) {
133 return;
134 }
kkinnunen50b58e62015-05-18 23:02:07 -0700135 const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
joshualitt92e496f2014-10-31 13:56:50 -0700136
kkinnunencabe20c2015-06-01 01:37:26 -0700137 this->flushPathStencilSettings(*args.fStencil);
joshualitt92e496f2014-10-31 13:56:50 -0700138 SkASSERT(!fHWPathStencilSettings.isTwoSided());
139
kkinnunen50b58e62015-05-18 23:02:07 -0700140 GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
141 fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
kkinnunen5b653572014-08-20 04:13:27 -0700142 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
143
kkinnunen50b58e62015-05-18 23:02:07 -0700144 if (glPath->shouldStroke()) {
145 if (glPath->shouldFill()) {
146 GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
kkinnunen5b653572014-08-20 04:13:27 -0700147 }
jvanverth439f23e2015-06-30 09:40:38 -0700148 this->stencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask, GR_GL_BOUNDING_BOX);
joshualitt92e496f2014-10-31 13:56:50 -0700149 } else {
jvanverth439f23e2015-06-30 09:40:38 -0700150 this->stencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask, 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 }
jvanverth439f23e2015-06-30 09:40:38 -0700180 this->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,
jvanverth439f23e2015-06-30 09:40:38 -0700183 gXformType2GLType[transformType], transformValues);
joshualitt92e496f2014-10-31 13:56:50 -0700184 } else {
jvanverth439f23e2015-06-30 09:40:38 -0700185 this->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,
jvanverth439f23e2015-06-30 09:40:38 -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) {
jvanverth439f23e2015-06-30 09:40:38 -0700195 SkASSERT(caps().fragmentInputGenSupport);
kkinnunen5b653572014-08-20 04:13:27 -0700196 GrGLfloat coefficients[3 * 3];
197 SkASSERT(components >= 1 && components <= 3);
kkinnunenccdaa042014-08-20 01:36:23 -0700198
kkinnunen5b653572014-08-20 04:13:27 -0700199 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
200 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
201 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
kkinnunenccdaa042014-08-20 01:36:23 -0700202
kkinnunen5b653572014-08-20 04:13:27 -0700203 if (components >= 2) {
204 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
205 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
206 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
kkinnunenccdaa042014-08-20 01:36:23 -0700207 }
kkinnunenccdaa042014-08-20 01:36:23 -0700208
kkinnunen5b653572014-08-20 04:13:27 -0700209 if (components >= 3) {
210 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
211 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
212 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
kkinnunenccdaa042014-08-20 01:36:23 -0700213 }
kkinnunenccdaa042014-08-20 01:36:23 -0700214
kkinnunen5b653572014-08-20 04:13:27 -0700215 GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
kkinnunenccdaa042014-08-20 01:36:23 -0700216}
217
218void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
joshualittee2af952014-12-30 09:04:15 -0800219 const SkISize& renderTargetSize,
220 GrSurfaceOrigin renderTargetOrigin) {
kkinnunenccdaa042014-08-20 01:36:23 -0700221
kkinnunencabe20c2015-06-01 01:37:26 -0700222 SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport());
kkinnunenccdaa042014-08-20 01:36:23 -0700223
224 if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
225 renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
226 matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
227 return;
228 }
229
230 fHWProjectionMatrixState.fViewMatrix = matrix;
231 fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
232 fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
233
234 GrGLfloat glMatrix[4 * 4];
235 fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
jvanverth50530632015-04-27 10:36:27 -0700236 GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
kkinnunenccdaa042014-08-20 01:36:23 -0700237}
238
cdaltonc7103a12014-08-11 14:05:05 -0700239GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
240 if (range > 1) {
241 GrGLuint name;
242 GL_CALL_RET(name, GenPaths(range));
243 return name;
244 }
245
246 if (NULL == fPathNameAllocator.get()) {
247 static const int range = 65536;
248 GrGLuint firstName;
249 GL_CALL_RET(firstName, GenPaths(range));
250 fPathNameAllocator.reset(SkNEW_ARGS(GrGLNameAllocator, (firstName, firstName + range)));
251 }
252
253 // When allocating names one at a time, pull from a client-side pool of
254 // available names in order to save a round trip to the GL server.
255 GrGLuint name = fPathNameAllocator->allocateName();
256
257 if (0 == name) {
258 // Our reserved path names are all in use. Fall back on GenPaths.
259 GL_CALL_RET(name, GenPaths(1));
260 }
261
262 return name;
263}
264
kkinnunen5b653572014-08-20 04:13:27 -0700265void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
cdaltonc7103a12014-08-11 14:05:05 -0700266 if (range > 1) {
267 // It is not supported to delete names in ranges that were allocated
268 // individually using GrGLPathNameAllocator.
269 SkASSERT(NULL == fPathNameAllocator.get() ||
270 path + range <= fPathNameAllocator->firstName() ||
271 path >= fPathNameAllocator->endName());
272 GL_CALL(DeletePaths(path, range));
273 return;
274 }
275
276 if (NULL == fPathNameAllocator.get() ||
277 path < fPathNameAllocator->firstName() ||
278 path >= fPathNameAllocator->endName()) {
279 // If we aren't inside fPathNameAllocator's range then this name was
280 // generated by the GenPaths fallback (or else was never allocated).
281 GL_CALL(DeletePaths(path, 1));
282 return;
283 }
284
285 // Make the path empty to save memory, but don't free the name in the driver.
286 GL_CALL(PathCommands(path, 0, NULL, 0, GR_GL_FLOAT, NULL));
287 fPathNameAllocator->free(path);
288}
289
joshualitt92e496f2014-10-31 13:56:50 -0700290void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
291 if (fHWPathStencilSettings != stencilSettings) {
kkinnunen5b653572014-08-20 04:13:27 -0700292 // Just the func, ref, and mask is set here. The op and write mask are params to the call
293 // that draws the path to the SB (glStencilFillPath)
294 GrGLenum func =
joshualitt92e496f2014-10-31 13:56:50 -0700295 GrToGLStencilFunc(stencilSettings.func(GrStencilSettings::kFront_Face));
296 GL_CALL(PathStencilFunc(func, stencilSettings.funcRef(GrStencilSettings::kFront_Face),
297 stencilSettings.funcMask(GrStencilSettings::kFront_Face)));
kkinnunen5b653572014-08-20 04:13:27 -0700298
joshualitt92e496f2014-10-31 13:56:50 -0700299 fHWPathStencilSettings = stencilSettings;
kkinnunen5b653572014-08-20 04:13:27 -0700300 }
cdaltonc7103a12014-08-11 14:05:05 -0700301}
302
jvanverth439f23e2015-06-30 09:40:38 -0700303inline void GrGLPathRendering::stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode,
304 GrGLuint mask, GrGLenum coverMode) {
305 if (caps().stencilThenCoverSupport) {
306 GL_CALL(StencilThenCoverFillPath(path, fillMode, mask, coverMode));
307 return;
308 }
309 GL_CALL(StencilFillPath(path, fillMode, mask));
310 GL_CALL(CoverFillPath(path, coverMode));
311}
312
313inline void GrGLPathRendering::stencilThenCoverStrokePath(GrGLuint path, GrGLint reference,
314 GrGLuint mask, GrGLenum coverMode) {
315 if (caps().stencilThenCoverSupport) {
316 GL_CALL(StencilThenCoverStrokePath(path, reference, mask, coverMode));
317 return;
318 }
319 GL_CALL(StencilStrokePath(path, reference, mask));
320 GL_CALL(CoverStrokePath(path, coverMode));
321}
322
323inline void GrGLPathRendering::stencilThenCoverFillPathInstanced(
324 GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
325 GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode,
326 GrGLenum transformType, const GrGLfloat *transformValues) {
327 if (caps().stencilThenCoverSupport) {
328 GL_CALL(StencilThenCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, fillMode,
329 mask, coverMode, transformType, transformValues));
330 return;
331 }
332 GL_CALL(StencilFillPathInstanced(numPaths, pathNameType, paths, pathBase,
333 fillMode, mask, transformType, transformValues));
334 GL_CALL(CoverFillPathInstanced(numPaths, pathNameType, paths, pathBase,
335 coverMode, transformType, transformValues));
336}
337
338inline void GrGLPathRendering::stencilThenCoverStrokePathInstanced(
339 GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths,
340 GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode,
341 GrGLenum transformType, const GrGLfloat *transformValues) {
342 if (caps().stencilThenCoverSupport) {
343 GL_CALL(StencilThenCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
344 reference, mask, coverMode, transformType,
345 transformValues));
346 return;
347 }
348
349 GL_CALL(StencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
350 reference, mask, transformType, transformValues));
351 GL_CALL(CoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
352 coverMode, transformType, transformValues));
353}
354
kkinnunencabe20c2015-06-01 01:37:26 -0700355inline GrGLGpu* GrGLPathRendering::gpu() {
356 return static_cast<GrGLGpu*>(fGpu);
357}