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/GrGLNameAllocator.h" 10#include "gl/GrGLUtil.h" 11#include "gl/GrGLGpu.h" 12 13#include "GrGLPath.h" 14#include "GrGLPathRange.h" 15#include "GrGLPathRendering.h" 16 17#include "SkStream.h" 18#include "SkTypeface.h" 19 20#define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X) 21#define GL_CALL_RET(RET, X) GR_GL_CALL_RET(fGpu->glInterface(), RET, X) 22 23 24static 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 35static 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} 61 62GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu) 63 : fGpu(gpu) { 64 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 fCaps.glyphLoadingSupport = 73 NULL != glInterface->fFunctions.fPathMemoryGlyphIndexArray; 74 75 SkASSERT(fCaps.fragmentInputGenSupport); 76} 77 78GrGLPathRendering::~GrGLPathRendering() { 79} 80 81void GrGLPathRendering::abandonGpuResources() { 82 fPathNameAllocator.reset(NULL); 83} 84 85void GrGLPathRendering::resetContext() { 86 fHWProjectionMatrixState.invalidate(); 87 // we don't use the model view matrix. 88 GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW)); 89 90 SkASSERT(fCaps.fragmentInputGenSupport); 91 fHWPathStencilSettings.invalidate(); 92} 93 94GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) { 95 return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke)); 96} 97 98GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator, 99 const SkStrokeRec& stroke) { 100 return SkNEW_ARGS(GrGLPathRange, (fGpu, pathGenerator, stroke)); 101} 102 103GrPathRange* GrGLPathRendering::createGlyphs(const SkTypeface* typeface, 104 const SkDescriptor* desc, 105 const SkStrokeRec& stroke) { 106 if (NULL != desc || !caps().glyphLoadingSupport) { 107 return GrPathRendering::createGlyphs(typeface, desc, stroke); 108 } 109 110 if (NULL == typeface) { 111 typeface = SkTypeface::GetDefaultTypeface(); 112 SkASSERT(NULL != typeface); 113 } 114 115 int faceIndex; 116 SkAutoTDelete<SkStream> fontStream(typeface->openStream(&faceIndex)); 117 118 const size_t fontDataLength = fontStream->getLength(); 119 if (0 == fontDataLength) { 120 return GrPathRendering::createGlyphs(typeface, NULL, stroke); 121 } 122 123 SkTArray<uint8_t> fontTempBuffer; 124 const void* fontData = fontStream->getMemoryBase(); 125 if (NULL == fontData) { 126 // TODO: Find a more efficient way to pass the font data (e.g. open file descriptor). 127 fontTempBuffer.reset(SkToInt(fontDataLength)); 128 fontStream->read(&fontTempBuffer.front(), fontDataLength); 129 fontData = &fontTempBuffer.front(); 130 } 131 132 const int numPaths = typeface->countGlyphs(); 133 const GrGLuint basePathID = this->genPaths(numPaths); 134 SkAutoTUnref<GrGLPath> templatePath(SkNEW_ARGS(GrGLPath, (fGpu, SkPath(), stroke))); 135 136 GrGLenum status; 137 GL_CALL_RET(status, PathMemoryGlyphIndexArray(basePathID, GR_GL_STANDARD_FONT_FORMAT, 138 fontDataLength, fontData, faceIndex, 0, 139 numPaths, templatePath->pathID(), 140 SkPaint::kCanonicalTextSizeForPaths)); 141 142 if (GR_GL_FONT_GLYPHS_AVAILABLE != status) { 143 this->deletePaths(basePathID, numPaths); 144 return GrPathRendering::createGlyphs(typeface, NULL, stroke); 145 } 146 147 // This is a crude approximation. We may want to consider giving this class 148 // a pseudo PathGenerator whose sole purpose is to track the approximate gpu 149 // memory size. 150 const size_t gpuMemorySize = fontDataLength / 4; 151 return SkNEW_ARGS(GrGLPathRange, (fGpu, basePathID, numPaths, gpuMemorySize, stroke)); 152} 153 154void GrGLPathRendering::stencilPath(const GrPath* path, const GrStencilSettings& stencilSettings) { 155 GrGLuint id = static_cast<const GrGLPath*>(path)->pathID(); 156 157 this->flushPathStencilSettings(stencilSettings); 158 SkASSERT(!fHWPathStencilSettings.isTwoSided()); 159 160 const SkStrokeRec& stroke = path->getStroke(); 161 162 GrGLenum fillMode = 163 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face)); 164 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face); 165 166 if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) { 167 GL_CALL(StencilFillPath(id, fillMode, writeMask)); 168 } 169 if (stroke.needToApply()) { 170 GL_CALL(StencilStrokePath(id, 0xffff, writeMask)); 171 } 172} 173 174void GrGLPathRendering::drawPath(const GrPath* path, const GrStencilSettings& stencilSettings) { 175 GrGLuint id = static_cast<const GrGLPath*>(path)->pathID(); 176 177 this->flushPathStencilSettings(stencilSettings); 178 SkASSERT(!fHWPathStencilSettings.isTwoSided()); 179 180 const SkStrokeRec& stroke = path->getStroke(); 181 182 GrGLenum fillMode = 183 gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face)); 184 GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face); 185 186 if (stroke.needToApply()) { 187 if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) { 188 GL_CALL(StencilFillPath(id, fillMode, writeMask)); 189 } 190 this->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX); 191 } else { 192 this->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX); 193 } 194} 195 196void GrGLPathRendering::drawPaths(const GrPathRange* pathRange, 197 const void* indices, PathIndexType indexType, 198 const float transformValues[], PathTransformType transformType, 199 int count, const GrStencilSettings& stencilSettings) { 200 SkASSERT(fGpu->caps()->shaderCaps()->pathRenderingSupport()); 201 202 GrGLuint baseID = static_cast<const GrGLPathRange*>(pathRange)->basePathID(); 203 204 this->flushPathStencilSettings(stencilSettings); 205 SkASSERT(!fHWPathStencilSettings.isTwoSided()); 206 207 const SkStrokeRec& stroke = pathRange->getStroke(); 208 209 GrGLenum fillMode = 210 gr_stencil_op_to_gl_path_rendering_fill_mode( 211 fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face)); 212 GrGLint writeMask = 213 fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face); 214 215 if (stroke.needToApply()) { 216 if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) { 217 GL_CALL(StencilFillPathInstanced( 218 count, gIndexType2GLType[indexType], indices, baseID, fillMode, 219 writeMask, gXformType2GLType[transformType], transformValues)); 220 } 221 this->stencilThenCoverStrokePathInstanced( 222 count, gIndexType2GLType[indexType], indices, baseID, 223 0xffff, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES, 224 gXformType2GLType[transformType], transformValues); 225 } else { 226 this->stencilThenCoverFillPathInstanced( 227 count, gIndexType2GLType[indexType], indices, baseID, 228 fillMode, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES, 229 gXformType2GLType[transformType], transformValues); 230 } 231} 232 233void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location, 234 GrGLenum genMode, GrGLint components, 235 const SkMatrix& matrix) { 236 SkASSERT(caps().fragmentInputGenSupport); 237 GrGLfloat coefficients[3 * 3]; 238 SkASSERT(components >= 1 && components <= 3); 239 240 coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]); 241 coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]); 242 coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]); 243 244 if (components >= 2) { 245 coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]); 246 coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]); 247 coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]); 248 } 249 250 if (components >= 3) { 251 coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]); 252 coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]); 253 coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]); 254 } 255 256 GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients)); 257} 258 259void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix, 260 const SkISize& renderTargetSize, 261 GrSurfaceOrigin renderTargetOrigin) { 262 263 SkASSERT(fGpu->glCaps().shaderCaps()->pathRenderingSupport()); 264 265 if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin && 266 renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize && 267 matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) { 268 return; 269 } 270 271 fHWProjectionMatrixState.fViewMatrix = matrix; 272 fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize; 273 fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin; 274 275 GrGLfloat glMatrix[4 * 4]; 276 fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix); 277 GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix)); 278} 279 280GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) { 281 if (range > 1) { 282 GrGLuint name; 283 GL_CALL_RET(name, GenPaths(range)); 284 return name; 285 } 286 287 if (NULL == fPathNameAllocator.get()) { 288 static const int range = 65536; 289 GrGLuint firstName; 290 GL_CALL_RET(firstName, GenPaths(range)); 291 fPathNameAllocator.reset(SkNEW_ARGS(GrGLNameAllocator, (firstName, firstName + range))); 292 } 293 294 // When allocating names one at a time, pull from a client-side pool of 295 // available names in order to save a round trip to the GL server. 296 GrGLuint name = fPathNameAllocator->allocateName(); 297 298 if (0 == name) { 299 // Our reserved path names are all in use. Fall back on GenPaths. 300 GL_CALL_RET(name, GenPaths(1)); 301 } 302 303 return name; 304} 305 306void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) { 307 if (range > 1) { 308 // It is not supported to delete names in ranges that were allocated 309 // individually using GrGLPathNameAllocator. 310 SkASSERT(NULL == fPathNameAllocator.get() || 311 path + range <= fPathNameAllocator->firstName() || 312 path >= fPathNameAllocator->endName()); 313 GL_CALL(DeletePaths(path, range)); 314 return; 315 } 316 317 if (NULL == fPathNameAllocator.get() || 318 path < fPathNameAllocator->firstName() || 319 path >= fPathNameAllocator->endName()) { 320 // If we aren't inside fPathNameAllocator's range then this name was 321 // generated by the GenPaths fallback (or else was never allocated). 322 GL_CALL(DeletePaths(path, 1)); 323 return; 324 } 325 326 // Make the path empty to save memory, but don't free the name in the driver. 327 GL_CALL(PathCommands(path, 0, NULL, 0, GR_GL_FLOAT, NULL)); 328 fPathNameAllocator->free(path); 329} 330 331void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) { 332 if (fHWPathStencilSettings != stencilSettings) { 333 // Just the func, ref, and mask is set here. The op and write mask are params to the call 334 // that draws the path to the SB (glStencilFillPath) 335 GrGLenum func = 336 GrToGLStencilFunc(stencilSettings.func(GrStencilSettings::kFront_Face)); 337 GL_CALL(PathStencilFunc(func, stencilSettings.funcRef(GrStencilSettings::kFront_Face), 338 stencilSettings.funcMask(GrStencilSettings::kFront_Face))); 339 340 fHWPathStencilSettings = stencilSettings; 341 } 342} 343 344inline void GrGLPathRendering::stencilThenCoverFillPath(GrGLuint path, GrGLenum fillMode, 345 GrGLuint mask, GrGLenum coverMode) { 346 if (caps().stencilThenCoverSupport) { 347 GL_CALL(StencilThenCoverFillPath(path, fillMode, mask, coverMode)); 348 return; 349 } 350 GL_CALL(StencilFillPath(path, fillMode, mask)); 351 GL_CALL(CoverFillPath(path, coverMode)); 352} 353 354inline void GrGLPathRendering::stencilThenCoverStrokePath(GrGLuint path, GrGLint reference, 355 GrGLuint mask, GrGLenum coverMode) { 356 if (caps().stencilThenCoverSupport) { 357 GL_CALL(StencilThenCoverStrokePath(path, reference, mask, coverMode)); 358 return; 359 } 360 GL_CALL(StencilStrokePath(path, reference, mask)); 361 GL_CALL(CoverStrokePath(path, coverMode)); 362} 363 364inline void GrGLPathRendering::stencilThenCoverFillPathInstanced( 365 GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, 366 GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode, 367 GrGLenum transformType, const GrGLfloat *transformValues) { 368 if (caps().stencilThenCoverSupport) { 369 GL_CALL(StencilThenCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, fillMode, 370 mask, coverMode, transformType, transformValues)); 371 return; 372 } 373 GL_CALL(StencilFillPathInstanced(numPaths, pathNameType, paths, pathBase, 374 fillMode, mask, transformType, transformValues)); 375 GL_CALL(CoverFillPathInstanced(numPaths, pathNameType, paths, pathBase, 376 coverMode, transformType, transformValues)); 377} 378 379inline void GrGLPathRendering::stencilThenCoverStrokePathInstanced( 380 GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, 381 GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode, 382 GrGLenum transformType, const GrGLfloat *transformValues) { 383 if (caps().stencilThenCoverSupport) { 384 GL_CALL(StencilThenCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase, 385 reference, mask, coverMode, transformType, 386 transformValues)); 387 return; 388 } 389 390 GL_CALL(StencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase, 391 reference, mask, transformType, transformValues)); 392 GL_CALL(CoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase, 393 coverMode, transformType, transformValues)); 394} 395