1 /* 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" 9 #include "gl/GrGLUtil.h" 10 #include "gl/GrGLGpu.h" 11 12 #include "GrGLPath.h" 13 #include "GrGLPathRange.h" 14 #include "GrGLPathRendering.h" 15 16 #include "SkStream.h" 17 #include "SkTypeface.h" 18 19 #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) 21 22 // 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. 24 static const GrGLsizei kPathIDPreallocationAmount = 65536; 25 26 static const GrGLenum gIndexType2GLType[] = { 27 GR_GL_UNSIGNED_BYTE, 28 GR_GL_UNSIGNED_SHORT, 29 GR_GL_UNSIGNED_INT 30 }; 31 32 GR_STATIC_ASSERT(0 == GrPathRange::kU8_PathIndexType); 33 GR_STATIC_ASSERT(1 == GrPathRange::kU16_PathIndexType); 34 GR_STATIC_ASSERT(2 == GrPathRange::kU32_PathIndexType); 35 GR_STATIC_ASSERT(GrPathRange::kU32_PathIndexType == GrPathRange::kLast_PathIndexType); 36 37 static 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 45 GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType); 46 GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType); 47 GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType); 48 GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType); 49 GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType); 50 GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType); 51 52 #ifdef SK_DEBUG 53 static const GrGLenum gXformType2ComponentCount[] = { 54 0, 55 1, 56 1, 57 2, 58 6 59 }; 60 61 static 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 68 static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) { 69 switch (op) { 70 default: 71 SK_ABORT("Unexpected path fill."); 72 /* fallthrough */; 73 case GrStencilOp::kIncWrap: 74 return GR_GL_COUNT_UP; 75 case GrStencilOp::kInvert: 76 return GR_GL_INVERT; 77 } 78 } 79 80 GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu) 81 : GrPathRendering(gpu) 82 , fPreallocatedPathCount(0) { 83 const GrGLInterface* glInterface = gpu->glInterface(); 84 fCaps.bindFragmentInputSupport = (bool)glInterface->fFunctions.fBindFragmentInputLocation; 85 } 86 87 GrGLPathRendering::~GrGLPathRendering() { 88 if (fPreallocatedPathCount > 0) { 89 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount); 90 } 91 } 92 93 void GrGLPathRendering::disconnect(GrGpu::DisconnectType type) { 94 if (GrGpu::DisconnectType::kCleanup == type) { 95 this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount); 96 }; 97 fPreallocatedPathCount = 0; 98 } 99 100 void GrGLPathRendering::resetContext() { 101 fHWProjectionMatrixState.invalidate(); 102 // we don't use the model view matrix. 103 GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW)); 104 105 fHWPathStencilSettings.invalidate(); 106 } 107 108 sk_sp<GrPath> GrGLPathRendering::createPath(const SkPath& inPath, const GrStyle& style) { 109 return sk_make_sp<GrGLPath>(this->gpu(), inPath, style); 110 } 111 112 sk_sp<GrPathRange> GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator, 113 const GrStyle& style) { 114 return sk_make_sp<GrGLPathRange>(this->gpu(), pathGenerator, style); 115 } 116 117 void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) { 118 GrGLGpu* gpu = this->gpu(); 119 SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport()); 120 gpu->flushColorWrite(false); 121 122 GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fProxy->priv().peekRenderTarget()); 123 SkISize size = SkISize::Make(rt->width(), rt->height()); 124 this->setProjectionMatrix(*args.fViewMatrix, size, args.fProxy->origin()); 125 gpu->flushScissor(*args.fScissor, rt->getViewport(), args.fProxy->origin()); 126 gpu->flushHWAAState(rt, args.fUseHWAA, true); 127 gpu->flushRenderTarget(rt, nullptr); 128 129 const GrGLPath* glPath = static_cast<const GrGLPath*>(path); 130 131 this->flushPathStencilSettings(*args.fStencil); 132 SkASSERT(!fHWPathStencilSettings.isTwoSided()); 133 134 GrGLenum fillMode = 135 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp); 136 GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask; 137 138 if (glPath->shouldFill()) { 139 GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask)); 140 } 141 if (glPath->shouldStroke()) { 142 GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask)); 143 } 144 } 145 146 void GrGLPathRendering::onDrawPath(const GrPipeline& pipeline, 147 const GrPrimitiveProcessor& primProc, 148 const GrStencilSettings& stencilPassSettings, 149 const GrPath* path) { 150 if (!this->gpu()->flushGLState(pipeline, primProc, false)) { 151 return; 152 } 153 const GrGLPath* glPath = static_cast<const GrGLPath*>(path); 154 155 this->flushPathStencilSettings(stencilPassSettings); 156 SkASSERT(!fHWPathStencilSettings.isTwoSided()); 157 158 GrGLenum fillMode = 159 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp); 160 GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask; 161 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 174 void GrGLPathRendering::onDrawPaths(const GrPipeline& pipeline, 175 const GrPrimitiveProcessor& primProc, 176 const GrStencilSettings& stencilPassSettings, 177 const GrPathRange* pathRange, const void* indices, 178 PathIndexType indexType, const float transformValues[], 179 PathTransformType transformType, int count) { 180 SkDEBUGCODE(verify_floats(transformValues, gXformType2ComponentCount[transformType] * count)); 181 182 if (!this->gpu()->flushGLState(pipeline, primProc, false)) { 183 return; 184 } 185 this->flushPathStencilSettings(stencilPassSettings); 186 SkASSERT(!fHWPathStencilSettings.isTwoSided()); 187 188 189 const GrGLPathRange* glPathRange = static_cast<const GrGLPathRange*>(pathRange); 190 191 GrGLenum fillMode = 192 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.front().fPassOp); 193 GrGLint writeMask = fHWPathStencilSettings.front().fWriteMask; 194 195 if (glPathRange->shouldStroke()) { 196 if (glPathRange->shouldFill()) { 197 GL_CALL(StencilFillPathInstanced( 198 count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(), 199 fillMode, writeMask, gXformType2GLType[transformType], 200 transformValues)); 201 } 202 GL_CALL(StencilThenCoverStrokePathInstanced( 203 count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(), 204 0xffff, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES, 205 gXformType2GLType[transformType], transformValues)); 206 } else { 207 GL_CALL(StencilThenCoverFillPathInstanced( 208 count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(), 209 fillMode, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES, 210 gXformType2GLType[transformType], transformValues)); 211 } 212 } 213 214 void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location, 215 GrGLenum genMode, GrGLint components, 216 const SkMatrix& matrix) { 217 float coefficients[3 * 3]; 218 SkASSERT(components >= 1 && components <= 3); 219 220 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]); 221 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]); 222 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]); 223 224 if (components >= 2) { 225 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]); 226 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]); 227 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]); 228 } 229 230 if (components >= 3) { 231 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]); 232 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]); 233 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]); 234 } 235 SkDEBUGCODE(verify_floats(coefficients, components * 3)); 236 237 GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients)); 238 } 239 240 void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix, 241 const SkISize& renderTargetSize, 242 GrSurfaceOrigin renderTargetOrigin) { 243 244 SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport()); 245 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 256 float glMatrix[4 * 4]; 257 fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix); 258 SkDEBUGCODE(verify_floats(glMatrix, SK_ARRAY_COUNT(glMatrix))); 259 GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix)); 260 } 261 262 GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) { 263 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; 303 } 304 305 GL_CALL_RET(firstID, GenPaths(range)); 306 if (firstID == 0) { 307 SkDebugf("Warning: Failed to allocate path\n"); 308 } 309 return firstID; 310 } 311 312 void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) { 313 GL_CALL(DeletePaths(path, range)); 314 } 315 316 void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) { 317 if (fHWPathStencilSettings != stencilSettings) { 318 SkASSERT(stencilSettings.isValid()); 319 // 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) 321 uint16_t ref = stencilSettings.front().fRef; 322 GrStencilTest test = stencilSettings.front().fTest; 323 uint16_t testMask = stencilSettings.front().fTestMask; 324 325 if (!fHWPathStencilSettings.isValid() || 326 ref != fHWPathStencilSettings.front().fRef || 327 test != fHWPathStencilSettings.front().fTest || 328 testMask != fHWPathStencilSettings.front().fTestMask) { 329 GL_CALL(PathStencilFunc(GrToGLStencilFunc(test), ref, testMask)); 330 } 331 fHWPathStencilSettings = stencilSettings; 332 } 333 } 334 335 inline GrGLGpu* GrGLPathRendering::gpu() { 336 return static_cast<GrGLGpu*>(fGpu); 337 } 338