Home | History | Annotate | Download | only in gl
      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 
     24 static const GrGLenum gIndexType2GLType[] = {
     25     GR_GL_UNSIGNED_BYTE,
     26     GR_GL_UNSIGNED_SHORT,
     27     GR_GL_UNSIGNED_INT
     28 };
     29 
     30 GR_STATIC_ASSERT(0 == GrPathRange::kU8_PathIndexType);
     31 GR_STATIC_ASSERT(1 == GrPathRange::kU16_PathIndexType);
     32 GR_STATIC_ASSERT(2 == GrPathRange::kU32_PathIndexType);
     33 GR_STATIC_ASSERT(GrPathRange::kU32_PathIndexType == GrPathRange::kLast_PathIndexType);
     34 
     35 static 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 
     43 GR_STATIC_ASSERT(0 == GrPathRendering::kNone_PathTransformType);
     44 GR_STATIC_ASSERT(1 == GrPathRendering::kTranslateX_PathTransformType);
     45 GR_STATIC_ASSERT(2 == GrPathRendering::kTranslateY_PathTransformType);
     46 GR_STATIC_ASSERT(3 == GrPathRendering::kTranslate_PathTransformType);
     47 GR_STATIC_ASSERT(4 == GrPathRendering::kAffine_PathTransformType);
     48 GR_STATIC_ASSERT(GrPathRendering::kAffine_PathTransformType == GrPathRendering::kLast_PathTransformType);
     49 
     50 static 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 
     62 GrGLPathRendering::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 
     78 GrGLPathRendering::~GrGLPathRendering() {
     79 }
     80 
     81 void GrGLPathRendering::abandonGpuResources() {
     82     fPathNameAllocator.reset(NULL);
     83 }
     84 
     85 void 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 
     94 GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const SkStrokeRec& stroke) {
     95     return SkNEW_ARGS(GrGLPath, (fGpu, inPath, stroke));
     96 }
     97 
     98 GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
     99                                                 const SkStrokeRec& stroke) {
    100     return SkNEW_ARGS(GrGLPathRange, (fGpu, pathGenerator, stroke));
    101 }
    102 
    103 GrPathRange* 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 
    154 void 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 
    174 void 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 
    196 void 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 
    233 void 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 
    259 void 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 
    280 GrGLuint 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 
    306 void 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 
    331 void 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 
    344 inline 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 
    354 inline 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 
    364 inline 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 
    379 inline 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