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 static GrGLenum gr_stencil_op_to_gl_path_rendering_fill_mode(GrStencilOp op) {
     53     switch (op) {
     54         default:
     55             SkFAIL("Unexpected path fill.");
     56             /* fallthrough */;
     57         case kIncClamp_StencilOp:
     58             return GR_GL_COUNT_UP;
     59         case kInvert_StencilOp:
     60             return GR_GL_INVERT;
     61     }
     62 }
     63 
     64 GrGLPathRendering::GrGLPathRendering(GrGLGpu* gpu)
     65     : GrPathRendering(gpu)
     66     , fPreallocatedPathCount(0) {
     67     const GrGLInterface* glInterface = gpu->glInterface();
     68     fCaps.bindFragmentInputSupport =
     69         nullptr != glInterface->fFunctions.fBindFragmentInputLocation;
     70 }
     71 
     72 GrGLPathRendering::~GrGLPathRendering() {
     73     if (fPreallocatedPathCount > 0) {
     74         this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
     75     }
     76 }
     77 
     78 void GrGLPathRendering::abandonGpuResources() {
     79     fPreallocatedPathCount = 0;
     80 }
     81 
     82 void GrGLPathRendering::resetContext() {
     83     fHWProjectionMatrixState.invalidate();
     84     // we don't use the model view matrix.
     85     GL_CALL(MatrixLoadIdentity(GR_GL_PATH_MODELVIEW));
     86 
     87     fHWPathStencilSettings.invalidate();
     88 }
     89 
     90 GrPath* GrGLPathRendering::createPath(const SkPath& inPath, const GrStrokeInfo& stroke) {
     91     return new GrGLPath(this->gpu(), inPath, stroke);
     92 }
     93 
     94 GrPathRange* GrGLPathRendering::createPathRange(GrPathRange::PathGenerator* pathGenerator,
     95                                                 const GrStrokeInfo& stroke) {
     96     return new GrGLPathRange(this->gpu(), pathGenerator, stroke);
     97 }
     98 
     99 void GrGLPathRendering::onStencilPath(const StencilPathArgs& args, const GrPath* path) {
    100     GrGLGpu* gpu = this->gpu();
    101     SkASSERT(gpu->caps()->shaderCaps()->pathRenderingSupport());
    102     gpu->flushColorWrite(false);
    103     gpu->flushDrawFace(GrPipelineBuilder::kBoth_DrawFace);
    104 
    105     GrGLRenderTarget* rt = static_cast<GrGLRenderTarget*>(args.fRenderTarget);
    106     SkISize size = SkISize::Make(rt->width(), rt->height());
    107     this->setProjectionMatrix(*args.fViewMatrix, size, rt->origin());
    108     gpu->flushScissor(*args.fScissor, rt->getViewport(), rt->origin());
    109     gpu->flushHWAAState(rt, args.fUseHWAA, true);
    110     gpu->flushRenderTarget(rt, nullptr);
    111 
    112     const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
    113 
    114     this->flushPathStencilSettings(*args.fStencil);
    115     SkASSERT(!fHWPathStencilSettings.isTwoSided());
    116 
    117     GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
    118         fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
    119     GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
    120 
    121     if (glPath->shouldFill()) {
    122         GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
    123     }
    124     if (glPath->shouldStroke()) {
    125         GL_CALL(StencilStrokePath(glPath->pathID(), 0xffff, writeMask));
    126     }
    127 }
    128 
    129 void GrGLPathRendering::onDrawPath(const DrawPathArgs& args, const GrPath* path) {
    130     if (!this->gpu()->flushGLState(args)) {
    131         return;
    132     }
    133     const GrGLPath* glPath = static_cast<const GrGLPath*>(path);
    134 
    135     this->flushPathStencilSettings(*args.fStencil);
    136     SkASSERT(!fHWPathStencilSettings.isTwoSided());
    137 
    138     GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(
    139         fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
    140     GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
    141 
    142     if (glPath->shouldStroke()) {
    143         if (glPath->shouldFill()) {
    144             GL_CALL(StencilFillPath(glPath->pathID(), fillMode, writeMask));
    145         }
    146         GL_CALL(StencilThenCoverStrokePath(glPath->pathID(), 0xffff, writeMask,
    147                                            GR_GL_BOUNDING_BOX));
    148     } else {
    149         GL_CALL(StencilThenCoverFillPath(glPath->pathID(), fillMode, writeMask,
    150                                          GR_GL_BOUNDING_BOX));
    151     }
    152 }
    153 
    154 void 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 
    164 
    165     const GrGLPathRange* glPathRange = static_cast<const GrGLPathRange*>(pathRange);
    166 
    167     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 
    173     if (glPathRange->shouldStroke()) {
    174         if (glPathRange->shouldFill()) {
    175             GL_CALL(StencilFillPathInstanced(
    176                             count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
    177                             fillMode, writeMask, gXformType2GLType[transformType],
    178                             transformValues));
    179         }
    180         GL_CALL(StencilThenCoverStrokePathInstanced(
    181                             count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
    182                             0xffff, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
    183                             gXformType2GLType[transformType], transformValues));
    184     } else {
    185         GL_CALL(StencilThenCoverFillPathInstanced(
    186                             count, gIndexType2GLType[indexType], indices, glPathRange->basePathID(),
    187                             fillMode, writeMask, GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
    188                             gXformType2GLType[transformType], transformValues));
    189     }
    190 }
    191 
    192 void GrGLPathRendering::setProgramPathFragmentInputTransform(GrGLuint program, GrGLint location,
    193                                                              GrGLenum genMode, GrGLint components,
    194                                                              const SkMatrix& matrix) {
    195     float coefficients[3 * 3];
    196     SkASSERT(components >= 1 && components <= 3);
    197 
    198     coefficients[0] = SkScalarToFloat(matrix[SkMatrix::kMScaleX]);
    199     coefficients[1] = SkScalarToFloat(matrix[SkMatrix::kMSkewX]);
    200     coefficients[2] = SkScalarToFloat(matrix[SkMatrix::kMTransX]);
    201 
    202     if (components >= 2) {
    203         coefficients[3] = SkScalarToFloat(matrix[SkMatrix::kMSkewY]);
    204         coefficients[4] = SkScalarToFloat(matrix[SkMatrix::kMScaleY]);
    205         coefficients[5] = SkScalarToFloat(matrix[SkMatrix::kMTransY]);
    206     }
    207 
    208     if (components >= 3) {
    209         coefficients[6] = SkScalarToFloat(matrix[SkMatrix::kMPersp0]);
    210         coefficients[7] = SkScalarToFloat(matrix[SkMatrix::kMPersp1]);
    211         coefficients[8] = SkScalarToFloat(matrix[SkMatrix::kMPersp2]);
    212     }
    213 
    214     GL_CALL(ProgramPathFragmentInputGen(program, location, genMode, components, coefficients));
    215 }
    216 
    217 void GrGLPathRendering::setProjectionMatrix(const SkMatrix& matrix,
    218                                             const SkISize& renderTargetSize,
    219                                             GrSurfaceOrigin renderTargetOrigin) {
    220 
    221     SkASSERT(this->gpu()->glCaps().shaderCaps()->pathRenderingSupport());
    222 
    223     if (renderTargetOrigin == fHWProjectionMatrixState.fRenderTargetOrigin &&
    224         renderTargetSize == fHWProjectionMatrixState.fRenderTargetSize &&
    225         matrix.cheapEqualTo(fHWProjectionMatrixState.fViewMatrix)) {
    226         return;
    227     }
    228 
    229     fHWProjectionMatrixState.fViewMatrix = matrix;
    230     fHWProjectionMatrixState.fRenderTargetSize = renderTargetSize;
    231     fHWProjectionMatrixState.fRenderTargetOrigin = renderTargetOrigin;
    232 
    233     float glMatrix[4 * 4];
    234     fHWProjectionMatrixState.getRTAdjustedGLMatrix<4>(glMatrix);
    235     GL_CALL(MatrixLoadf(GR_GL_PATH_PROJECTION, glMatrix));
    236 }
    237 
    238 GrGLuint GrGLPathRendering::genPaths(GrGLsizei range) {
    239     SkASSERT(range > 0);
    240     GrGLuint firstID;
    241     if (fPreallocatedPathCount >= range) {
    242         firstID = fFirstPreallocatedPathID;
    243         fPreallocatedPathCount -= range;
    244         fFirstPreallocatedPathID += range;
    245         return firstID;
    246     }
    247     // Allocate range + the amount to fill up preallocation amount. If succeed, either join with
    248     // the existing preallocation range or delete the existing and use the new (potentially partial)
    249     // preallocation range.
    250     GrGLsizei allocAmount = range + (kPathIDPreallocationAmount - fPreallocatedPathCount);
    251     if (allocAmount >= range) {
    252         GL_CALL_RET(firstID, GenPaths(allocAmount));
    253 
    254         if (firstID != 0) {
    255             if (fPreallocatedPathCount > 0 &&
    256                 firstID == fFirstPreallocatedPathID + fPreallocatedPathCount) {
    257                 firstID = fFirstPreallocatedPathID;
    258                 fPreallocatedPathCount += allocAmount - range;
    259                 fFirstPreallocatedPathID += range;
    260                 return firstID;
    261             }
    262 
    263             if (allocAmount > range) {
    264                 if (fPreallocatedPathCount > 0) {
    265                     this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
    266                 }
    267                 fFirstPreallocatedPathID = firstID + range;
    268                 fPreallocatedPathCount = allocAmount - range;
    269             }
    270             // Special case: if allocAmount == range, we have full preallocated range.
    271             return firstID;
    272         }
    273     }
    274     // Failed to allocate with preallocation. Remove existing preallocation and try to allocate just
    275     // the range.
    276     if (fPreallocatedPathCount > 0) {
    277         this->deletePaths(fFirstPreallocatedPathID, fPreallocatedPathCount);
    278         fPreallocatedPathCount = 0;
    279     }
    280 
    281     GL_CALL_RET(firstID, GenPaths(range));
    282     if (firstID == 0) {
    283         SkDebugf("Warning: Failed to allocate path\n");
    284     }
    285     return firstID;
    286 }
    287 
    288 void GrGLPathRendering::deletePaths(GrGLuint path, GrGLsizei range) {
    289     GL_CALL(DeletePaths(path, range));
    290 }
    291 
    292 void GrGLPathRendering::flushPathStencilSettings(const GrStencilSettings& stencilSettings) {
    293     if (fHWPathStencilSettings != stencilSettings) {
    294         SkASSERT(stencilSettings.isValid());
    295         // Just the func, ref, and mask is set here. The op and write mask are params to the call
    296         // that draws the path to the SB (glStencilFillPath)
    297         const GrStencilSettings::Face kFront_Face = GrStencilSettings::kFront_Face;
    298         GrStencilFunc func = stencilSettings.func(kFront_Face);
    299         uint16_t funcRef = stencilSettings.funcRef(kFront_Face);
    300         uint16_t funcMask = stencilSettings.funcMask(kFront_Face);
    301 
    302         if (!fHWPathStencilSettings.isValid() ||
    303             func != fHWPathStencilSettings.func(kFront_Face) ||
    304             funcRef != fHWPathStencilSettings.funcRef(kFront_Face) ||
    305             funcMask != fHWPathStencilSettings.funcMask(kFront_Face)) {
    306             GL_CALL(PathStencilFunc(GrToGLStencilFunc(func), funcRef, funcMask));
    307         }
    308         fHWPathStencilSettings = stencilSettings;
    309     }
    310 }
    311 
    312 inline GrGLGpu* GrGLPathRendering::gpu() {
    313     return static_cast<GrGLGpu*>(fGpu);
    314 }
    315