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/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