Exemplo n.º 1
0
void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture,
                                              GrDrawTarget* target,
                                              const GrIRect& rect) {
    GrDrawState* drawState = target->drawState();

    GrDrawState::AutoDeviceCoordDraw adcd(drawState);
    if (!adcd.succeeded()) {
        return;
    }
    enum {
        // the SW path renderer shares this stage with glyph
        // rendering (kGlyphMaskStage in GrBatchedTextContext)
        kPathMaskStage = GrPaint::kTotalStages,
    };
    GrAssert(!drawState->isStageEnabled(kPathMaskStage));
    drawState->stage(kPathMaskStage)->reset();
    drawState->createTextureEffect(kPathMaskStage, texture);
    GrScalar w = GrIntToScalar(rect.width());
    GrScalar h = GrIntToScalar(rect.height());
    GrRect maskRect = GrRect::MakeWH(w / texture->width(),
                                     h / texture->height());

    const GrRect* srcRects[GrDrawState::kNumStages] = { NULL };
    srcRects[kPathMaskStage] = &maskRect;
    GrRect dstRect = GrRect::MakeLTRB(
                            SK_Scalar1 * rect.fLeft,
                            SK_Scalar1 * rect.fTop,
                            SK_Scalar1 * rect.fRight,
                            SK_Scalar1 * rect.fBottom);
    target->drawRect(dstRect, NULL, srcRects, NULL);
    drawState->disableStage(kPathMaskStage);
}
Exemplo n.º 2
0
void GrGpuGLShaders::flushViewMatrix() {
    GrAssert(NULL != fCurrDrawState.fRenderTarget);
    GrMatrix m (
        GrIntToScalar(2) / fCurrDrawState.fRenderTarget->width(), 0, -GR_Scalar1,
        0,-GrIntToScalar(2) / fCurrDrawState.fRenderTarget->height(), GR_Scalar1,
        0, 0, GrMatrix::I()[8]);
    m.setConcat(m, fCurrDrawState.fViewMatrix);

    // ES doesn't allow you to pass true to the transpose param,
    // so do our own transpose
    GrScalar mt[]  = {
        m[GrMatrix::kScaleX],
        m[GrMatrix::kSkewY],
        m[GrMatrix::kPersp0],
        m[GrMatrix::kSkewX],
        m[GrMatrix::kScaleY],
        m[GrMatrix::kPersp1],
        m[GrMatrix::kTransX],
        m[GrMatrix::kTransY],
        m[GrMatrix::kPersp2]
    };
#if ATTRIBUTE_MATRIX
    GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+0, mt+0));
    GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+1, mt+3));
    GR_GL(VertexAttrib4fv(VIEWMAT_ATTR_LOCATION+2, mt+6));
#else
    GR_GL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,1,false,mt));
#endif
}
Exemplo n.º 3
0
void GrGpuGLShaders::flushViewMatrix() {
    const GrMatrix& vm = this->getDrawState().getViewMatrix();
    if (!fProgramData->fViewMatrix.cheapEqualTo(vm)) {

        const GrRenderTarget* rt = this->getDrawState().getRenderTarget();
        GrAssert(NULL != rt);
        GrMatrix m;
        m.setAll(
            GrIntToScalar(2) / rt->width(), 0, -GR_Scalar1,
            0,-GrIntToScalar(2) / rt->height(), GR_Scalar1,
            0, 0, GrMatrix::I()[8]);
        m.setConcat(m, vm);

        // ES doesn't allow you to pass true to the transpose param,
        // so do our own transpose
        GrGLfloat mt[]  = {
            GrScalarToFloat(m[GrMatrix::kMScaleX]),
            GrScalarToFloat(m[GrMatrix::kMSkewY]),
            GrScalarToFloat(m[GrMatrix::kMPersp0]),
            GrScalarToFloat(m[GrMatrix::kMSkewX]),
            GrScalarToFloat(m[GrMatrix::kMScaleY]),
            GrScalarToFloat(m[GrMatrix::kMPersp1]),
            GrScalarToFloat(m[GrMatrix::kMTransX]),
            GrScalarToFloat(m[GrMatrix::kMTransY]),
            GrScalarToFloat(m[GrMatrix::kMPersp2])
        };

        GrAssert(GrGLProgram::kUnusedUniform != 
                 fProgramData->fUniLocations.fViewMatrixUni);
        GL_CALL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
                                 1, false, mt));
        fProgramData->fViewMatrix = vm;
    }
}
Exemplo n.º 4
0
////////////////////////////////////////////////////////////////////////////////
// return true on success; false on failure
bool GrSoftwarePathRenderer::onDrawPath(const SkPath& path,
                                        GrPathFill fill,
                                        const GrVec* translate,
                                        GrDrawTarget* target,
                                        GrDrawState::StageMask stageMask,
                                        bool antiAlias) {

    if (NULL == fContext) {
        return false;
    }

    GrAutoScratchTexture ast;
    GrIRect pathBounds, clipBounds;
    if (!get_path_and_clip_bounds(target, path, translate,
                                  &pathBounds, &clipBounds)) {
        return true;    // path is empty so there is nothing to do
    }
    if (sw_draw_path_to_mask_texture(path, pathBounds,
                                     fill, fContext,
                                     translate, &ast, antiAlias)) {
        GrTexture* texture = ast.texture();
        GrAssert(NULL != texture);
        GrDrawTarget::AutoDeviceCoordDraw adcd(target, stageMask);
        enum {
            // the SW path renderer shares this stage with glyph
            // rendering (kGlyphMaskStage in GrBatchedTextContext)
            kPathMaskStage = GrPaint::kTotalStages,
        };
        GrAssert(NULL == target->drawState()->getTexture(kPathMaskStage));
        target->drawState()->setTexture(kPathMaskStage, texture);
        target->drawState()->sampler(kPathMaskStage)->reset();
        GrScalar w = GrIntToScalar(pathBounds.width());
        GrScalar h = GrIntToScalar(pathBounds.height());
        GrRect maskRect = GrRect::MakeWH(w / texture->width(),
                                         h / texture->height());
        const GrRect* srcRects[GrDrawState::kNumStages] = {NULL};
        srcRects[kPathMaskStage] = &maskRect;
        stageMask |= 1 << kPathMaskStage;
        GrRect dstRect = GrRect::MakeLTRB(
                              SK_Scalar1* pathBounds.fLeft,
                              SK_Scalar1* pathBounds.fTop,
                              SK_Scalar1* pathBounds.fRight,
                              SK_Scalar1* pathBounds.fBottom);
        target->drawRect(dstRect, NULL, stageMask, srcRects, NULL);
        target->drawState()->setTexture(kPathMaskStage, NULL);
        if (GrIsFillInverted(fill)) {
            draw_around_inv_path(target, stageMask,
                                 clipBounds, pathBounds);
        }
        return true;
    }

    return false;
}
Exemplo n.º 5
0
////////////////////////////////////////////////////////////////////////////////
// Shared preamble between gpu and SW-only AA clip mask creation paths.
// Handles caching, determination of clip mask bound & allocation (if needed)
// of the result texture
// Returns true if there is no more work to be done (i.e., we got a cache hit)
bool GrClipMaskManager::clipMaskPreamble(GrGpu* gpu,
                                         const GrClip& clipIn,
                                         GrTexture** result,
                                         GrIRect *resultBounds) {
    GrDrawState* origDrawState = gpu->drawState();
    GrAssert(origDrawState->isClipState());

    GrRenderTarget* rt = origDrawState->getRenderTarget();
    GrAssert(NULL != rt);

    GrRect rtRect;
    rtRect.setLTRB(0, 0,
                    GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));

    // unlike the stencil path the alpha path is not bound to the size of the
    // render target - determine the minimum size required for the mask
    GrRect bounds;

    if (clipIn.hasConservativeBounds()) {
        bounds = clipIn.getConservativeBounds();
        if (!bounds.intersect(rtRect)) {
            // the mask will be empty in this case
            GrAssert(false);
            bounds.setEmpty();
        }
    } else {
        // still locked to the size of the render target
        bounds = rtRect;
    }

    GrIRect intBounds;
    bounds.roundOut(&intBounds);

    // need to outset a pixel since the standard bounding box computation
    // path doesn't leave any room for antialiasing (esp. w.r.t. rects)
    intBounds.outset(1, 1);

    // TODO: make sure we don't outset if bounds are still 0,0 @ min

    if (fAACache.canReuse(clipIn, 
                          intBounds.width(),
                          intBounds.height())) {
        *result = fAACache.getLastMask();
        fAACache.getLastBound(resultBounds);
        return true;
    }

    this->setupCache(clipIn, intBounds);

    *resultBounds = intBounds;
    return false;
}
Exemplo n.º 6
0
void GrGpuGLShaders::flushViewMatrix() {
    const GrMatrix& vm = this->getDrawState().getViewMatrix();
    if (GrGpuGLShaders::getHWViewMatrix() != vm) {

        const GrRenderTarget* rt = this->getDrawState().getRenderTarget();
        GrAssert(NULL != rt);
        GrMatrix m;
        m.setAll(
            GrIntToScalar(2) / rt->width(), 0, -GR_Scalar1,
            0,-GrIntToScalar(2) / rt->height(), GR_Scalar1,
            0, 0, GrMatrix::I()[8]);
        m.setConcat(m, vm);

        // ES doesn't allow you to pass true to the transpose param,
        // so do our own transpose
        GrGLfloat mt[]  = {
            GrScalarToFloat(m[GrMatrix::kMScaleX]),
            GrScalarToFloat(m[GrMatrix::kMSkewY]),
            GrScalarToFloat(m[GrMatrix::kMPersp0]),
            GrScalarToFloat(m[GrMatrix::kMSkewX]),
            GrScalarToFloat(m[GrMatrix::kMScaleY]),
            GrScalarToFloat(m[GrMatrix::kMPersp1]),
            GrScalarToFloat(m[GrMatrix::kMTransX]),
            GrScalarToFloat(m[GrMatrix::kMTransY]),
            GrScalarToFloat(m[GrMatrix::kMPersp2])
        };

        if (GrGLProgram::kSetAsAttribute ==
                fProgramData->fUniLocations.fViewMatrixUni) {
            int baseIdx = GrGLProgram::ViewMatrixAttributeIdx();
            GL_CALL(VertexAttrib4fv(baseIdx + 0, mt+0));
            GL_CALL(VertexAttrib4fv(baseIdx + 1, mt+3));
            GL_CALL(VertexAttrib4fv(baseIdx + 2, mt+6));
        } else {
            GrAssert(GrGLProgram::kUnusedUniform !=
                     fProgramData->fUniLocations.fViewMatrixUni);
            GL_CALL(UniformMatrix3fv(fProgramData->fUniLocations.fViewMatrixUni,
                                     1, false, mt));
        }
        this->recordHWViewMatrix(vm);
    }
}
Exemplo n.º 7
0
GrGLTexture::GrGLTexture(GrGpuGL* gpu,
                         const GLTextureDesc& textureDesc,
                         const GLRenderTargetIDs& rtIDs,
                         const TexParams& initialTexParams)
    : INHERITED(gpu,
                textureDesc.fContentWidth,
                textureDesc.fContentHeight,
                textureDesc.fFormat) {

    fTexParams          = initialTexParams;
    fTexIDObj           = new GrGLTexID(textureDesc.fTextureID,
                                        textureDesc.fOwnsID);
    fUploadFormat       = textureDesc.fUploadFormat;
    fUploadByteCount    = textureDesc.fUploadByteCount;
    fUploadType         = textureDesc.fUploadType;
    fOrientation        = textureDesc.fOrientation;
    fAllocWidth         = textureDesc.fAllocWidth;
    fAllocHeight        = textureDesc.fAllocHeight;
    fScaleX             = GrIntToScalar(textureDesc.fContentWidth) /
                            textureDesc.fAllocWidth;
    fScaleY             = GrIntToScalar(textureDesc.fContentHeight) /
                            textureDesc.fAllocHeight;

    GrAssert(0 != textureDesc.fTextureID);

    if (rtIDs.fTexFBOID) {
        // we render to the top left
        GrGLIRect vp;
        vp.fLeft   = 0;
        vp.fWidth  = textureDesc.fContentWidth;
        vp.fHeight = textureDesc.fContentHeight;
        vp.fBottom = textureDesc.fAllocHeight - textureDesc.fContentHeight;

        fRenderTarget = new GrGLRenderTarget(gpu, rtIDs, fTexIDObj,
                                             textureDesc.fStencilBits,
                                             rtIDs.fRTFBOID != rtIDs.fTexFBOID,
                                             vp, this);
    }
}
Exemplo n.º 8
0
static void test_convex() {
#if 0
    GrPath testPath;
    GrPath::Iter testIter;
    
    GrPath pt;
    pt.moveTo(0, 0);
    pt.close();
    
    testIter.reset(pt);
    testPath.resetFromIter(&testIter);
    GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
    
    GrPath line;
    line.moveTo(GrIntToScalar(12), GrIntToScalar(20));
    line.lineTo(GrIntToScalar(-12), GrIntToScalar(-20));
    line.close();
    
    testIter.reset(line);
    testPath.resetFromIter(&testIter);
    GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
    
    GrPath triLeft;
    triLeft.moveTo(0, 0);
    triLeft.lineTo(1, 0);
    triLeft.lineTo(1, 1);
    triLeft.close();
    
    testIter.reset(triLeft);
    testPath.resetFromIter(&testIter);
    GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
    
    GrPath triRight;
    triRight.moveTo(0, 0);
    triRight.lineTo(-1, 0);
    triRight.lineTo(1, 1);
    triRight.close();
    
    testIter.reset(triRight);
    testPath.resetFromIter(&testIter);
    GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
    
    GrPath square;
    square.moveTo(0, 0);
    square.lineTo(1, 0);
    square.lineTo(1, 1);
    square.lineTo(0, 1);
    square.close();
    
    testIter.reset(square);
    testPath.resetFromIter(&testIter);
    GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
    
    GrPath redundantSquare;
    square.moveTo(0, 0);
    square.lineTo(0, 0);
    square.lineTo(0, 0);
    square.lineTo(1, 0);
    square.lineTo(1, 0);
    square.lineTo(1, 0);
    square.lineTo(1, 1);
    square.lineTo(1, 1);
    square.lineTo(1, 1);
    square.lineTo(0, 1);
    square.lineTo(0, 1);
    square.lineTo(0, 1);
    square.close();
    
    testIter.reset(redundantSquare);
    testPath.resetFromIter(&testIter);
    GrAssert(kConvex_ConvexHint == testPath.getConvexHint());
    
    GrPath bowTie;
    bowTie.moveTo(0, 0);
    bowTie.lineTo(0, 0);
    bowTie.lineTo(0, 0);
    bowTie.lineTo(1, 1);
    bowTie.lineTo(1, 1);
    bowTie.lineTo(1, 1);
    bowTie.lineTo(1, 0);
    bowTie.lineTo(1, 0);
    bowTie.lineTo(1, 0);
    bowTie.lineTo(0, 1);
    bowTie.lineTo(0, 1);
    bowTie.lineTo(0, 1);
    bowTie.close();
    
    testIter.reset(bowTie);
    testPath.resetFromIter(&testIter);
    GrAssert(kConcave_ConvexHint == testPath.getConvexHint());
    
    GrPath spiral;
    spiral.moveTo(0, 0);
    spiral.lineTo(1, 0);
    spiral.lineTo(1, 1);
    spiral.lineTo(0, 1);
    spiral.lineTo(0,.5);
    spiral.lineTo(.5,.5);
    spiral.lineTo(.5,.75);
    spiral.close();
    
    testIter.reset(spiral);
    testPath.resetFromIter(&testIter);
    GrAssert(kConcave_ConvexHint == testPath.getConvexHint());
    
    GrPath dent;
    dent.moveTo(0, 0);
    dent.lineTo(1, 1);
    dent.lineTo(0, 1);
    dent.lineTo(-.5,2);
    dent.lineTo(-2, 1);
    dent.close();
    
    testIter.reset(dent);
    testPath.resetFromIter(&testIter);
    GrAssert(kConcave_ConvexHint == testPath.getConvexHint());
#endif
}
bool GrTesselatedPathRenderer::onDrawPath(const SkPath& path,
                                          GrPathFill fill,
                                          const GrVec* translate,
                                          GrDrawTarget* target,
                                          GrDrawState::StageMask stageMask,
                                          bool antiAlias) {

    GrDrawTarget::AutoStateRestore asr(target);
    GrDrawState* drawState = target->drawState();
    // face culling doesn't make sense here
    GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());

    GrMatrix viewM = drawState->getViewMatrix();

    GrScalar tol = GR_Scalar1;
    tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());
    GrScalar tolSqd = GrMul(tol, tol);

    int subpathCnt;
    int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);

    GrVertexLayout layout = 0;
    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
        if ((1 << s) & stageMask) {
            layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
        }
    }

    bool inverted = GrIsFillInverted(fill);
    if (inverted) {
        maxPts += 4;
        subpathCnt++;
    }
    if (maxPts > USHRT_MAX) {
        return false;
    }
    SkAutoSTMalloc<8, GrPoint> baseMem(maxPts);
    GrPoint* base = baseMem;
    GrPoint* vert = base;
    GrPoint* subpathBase = base;

    SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);

    GrPoint pts[4];
    SkPath::Iter iter(path, false);

    bool first = true;
    int subpath = 0;

    for (;;) {
        switch (iter.next(pts)) {
            case kMove_PathCmd:
                if (!first) {
                    subpathVertCount[subpath] = vert-subpathBase;
                    subpathBase = vert;
                    ++subpath;
                }
                *vert = pts[0];
                vert++;
                break;
            case kLine_PathCmd:
                *vert = pts[1];
                vert++;
                break;
            case kQuadratic_PathCmd: {
                GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
                                                     tolSqd, &vert,
                                                     GrPathUtils::quadraticPointCount(pts, tol));
                break;
            }
            case kCubic_PathCmd: {
                GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
                                                 tolSqd, &vert,
                                                 GrPathUtils::cubicPointCount(pts, tol));
                break;
            }
            case kClose_PathCmd:
                break;
            case kEnd_PathCmd:
                subpathVertCount[subpath] = vert-subpathBase;
                ++subpath; // this could be only in debug
                goto FINISHED;
        }
        first = false;
    }
FINISHED:
    if (NULL != translate && 0 != translate->fX && 0 != translate->fY) {
        for (int i = 0; i < vert - base; i++) {
            base[i].offset(translate->fX, translate->fY);
        }
    }

    if (inverted) {
        GrRect bounds;
        GrAssert(NULL != drawState->getRenderTarget());
        bounds.setLTRB(0, 0,
                       GrIntToScalar(drawState->getRenderTarget()->width()),
                       GrIntToScalar(drawState->getRenderTarget()->height()));
        GrMatrix vmi;
        if (drawState->getViewInverse(&vmi)) {
            vmi.mapRect(&bounds);
        }
        *vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop);
        *vert++ = GrPoint::Make(bounds.fLeft, bounds.fBottom);
        *vert++ = GrPoint::Make(bounds.fRight, bounds.fBottom);
        *vert++ = GrPoint::Make(bounds.fRight, bounds.fTop);
        subpathVertCount[subpath++] = 4;
    }

    GrAssert(subpath == subpathCnt);
    GrAssert((vert - base) <= maxPts);

    size_t count = vert - base;

    if (count < 3) {
        return true;
    }

    if (subpathCnt == 1 && !inverted && path.isConvex()) {
        if (antiAlias) {
            GrEdgeArray edges;
            GrMatrix inverse, matrix = drawState->getViewMatrix();
            drawState->getViewInverse(&inverse);

            count = computeEdgesAndIntersect(matrix, inverse, base, count, &edges, 0.0f);
            size_t maxEdges = target->getMaxEdges();
            if (count == 0) {
                return true;
            }
            if (count <= maxEdges) {
                // All edges fit; upload all edges and draw all verts as a fan
                target->setVertexSourceToArray(layout, base, count);
                drawState->setEdgeAAData(&edges[0], count);
                target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
            } else {
                // Upload "maxEdges" edges and verts at a time, and draw as
                // separate fans
                for (size_t i = 0; i < count - 2; i += maxEdges - 2) {
                    edges[i] = edges[0];
                    base[i] = base[0];
                    int size = GR_CT_MIN(count - i, maxEdges);
                    target->setVertexSourceToArray(layout, &base[i], size);
                    drawState->setEdgeAAData(&edges[i], size);
                    target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size);
                }
            }
            drawState->setEdgeAAData(NULL, 0);
        } else {
            target->setVertexSourceToArray(layout, base, count);
            target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
        }
        return true;
    }

    if (antiAlias) {
        // Run the tesselator once to get the boundaries.
        GrBoundaryTess btess(count, fill_type_to_glu_winding_rule(fill));
        btess.addVertices(base, subpathVertCount, subpathCnt);

        GrMatrix inverse, matrix = drawState->getViewMatrix();
        if (!drawState->getViewInverse(&inverse)) {
            return false;
        }

        if (btess.vertices().count() > USHRT_MAX) {
            return false;
        }

        // Inflate the boundary, and run the tesselator again to generate
        // interior polys.
        const GrPointArray& contourPoints = btess.contourPoints();
        const GrIndexArray& contours = btess.contours();
        GrEdgePolygonTess ptess(contourPoints.count(), GLU_TESS_WINDING_NONZERO, matrix);

        size_t i = 0;
        Sk_gluTessBeginPolygon(ptess.tess(), &ptess);
        for (int contour = 0; contour < contours.count(); ++contour) {
            int count = contours[contour];
            GrEdgeArray edges;
            int newCount = computeEdgesAndIntersect(matrix, inverse, &btess.contourPoints()[i], count, &edges, 1.0f);
            Sk_gluTessBeginContour(ptess.tess());
            for (int j = 0; j < newCount; j++) {
                ptess.addVertex(contourPoints[i + j], ptess.vertices().count());
            }
            i += count;
            Sk_gluTessEndContour(ptess.tess());
        }

        Sk_gluTessEndPolygon(ptess.tess());

        if (ptess.vertices().count() > USHRT_MAX) {
            return false;
        }

        // Draw the resulting polys and upload their edge data.
        drawState->enableState(GrDrawState::kEdgeAAConcave_StateBit);
        const GrPointArray& vertices = ptess.vertices();
        const GrIndexArray& indices = ptess.indices();
        const GrDrawState::Edge* edges = ptess.edges();
        GR_DEBUGASSERT(indices.count() % 3 == 0);
        for (int i = 0; i < indices.count(); i += 3) {
            GrPoint tri_verts[3];
            int index0 = indices[i];
            int index1 = indices[i + 1];
            int index2 = indices[i + 2];
            tri_verts[0] = vertices[index0];
            tri_verts[1] = vertices[index1];
            tri_verts[2] = vertices[index2];
            GrDrawState::Edge tri_edges[6];
            int t = 0;
            const GrDrawState::Edge& edge0 = edges[index0 * 2];
            const GrDrawState::Edge& edge1 = edges[index0 * 2 + 1];
            const GrDrawState::Edge& edge2 = edges[index1 * 2];
            const GrDrawState::Edge& edge3 = edges[index1 * 2 + 1];
            const GrDrawState::Edge& edge4 = edges[index2 * 2];
            const GrDrawState::Edge& edge5 = edges[index2 * 2 + 1];
            if (validEdge(edge0) && validEdge(edge1)) {
                tri_edges[t++] = edge0;
                tri_edges[t++] = edge1;
            }
            if (validEdge(edge2) && validEdge(edge3)) {
                tri_edges[t++] = edge2;
                tri_edges[t++] = edge3;
            }
            if (validEdge(edge4) && validEdge(edge5)) {
                tri_edges[t++] = edge4;
                tri_edges[t++] = edge5;
            }
            drawState->setEdgeAAData(&tri_edges[0], t);
            target->setVertexSourceToArray(layout, &tri_verts[0], 3);
            target->drawNonIndexed(kTriangles_PrimitiveType, 0, 3);
        }
        drawState->setEdgeAAData(NULL, 0);
        drawState->disableState(GrDrawState::kEdgeAAConcave_StateBit);
        return true;
    }

    GrPolygonTess ptess(count, fill_type_to_glu_winding_rule(fill));
    ptess.addVertices(base, subpathVertCount, subpathCnt);
    const GrPointArray& vertices = ptess.vertices();
    const GrIndexArray& indices = ptess.indices();
    if (indices.count() > 0) {
        target->setVertexSourceToArray(layout, vertices.begin(), vertices.count());
        target->setIndexSourceToArray(indices.begin(), indices.count());
        target->drawIndexed(kTriangles_PrimitiveType,
                            0,
                            0,
                            vertices.count(),
                            indices.count());
    }
    return true;
}
Exemplo n.º 10
0
////////////////////////////////////////////////////////////////////////////////
// sort out what kind of clip mask needs to be created: alpha, stencil,
// scissor, or entirely software
bool GrClipMaskManager::createClipMask(GrGpu* gpu, 
                                       const GrClip& clipIn,
                                       ScissoringSettings* scissorSettings) {

    GrAssert(scissorSettings);

    scissorSettings->fEnableScissoring = false;
    fClipMaskInStencil = false;
    fClipMaskInAlpha = false;

    GrDrawState* drawState = gpu->drawState();
    if (!drawState->isClipState()) {
        return true;
    }

    GrRenderTarget* rt = drawState->getRenderTarget();

    // GrDrawTarget should have filtered this for us
    GrAssert(NULL != rt);

#if GR_SW_CLIP
    if (create_mask_in_sw()) {
        // The clip geometry is complex enough that it will be more
        // efficient to create it entirely in software
        GrTexture* result = NULL;
        GrIRect bound;
        if (this->createSoftwareClipMask(gpu, clipIn, &result, &bound)) {
            fClipMaskInAlpha = true;

            setup_drawstate_aaclip(gpu, result, bound);
            return true;
        }
    }
#endif

#if GR_AA_CLIP
    // If MSAA is enabled use the (faster) stencil path for AA clipping
    // otherwise the alpha clip mask is our only option
    if (clipIn.requiresAA() && 0 == rt->numSamples()) {
        // Since we are going to create a destination texture of the correct
        // size for the mask (rather than being bound by the size of the
        // render target) we aren't going to use scissoring like the stencil
        // path does (see scissorSettings below)
        GrTexture* result = NULL;
        GrIRect bound;
        if (this->createAlphaClipMask(gpu, clipIn, &result, &bound)) {
            fClipMaskInAlpha = true;

            setup_drawstate_aaclip(gpu, result, bound);
            return true;
        }

        // if alpha clip mask creation fails fall through to the stencil
        // buffer method
    }
#endif // GR_AA_CLIP

    GrRect bounds;
    GrRect rtRect;
    rtRect.setLTRB(0, 0,
                    GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
    if (clipIn.hasConservativeBounds()) {
        bounds = clipIn.getConservativeBounds();
        if (!bounds.intersect(rtRect)) {
            bounds.setEmpty();
        }
    } else {
        bounds = rtRect;
    }

    bounds.roundOut(&scissorSettings->fScissorRect);
    if  (scissorSettings->fScissorRect.isEmpty()) {
        scissorSettings->fScissorRect.setLTRB(0,0,0,0);
        // TODO: I think we can do an early exit here - after refactoring try:
        //  set fEnableScissoring to true but leave fClipMaskInStencil false
        //  and return - everything is going to be scissored away anyway!
    }
    scissorSettings->fEnableScissoring = true;

    // use the stencil clip if we can't represent the clip as a rectangle.
    fClipMaskInStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
                         !bounds.isEmpty();

    if (fClipMaskInStencil) {
        return this->createStencilClipMask(gpu, clipIn, bounds, scissorSettings);
    }

    return true;
}
Exemplo n.º 11
0
bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path,
                                               GrPathFill fill,
                                               GrDrawTarget* target,
                                               bool antiAlias) {
    GrAssert(!antiAlias);
    GrAssert(kHairLine_GrPathFill != fill);

    GrDrawState* drawState = target->drawState();
    GrAssert(drawState->getStencil().isDisabled());

    SkAutoTUnref<GrPath> p(fGpu->createPath(path));

    GrPathFill nonInvertedFill = GrNonInvertedFill(fill);
    target->stencilPath(p, nonInvertedFill);

    // TODO: Use built in cover operation rather than a rect draw. This will require making our
    // fragment shaders be able to eat varyings generated by a matrix.

    // fill the path, zero out the stencil
    GrRect bounds = p->getBounds();
    GrScalar bloat = drawState->getViewMatrix().getMaxStretch() * GR_ScalarHalf;
    GrDrawState::AutoDeviceCoordDraw adcd;

    if (nonInvertedFill == fill) {
        GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
            kZero_StencilOp,
            kZero_StencilOp,
            kNotEqual_StencilFunc,
            0xffff,
            0x0000,
            0xffff);
        *drawState->stencil() = kStencilPass;
    } else {
        GR_STATIC_CONST_SAME_STENCIL(kInvertedStencilPass,
            kZero_StencilOp,
            kZero_StencilOp,
            // We know our rect will hit pixels outside the clip and the user bits will be 0
            // outside the clip. So we can't just fill where the user bits are 0. We also need to
            // check that the clip bit is set.
            kEqualIfInClip_StencilFunc,
            0xffff,
            0x0000,
            0xffff);
        GrMatrix vmi;
        bounds.setLTRB(0, 0,
                       GrIntToScalar(drawState->getRenderTarget()->width()),
                       GrIntToScalar(drawState->getRenderTarget()->height()));
        // mapRect through persp matrix may not be correct
        if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) {
            vmi.mapRect(&bounds);
            // theoretically could set bloat = 0, instead leave it because of matrix inversion
            // precision.
        } else {
            adcd.set(drawState);
            bloat = 0;
        }
        *drawState->stencil() = kInvertedStencilPass;
    }
    bounds.outset(bloat, bloat);
    target->drawSimpleRect(bounds, NULL);
    target->drawState()->stencil()->setDisabled();
    return true;
}
Exemplo n.º 12
0
void GrDefaultPathRenderer::onDrawPath(GrDrawTarget* target,
                                       GrDrawTarget::StageBitfield stages,
                                       const GrPath& path,
                                       GrPathFill fill,
                                       const GrPoint* translate,
                                       bool stencilOnly) {

    GrDrawTarget::AutoStateRestore asr(target);
    bool colorWritesWereDisabled = target->isColorWriteDisabled();
    // face culling doesn't make sense here
    GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace());

    GrMatrix viewM = target->getViewMatrix();
    // In order to tesselate the path we get a bound on how much the matrix can
    // stretch when mapping to screen coordinates.
    GrScalar stretch = viewM.getMaxStretch();
    bool useStretch = stretch > 0;
    GrScalar tol = fCurveTolerance;

    if (!useStretch) {
        // TODO: deal with perspective in some better way.
        tol /= 10;
    } else {
        tol = GrScalarDiv(tol, stretch);
    }
    GrScalar tolSqd = GrMul(tol, tol);

    int subpathCnt;
    int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol);

    GrVertexLayout layout = 0;
    for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
        if ((1 << s) & stages) {
            layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
        }
    }

    // add 4 to hold the bounding rect
    GrDrawTarget::AutoReleaseGeometry arg(target, layout, maxPts + 4, 0);

    GrPoint* base = (GrPoint*) arg.vertices();
    GrPoint* vert = base;
    GrPoint* subpathBase = base;

    GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);

    // TODO: use primitve restart if available rather than multiple draws
    GrPrimitiveType             type;
    int                         passCount = 0;
    const GrStencilSettings*    passes[3];
    GrDrawTarget::DrawFace      drawFace[3];
    bool                        reverse = false;
    bool                        lastPassIsBounds;

    if (kHairLine_PathFill == fill) {
        type = kLineStrip_PrimitiveType;
        passCount = 1;
        if (stencilOnly) {
            passes[0] = &gDirectToStencil;
        } else {
            passes[0] = NULL;
        }
        lastPassIsBounds = false;
        drawFace[0] = GrDrawTarget::kBoth_DrawFace;
    } else {
        type = kTriangleFan_PrimitiveType;
        if (single_pass_path(*target, path, fill)) {
            passCount = 1;
            if (stencilOnly) {
                passes[0] = &gDirectToStencil;
            } else {
                passes[0] = NULL;
            }
            drawFace[0] = GrDrawTarget::kBoth_DrawFace;
            lastPassIsBounds = false;
        } else {
            switch (fill) {
                case kInverseEvenOdd_PathFill:
                    reverse = true;
                    // fallthrough
                case kEvenOdd_PathFill:
                    passes[0] = &gEOStencilPass;
                    if (stencilOnly) {
                        passCount = 1;
                        lastPassIsBounds = false;
                    } else {
                        passCount = 2;
                        lastPassIsBounds = true;
                        if (reverse) {
                            passes[1] = &gInvEOColorPass;
                        } else {
                            passes[1] = &gEOColorPass;
                        }
                    }
                    drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
                    break;

                case kInverseWinding_PathFill:
                    reverse = true;
                    // fallthrough
                case kWinding_PathFill:
                    if (fSeparateStencil) {
                        if (fStencilWrapOps) {
                            passes[0] = &gWindStencilSeparateWithWrap;
                        } else {
                            passes[0] = &gWindStencilSeparateNoWrap;
                        }
                        passCount = 2;
                        drawFace[0] = GrDrawTarget::kBoth_DrawFace;
                    } else {
                        if (fStencilWrapOps) {
                            passes[0] = &gWindSingleStencilWithWrapInc;
                            passes[1] = &gWindSingleStencilWithWrapDec;
                        } else {
                            passes[0] = &gWindSingleStencilNoWrapInc;
                            passes[1] = &gWindSingleStencilNoWrapDec;
                        }
                        // which is cw and which is ccw is arbitrary.
                        drawFace[0] = GrDrawTarget::kCW_DrawFace;
                        drawFace[1] = GrDrawTarget::kCCW_DrawFace;
                        passCount = 3;
                    }
                    if (stencilOnly) {
                        lastPassIsBounds = false;
                        --passCount;
                    } else {
                        lastPassIsBounds = true;
                        drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
                        if (reverse) {
                            passes[passCount-1] = &gInvWindColorPass;
                        } else {
                            passes[passCount-1] = &gWindColorPass;
                        }
                    }
                    break;
                default:
                    GrAssert(!"Unknown path fill!");
                    return;
            }
        }
    }

    GrPoint pts[4];

    bool first = true;
    int subpath = 0;

    SkPath::Iter iter(path, false);

    for (;;) {
        GrPathCmd cmd = (GrPathCmd)iter.next(pts);
        switch (cmd) {
            case kMove_PathCmd:
                if (!first) {
                    subpathVertCount[subpath] = vert-subpathBase;
                    subpathBase = vert;
                    ++subpath;
                }
                *vert = pts[0];
                vert++;
                break;
            case kLine_PathCmd:
                *vert = pts[1];
                vert++;
                break;
            case kQuadratic_PathCmd: {
                GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
                                                     tolSqd, &vert,
                                                     GrPathUtils::quadraticPointCount(pts, tol));
                break;
            }
            case kCubic_PathCmd: {
                GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
                                                 tolSqd, &vert,
                                                 GrPathUtils::cubicPointCount(pts, tol));
                break;
            }
            case kClose_PathCmd:
                break;
            case kEnd_PathCmd:
                subpathVertCount[subpath] = vert-subpathBase;
                ++subpath; // this could be only in debug
                goto FINISHED;
        }
        first = false;
    }
FINISHED:
    GrAssert(subpath == subpathCnt);
    GrAssert((vert - base) <= maxPts);

    if (translate) {
        int count = vert - base;
        for (int i = 0; i < count; i++) {
            base[i].offset(translate->fX, translate->fY);
        }
    }

    // if we're stenciling we will follow with a pass that draws
    // a bounding rect to set the color. We're stenciling when
    // passCount > 1.
    const int& boundVertexStart = maxPts;
    GrPoint* boundsVerts = base + boundVertexStart;
    if (lastPassIsBounds) {
        GrRect bounds;
        if (reverse) {
            GrAssert(NULL != target->getRenderTarget());
            // draw over the whole world.
            bounds.setLTRB(0, 0,
                           GrIntToScalar(target->getRenderTarget()->width()),
                           GrIntToScalar(target->getRenderTarget()->height()));
            GrMatrix vmi;
            if (target->getViewInverse(&vmi)) {
                vmi.mapRect(&bounds);
            }
        } else {
            bounds.setBounds((GrPoint*)base, vert - base);
        }
        boundsVerts[0].setRectFan(bounds.fLeft, bounds.fTop, bounds.fRight,
                                  bounds.fBottom);
    }

    for (int p = 0; p < passCount; ++p) {
        target->setDrawFace(drawFace[p]);
        if (NULL != passes[p]) {
            target->setStencil(*passes[p]);
        }

        if (lastPassIsBounds && (p == passCount-1)) {
            if (!colorWritesWereDisabled) {
                target->disableState(GrDrawTarget::kNoColorWrites_StateBit);
            }
            target->drawNonIndexed(kTriangleFan_PrimitiveType,
                                   boundVertexStart, 4);

        } else {
            if (passCount > 1) {
                target->enableState(GrDrawTarget::kNoColorWrites_StateBit);
            }
            int baseVertex = 0;
            for (int sp = 0; sp < subpathCnt; ++sp) {
                target->drawNonIndexed(type,
                                      baseVertex,
                                      subpathVertCount[sp]);
                baseVertex += subpathVertCount[sp];
            }
        }
    }
}
Exemplo n.º 13
0
bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
    const GrIRect* r = NULL;
    GrIRect clipRect;

    // we check this early because we need a valid
    // render target to setup stencil clipping
    // before even going into flushGraphicsState
    if (NULL == fCurrDrawState.fRenderTarget) {
        GrAssert(!"No render target bound.");
        return false;
    }

    if (fCurrDrawState.fFlagBits & kClip_StateBit) {
        GrRenderTarget& rt = *fCurrDrawState.fRenderTarget;

        GrRect bounds;
        GrRect rtRect;
        rtRect.setLTRB(0, 0,
                       GrIntToScalar(rt.width()), GrIntToScalar(rt.height()));
        if (fClip.hasConservativeBounds()) {
            bounds = fClip.getConservativeBounds();
            bounds.intersectWith(rtRect);
        } else {
            bounds = rtRect;
        }

        bounds.roundOut(&clipRect);
        if  (clipRect.isEmpty()) {
            clipRect.setLTRB(0,0,0,0);
        }
        r = &clipRect;

        fClipState.fClipInStencil = !fClip.isRect() &&
                                    !fClip.isEmpty() &&
                                    !bounds.isEmpty();

        if (fClipState.fClipInStencil &&
            (fClipState.fClipIsDirty ||
             fClip != rt.fLastStencilClip)) {

            rt.fLastStencilClip = fClip;
            // we set the current clip to the bounds so that our recursive
            // draws are scissored to them. We use the copy of the complex clip
            // in the rt to render
            const GrClip& clip = rt.fLastStencilClip;
            fClip.setFromRect(bounds);

            AutoStateRestore asr(this);
            AutoInternalDrawGeomRestore aidgr(this);

            this->setViewMatrix(GrMatrix::I());
            this->eraseStencilClip(clipRect);
            this->flushScissor(NULL);
#if !VISUALIZE_COMPLEX_CLIP
            this->enableState(kNoColorWrites_StateBit);
#else
            this->disableState(kNoColorWrites_StateBit);
#endif
            int count = clip.getElementCount();
            int clipBit = rt.stencilBits();
            clipBit = (1 << (clipBit-1));

            // often we'll see the first two elements of the clip are
            // the full rt size and another element intersected with it.
            // We can skip the first full-size rect and save a big rect draw.
            int firstElement = 0;
            if (clip.getElementCount() > 1 &&
                kRect_ClipType == clip.getElementType(0) &&
                kIntersect_SetOp == clip.getOp(1)&&
                clip.getRect(0).contains(bounds)) {
                firstElement = 1;
            }

            // walk through each clip element and perform its set op
            // with the existing clip.
            for (int c = firstElement; c < count; ++c) {
                GrPathFill fill;
                // enabled at bottom of loop
                this->disableState(kModifyStencilClip_StateBit);

                bool canDrawDirectToClip;
                if (kRect_ClipType == clip.getElementType(c)) {
                    canDrawDirectToClip = true;
                    fill = kEvenOdd_PathFill;
                } else {
                    fill = clip.getPathFill(c);
                    GrPathRenderer* pr = this->getPathRenderer();
                    canDrawDirectToClip = pr->requiresStencilPass(this, clip.getPath(c), fill);
                }

                GrSetOp op = firstElement == c ? kReplace_SetOp : clip.getOp(c);
                int passes;
                GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];

                canDrawDirectToClip = GrStencilSettings::GetClipPasses(op, canDrawDirectToClip,
                                                                       clipBit, IsFillInverted(fill),
                                                                       &passes, stencilSettings);

                // draw the element to the client stencil bits if necessary
                if (!canDrawDirectToClip) {
                    if (kRect_ClipType == clip.getElementType(c)) {
                        static const GrStencilSettings gDrawToStencil = {
                            kIncClamp_StencilOp, kIncClamp_StencilOp,
                            kIncClamp_StencilOp, kIncClamp_StencilOp,
                            kAlways_StencilFunc, kAlways_StencilFunc,
                            0xffffffff,          0xffffffff,
                            0x00000000,          0x00000000,
                            0xffffffff,          0xffffffff,
                        };
                        this->setStencil(gDrawToStencil);
                        SET_RANDOM_COLOR
                        this->drawSimpleRect(clip.getRect(c), NULL, 0);
                    } else {
                        SET_RANDOM_COLOR
                        getPathRenderer()->drawPathToStencil(this, clip.getPath(c),
                                                             NonInvertedFill(fill),
                                                             NULL);
                    }
                }

                // now we modify the clip bit by rendering either the clip
                // element directly or a bounding rect of the entire clip.
                this->enableState(kModifyStencilClip_StateBit);
                for (int p = 0; p < passes; ++p) {
                    this->setStencil(stencilSettings[p]);
                    if (canDrawDirectToClip) {
                        if (kRect_ClipType == clip.getElementType(c)) {
                            SET_RANDOM_COLOR
                            this->drawSimpleRect(clip.getRect(c), NULL, 0);
                        } else {
                            SET_RANDOM_COLOR
                            getPathRenderer()->drawPath(this, 0,
                                                        clip.getPath(c),
                                                        fill, NULL);
                        }
                    } else {
                        SET_RANDOM_COLOR
                        this->drawSimpleRect(bounds, 0, NULL);
                    }
                }
            }
            fClip = clip;
            // recusive draws would have disabled this.
            fClipState.fClipInStencil = true;
        }

        fClipState.fClipIsDirty = false;
    }

    // Must flush the scissor after graphics state
    if (!this->flushGraphicsState(type)) {
        return false;
    }
    this->flushScissor(r);
    return true;
}
Exemplo n.º 14
0
void GrGpuGL::flushViewMatrix(DrawType type) {
    const GrGLRenderTarget* rt = static_cast<const GrGLRenderTarget*>(this->getDrawState().getRenderTarget());
    SkISize viewportSize;
    const GrGLIRect& viewport = rt->getViewport();
    viewportSize.set(viewport.fWidth, viewport.fHeight);

    const GrMatrix& vm = this->getDrawState().getViewMatrix();

    if (kStencilPath_DrawType == type) {
        if (fHWPathMatrixState.fViewMatrix != vm ||
            fHWPathMatrixState.fRTSize != viewportSize) {
            // rescale the coords from skia's "device" coords to GL's normalized coords,
            // and perform a y-flip.
            GrMatrix m;
            m.setScale(GrIntToScalar(2) / rt->width(), GrIntToScalar(-2) / rt->height());
            m.postTranslate(-GR_Scalar1, GR_Scalar1);
            m.preConcat(vm);

            // GL wants a column-major 4x4.
            GrGLfloat mv[]  = {
                // col 0
                GrScalarToFloat(m[GrMatrix::kMScaleX]),
                GrScalarToFloat(m[GrMatrix::kMSkewY]),
                0,
                GrScalarToFloat(m[GrMatrix::kMPersp0]),

                // col 1
                GrScalarToFloat(m[GrMatrix::kMSkewX]),
                GrScalarToFloat(m[GrMatrix::kMScaleY]),
                0,
                GrScalarToFloat(m[GrMatrix::kMPersp1]),

                // col 2
                0, 0, 0, 0,

                // col3
                GrScalarToFloat(m[GrMatrix::kMTransX]),
                GrScalarToFloat(m[GrMatrix::kMTransY]),
                0.0f,
                GrScalarToFloat(m[GrMatrix::kMPersp2])
            };
            GL_CALL(MatrixMode(GR_GL_PROJECTION));
            GL_CALL(LoadMatrixf(mv));
            fHWPathMatrixState.fViewMatrix = vm;
            fHWPathMatrixState.fRTSize = viewportSize;
        }
    } else if (!fCurrentProgram->fViewMatrix.cheapEqualTo(vm) ||
               fCurrentProgram->fViewportSize != viewportSize) {
        GrMatrix m;
        m.setAll(
            GrIntToScalar(2) / viewportSize.fWidth, 0, -GR_Scalar1,
            0,-GrIntToScalar(2) / viewportSize.fHeight, GR_Scalar1,
            0, 0, GrMatrix::I()[8]);
        m.setConcat(m, vm);

        // ES doesn't allow you to pass true to the transpose param,
        // so do our own transpose
        GrGLfloat mt[]  = {
            GrScalarToFloat(m[GrMatrix::kMScaleX]),
            GrScalarToFloat(m[GrMatrix::kMSkewY]),
            GrScalarToFloat(m[GrMatrix::kMPersp0]),
            GrScalarToFloat(m[GrMatrix::kMSkewX]),
            GrScalarToFloat(m[GrMatrix::kMScaleY]),
            GrScalarToFloat(m[GrMatrix::kMPersp1]),
            GrScalarToFloat(m[GrMatrix::kMTransX]),
            GrScalarToFloat(m[GrMatrix::kMTransY]),
            GrScalarToFloat(m[GrMatrix::kMPersp2])
        };
        fCurrentProgram->fUniformManager.setMatrix3f(fCurrentProgram->fUniforms.fViewMatrixUni, mt);
        fCurrentProgram->fViewMatrix = vm;
        fCurrentProgram->fViewportSize = viewportSize;
    }
}
Exemplo n.º 15
0
bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path,
                                             GrPathFill fill,
                                             GrDrawTarget* target,
                                             bool stencilOnly) {

    GrMatrix viewM = target->getDrawState().getViewMatrix();
    GrScalar tol = GR_Scalar1;
    tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds());

    int vertexCnt;
    int indexCnt;
    GrPrimitiveType primType;
    GrDrawTarget::AutoReleaseGeometry arg;
    if (!this->createGeom(path,
                          fill,
                          tol,
                          target,
                          &primType,
                          &vertexCnt,
                          &indexCnt,
                          &arg)) {
        return false;
    }

    GrAssert(NULL != target);
    GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit);
    GrDrawState* drawState = target->drawState();
    bool colorWritesWereDisabled = drawState->isColorWriteDisabled();
    // face culling doesn't make sense here
    GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace());

    int                         passCount = 0;
    const GrStencilSettings*    passes[3];
    GrDrawState::DrawFace       drawFace[3];
    bool                        reverse = false;
    bool                        lastPassIsBounds;

    if (kHairLine_GrPathFill == fill) {
        passCount = 1;
        if (stencilOnly) {
            passes[0] = &gDirectToStencil;
        } else {
            passes[0] = NULL;
        }
        lastPassIsBounds = false;
        drawFace[0] = GrDrawState::kBoth_DrawFace;
    } else {
        if (single_pass_path(path, fill)) {
            passCount = 1;
            if (stencilOnly) {
                passes[0] = &gDirectToStencil;
            } else {
                passes[0] = NULL;
            }
            drawFace[0] = GrDrawState::kBoth_DrawFace;
            lastPassIsBounds = false;
        } else {
            switch (fill) {
                case kInverseEvenOdd_GrPathFill:
                    reverse = true;
                    // fallthrough
                case kEvenOdd_GrPathFill:
                    passes[0] = &gEOStencilPass;
                    if (stencilOnly) {
                        passCount = 1;
                        lastPassIsBounds = false;
                    } else {
                        passCount = 2;
                        lastPassIsBounds = true;
                        if (reverse) {
                            passes[1] = &gInvEOColorPass;
                        } else {
                            passes[1] = &gEOColorPass;
                        }
                    }
                    drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace;
                    break;

                case kInverseWinding_GrPathFill:
                    reverse = true;
                    // fallthrough
                case kWinding_GrPathFill:
                    if (fSeparateStencil) {
                        if (fStencilWrapOps) {
                            passes[0] = &gWindStencilSeparateWithWrap;
                        } else {
                            passes[0] = &gWindStencilSeparateNoWrap;
                        }
                        passCount = 2;
                        drawFace[0] = GrDrawState::kBoth_DrawFace;
                    } else {
                        if (fStencilWrapOps) {
                            passes[0] = &gWindSingleStencilWithWrapInc;
                            passes[1] = &gWindSingleStencilWithWrapDec;
                        } else {
                            passes[0] = &gWindSingleStencilNoWrapInc;
                            passes[1] = &gWindSingleStencilNoWrapDec;
                        }
                        // which is cw and which is ccw is arbitrary.
                        drawFace[0] = GrDrawState::kCW_DrawFace;
                        drawFace[1] = GrDrawState::kCCW_DrawFace;
                        passCount = 3;
                    }
                    if (stencilOnly) {
                        lastPassIsBounds = false;
                        --passCount;
                    } else {
                        lastPassIsBounds = true;
                        drawFace[passCount-1] = GrDrawState::kBoth_DrawFace;
                        if (reverse) {
                            passes[passCount-1] = &gInvWindColorPass;
                        } else {
                            passes[passCount-1] = &gWindColorPass;
                        }
                    }
                    break;
                default:
                    GrAssert(!"Unknown path fFill!");
                    return false;
            }
        }
    }

    {
    for (int p = 0; p < passCount; ++p) {
        drawState->setDrawFace(drawFace[p]);
        if (NULL != passes[p]) {
            *drawState->stencil() = *passes[p];
        }

        if (lastPassIsBounds && (p == passCount-1)) {
            if (!colorWritesWereDisabled) {
                drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
            }
            GrRect bounds;
            GrDrawState::AutoDeviceCoordDraw adcd;
            if (reverse) {
                GrAssert(NULL != drawState->getRenderTarget());
                // draw over the whole world.
                bounds.setLTRB(0, 0,
                               GrIntToScalar(drawState->getRenderTarget()->width()),
                               GrIntToScalar(drawState->getRenderTarget()->height()));
                GrMatrix vmi;
                // mapRect through persp matrix may not be correct
                if (!drawState->getViewMatrix().hasPerspective() &&
                    drawState->getViewInverse(&vmi)) {
                    vmi.mapRect(&bounds);
                } else {
                    adcd.set(drawState);
                }
            } else {
                bounds = path.getBounds();
            }
            GrDrawTarget::AutoGeometryPush agp(target);
            target->drawSimpleRect(bounds, NULL);
        } else {
            if (passCount > 1) {
                drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
            }
            if (indexCnt) {
                target->drawIndexed(primType, 0, 0,
                                    vertexCnt, indexCnt);
            } else {
                target->drawNonIndexed(primType, 0, vertexCnt);
            }
        }
    }
    }
    return true;
}
Exemplo n.º 16
0
bool GrGpu::setupClipAndFlushState(GrPrimitiveType type) {
    const GrIRect* r = NULL;
    GrIRect clipRect;

    GrDrawState* drawState = this->drawState();
    const GrRenderTarget* rt = drawState->getRenderTarget();

    // GrDrawTarget should have filtered this for us
    GrAssert(NULL != rt);

    if (drawState->isClipState()) {

        GrRect bounds;
        GrRect rtRect;
        rtRect.setLTRB(0, 0,
                       GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
        if (fClip.hasConservativeBounds()) {
            bounds = fClip.getConservativeBounds();
            if (!bounds.intersect(rtRect)) {
                bounds.setEmpty();
            }
        } else {
            bounds = rtRect;
        }

        bounds.roundOut(&clipRect);
        if  (clipRect.isEmpty()) {
            clipRect.setLTRB(0,0,0,0);
        }
        r = &clipRect;

        // use the stencil clip if we can't represent the clip as a rectangle.
        fClipInStencil = !fClip.isRect() && !fClip.isEmpty() && 
                         !bounds.isEmpty();

        // TODO: dynamically attach a SB when needed.
        GrStencilBuffer* stencilBuffer = rt->getStencilBuffer();
        if (fClipInStencil && NULL == stencilBuffer) {
            return false;
        }

        if (fClipInStencil &&
            stencilBuffer->mustRenderClip(fClip, rt->width(), rt->height())) {

            stencilBuffer->setLastClip(fClip, rt->width(), rt->height());

            // we set the current clip to the bounds so that our recursive
            // draws are scissored to them. We use the copy of the complex clip
            // we just stashed on the SB to render from. We set it back after
            // we finish drawing it into the stencil.
            const GrClip& clip = stencilBuffer->getLastClip();
            fClip.setFromRect(bounds);

            AutoStateRestore asr(this);
            AutoGeometryPush agp(this);

            drawState->setViewMatrix(GrMatrix::I());
            this->flushScissor(NULL);
#if !VISUALIZE_COMPLEX_CLIP
            drawState->enableState(GrDrawState::kNoColorWrites_StateBit);
#else
            drawState->disableState(GrDrawState::kNoColorWrites_StateBit);
#endif
            int count = clip.getElementCount();
            int clipBit = stencilBuffer->bits();
            SkASSERT((clipBit <= 16) &&
                     "Ganesh only handles 16b or smaller stencil buffers");
            clipBit = (1 << (clipBit-1));
            
            bool clearToInside;
            GrSetOp startOp = kReplace_SetOp; // suppress warning
            int start = process_initial_clip_elements(clip,
                                                      rtRect,
                                                      &clearToInside,
                                                      &startOp);

            this->clearStencilClip(clipRect, clearToInside);

            // walk through each clip element and perform its set op
            // with the existing clip.
            for (int c = start; c < count; ++c) {
                GrPathFill fill;
                bool fillInverted;
                // enabled at bottom of loop
                drawState->disableState(kModifyStencilClip_StateBit);

                bool canRenderDirectToStencil; // can the clip element be drawn
                                               // directly to the stencil buffer
                                               // with a non-inverted fill rule
                                               // without extra passes to
                                               // resolve in/out status.

                GrPathRenderer* pr = NULL;
                const GrPath* clipPath = NULL;
                GrPathRenderer::AutoClearPath arp;
                if (kRect_ClipType == clip.getElementType(c)) {
                    canRenderDirectToStencil = true;
                    fill = kEvenOdd_PathFill;
                    fillInverted = false;
                    // there is no point in intersecting a screen filling
                    // rectangle.
                    if (kIntersect_SetOp == clip.getOp(c) &&
                        clip.getRect(c).contains(rtRect)) {
                        continue;
                    }
                } else {
                    fill = clip.getPathFill(c);
                    fillInverted = GrIsFillInverted(fill);
                    fill = GrNonInvertedFill(fill);
                    clipPath = &clip.getPath(c);
                    pr = this->getClipPathRenderer(*clipPath, fill);
                    if (NULL == pr) {
                        fClipInStencil = false;
                        fClip = clip;
                        return false;
                    }
                    canRenderDirectToStencil =
                        !pr->requiresStencilPass(this, *clipPath, fill);
                    arp.set(pr, this, clipPath, fill, false, NULL);
                }

                GrSetOp op = (c == start) ? startOp : clip.getOp(c);
                int passes;
                GrStencilSettings stencilSettings[GrStencilSettings::kMaxStencilClipPasses];

                bool canDrawDirectToClip; // Given the renderer, the element,
                                          // fill rule, and set operation can
                                          // we render the element directly to
                                          // stencil bit used for clipping.
                canDrawDirectToClip =
                    GrStencilSettings::GetClipPasses(op,
                                                     canRenderDirectToStencil,
                                                     clipBit,
                                                     fillInverted,
                                                     &passes, stencilSettings);

                // draw the element to the client stencil bits if necessary
                if (!canDrawDirectToClip) {
                    GR_STATIC_CONST_SAME_STENCIL(gDrawToStencil,
                        kIncClamp_StencilOp,
                        kIncClamp_StencilOp,
                        kAlways_StencilFunc,
                        0xffff,
                        0x0000,
                        0xffff);
                    SET_RANDOM_COLOR
                    if (kRect_ClipType == clip.getElementType(c)) {
                        *drawState->stencil() = gDrawToStencil;
                        this->drawSimpleRect(clip.getRect(c), NULL, 0);
                    } else {
                        if (canRenderDirectToStencil) {
                            *drawState->stencil() = gDrawToStencil;
                            pr->drawPath(0);
                        } else {
                            pr->drawPathToStencil();
                        }
                    }
                }

                // now we modify the clip bit by rendering either the clip
                // element directly or a bounding rect of the entire clip.
                drawState->enableState(kModifyStencilClip_StateBit);
                for (int p = 0; p < passes; ++p) {
                    *drawState->stencil() = stencilSettings[p];
                    if (canDrawDirectToClip) {
                        if (kRect_ClipType == clip.getElementType(c)) {
                            SET_RANDOM_COLOR
                            this->drawSimpleRect(clip.getRect(c), NULL, 0);
                        } else {
                            SET_RANDOM_COLOR
                            pr->drawPath(0);
                        }
                    } else {
                        SET_RANDOM_COLOR
                        this->drawSimpleRect(bounds, NULL, 0);
                    }
                }
            }
Exemplo n.º 17
0
void GrDefaultPathRenderer::onDrawPath(GrDrawTarget::StageBitfield stages,
                                       bool stencilOnly) {

    GrMatrix viewM = fTarget->getViewMatrix();
    GrScalar tol = GR_Scalar1;
    tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, fPath->getBounds());

    // FIXME: It's really dumb that we recreate the verts for a new vertex
    // layout. We only do that because the GrDrawTarget API doesn't allow
    // us to change the vertex layout after reserveVertexSpace(). We won't
    // actually change the vertex data when the layout changes since all the
    // stages reference the positions (rather than having separate tex coords)
    // and we don't ever have per-vert colors. In practice our call sites
    // won't change the stages in use inside a setPath / removePath pair. But
    // it is a silly limitation of the GrDrawTarget design that should be fixed.
    if (tol != fPreviousSrcTol ||
        stages != fPreviousStages) {
        if (!this->createGeom(tol, stages)) {
            return;
        }
    }

    GrAssert(NULL != fTarget);
    GrDrawTarget::AutoStateRestore asr(fTarget);
    bool colorWritesWereDisabled = fTarget->isColorWriteDisabled();
    // face culling doesn't make sense here
    GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());

    int                         passCount = 0;
    const GrStencilSettings*    passes[3];
    GrDrawTarget::DrawFace      drawFace[3];
    bool                        reverse = false;
    bool                        lastPassIsBounds;

    if (kHairLine_PathFill == fFill) {
        passCount = 1;
        if (stencilOnly) {
            passes[0] = &gDirectToStencil;
        } else {
            passes[0] = NULL;
        }
        lastPassIsBounds = false;
        drawFace[0] = GrDrawTarget::kBoth_DrawFace;
    } else {
        if (single_pass_path(*fTarget, *fPath, fFill)) {
            passCount = 1;
            if (stencilOnly) {
                passes[0] = &gDirectToStencil;
            } else {
                passes[0] = NULL;
            }
            drawFace[0] = GrDrawTarget::kBoth_DrawFace;
            lastPassIsBounds = false;
        } else {
            switch (fFill) {
                case kInverseEvenOdd_PathFill:
                    reverse = true;
                    // fallthrough
                case kEvenOdd_PathFill:
                    passes[0] = &gEOStencilPass;
                    if (stencilOnly) {
                        passCount = 1;
                        lastPassIsBounds = false;
                    } else {
                        passCount = 2;
                        lastPassIsBounds = true;
                        if (reverse) {
                            passes[1] = &gInvEOColorPass;
                        } else {
                            passes[1] = &gEOColorPass;
                        }
                    }
                    drawFace[0] = drawFace[1] = GrDrawTarget::kBoth_DrawFace;
                    break;

                case kInverseWinding_PathFill:
                    reverse = true;
                    // fallthrough
                case kWinding_PathFill:
                    if (fSeparateStencil) {
                        if (fStencilWrapOps) {
                            passes[0] = &gWindStencilSeparateWithWrap;
                        } else {
                            passes[0] = &gWindStencilSeparateNoWrap;
                        }
                        passCount = 2;
                        drawFace[0] = GrDrawTarget::kBoth_DrawFace;
                    } else {
                        if (fStencilWrapOps) {
                            passes[0] = &gWindSingleStencilWithWrapInc;
                            passes[1] = &gWindSingleStencilWithWrapDec;
                        } else {
                            passes[0] = &gWindSingleStencilNoWrapInc;
                            passes[1] = &gWindSingleStencilNoWrapDec;
                        }
                        // which is cw and which is ccw is arbitrary.
                        drawFace[0] = GrDrawTarget::kCW_DrawFace;
                        drawFace[1] = GrDrawTarget::kCCW_DrawFace;
                        passCount = 3;
                    }
                    if (stencilOnly) {
                        lastPassIsBounds = false;
                        --passCount;
                    } else {
                        lastPassIsBounds = true;
                        drawFace[passCount-1] = GrDrawTarget::kBoth_DrawFace;
                        if (reverse) {
                            passes[passCount-1] = &gInvWindColorPass;
                        } else {
                            passes[passCount-1] = &gWindColorPass;
                        }
                    }
                    break;
                default:
                    GrAssert(!"Unknown path fFill!");
                    return;
            }
        }
    }

    {
    for (int p = 0; p < passCount; ++p) {
        fTarget->setDrawFace(drawFace[p]);
        if (NULL != passes[p]) {
            fTarget->setStencil(*passes[p]);
        }

        if (lastPassIsBounds && (p == passCount-1)) {
            if (!colorWritesWereDisabled) {
                fTarget->disableState(GrDrawTarget::kNoColorWrites_StateBit);
            }
            GrRect bounds;
            if (reverse) {
                GrAssert(NULL != fTarget->getRenderTarget());
                // draw over the whole world.
                bounds.setLTRB(0, 0,
                               GrIntToScalar(fTarget->getRenderTarget()->width()),
                               GrIntToScalar(fTarget->getRenderTarget()->height()));
                GrMatrix vmi;
                // mapRect through persp matrix may not be correct
                if (!fTarget->getViewMatrix().hasPerspective() &&
                    fTarget->getViewInverse(&vmi)) {
                    vmi.mapRect(&bounds);
                } else {
                    if (stages) {
                        if (!fTarget->getViewInverse(&vmi)) {
                            GrPrintf("Could not invert matrix.");
                            return;
                        }
                        fTarget->preConcatSamplerMatrices(stages, vmi);
                    }
                    fTarget->setViewMatrix(GrMatrix::I());
                }
            } else {
                bounds = fPath->getBounds();
                bounds.offset(fTranslate);
            }
            GrDrawTarget::AutoGeometryPush agp(fTarget);
            fTarget->drawSimpleRect(bounds, NULL, stages);
        } else {
            if (passCount > 1) {
                fTarget->enableState(GrDrawTarget::kNoColorWrites_StateBit);
            }
            if (fUseIndexedDraw) {
                fTarget->drawIndexed(fPrimitiveType, 0, 0, 
                                     fVertexCnt, fIndexCnt);
            } else {
                int baseVertex = 0;
                for (int sp = 0; sp < fSubpathCount; ++sp) {
                    fTarget->drawNonIndexed(fPrimitiveType, baseVertex,
                                            fSubpathVertCount[sp]);
                    baseVertex += fSubpathVertCount[sp];
                }
            }
        }
    }
    }
}
Exemplo n.º 18
0
////////////////////////////////////////////////////////////////////////////////
// sort out what kind of clip mask needs to be created: alpha, stencil,
// scissor, or entirely software
bool GrClipMaskManager::createClipMask(GrGpu* gpu, 
                                       const GrClip& clipIn,
                                       ScissoringSettings* scissorSettings) {

    GrAssert(scissorSettings);

    scissorSettings->fEnableScissoring = false;
    fClipMaskInStencil = false;
    fClipMaskInAlpha = false;

    GrDrawState* drawState = gpu->drawState();
    if (!drawState->isClipState()) {
        return true;
    }

    GrRenderTarget* rt = drawState->getRenderTarget();

    // GrDrawTarget should have filtered this for us
    GrAssert(NULL != rt);

#if GR_SW_CLIP
    // If MSAA is enabled we can do everything in the stencil buffer.
    // Otherwise check if we should just create the entire clip mask 
    // in software (this will only happen if the clip mask is anti-aliased
    // and too complex for the gpu to handle in its entirety)
    if (0 == rt->numSamples() && useSWOnlyPath(gpu, clipIn)) {
        // The clip geometry is complex enough that it will be more
        // efficient to create it entirely in software
        GrTexture* result = NULL;
        GrIRect bound;
        if (this->createSoftwareClipMask(gpu, clipIn, &result, &bound)) {
            fClipMaskInAlpha = true;

            setup_drawstate_aaclip(gpu, result, bound);
            return true;
        }

        // if SW clip mask creation fails fall through to the other
        // two possible methods (bottoming out at stencil clipping)
    }
#endif // GR_SW_CLIP

#if GR_AA_CLIP
    // If MSAA is enabled use the (faster) stencil path for AA clipping
    // otherwise the alpha clip mask is our only option
    if (0 == rt->numSamples() && clipIn.requiresAA()) {
        // Since we are going to create a destination texture of the correct
        // size for the mask (rather than being bound by the size of the
        // render target) we aren't going to use scissoring like the stencil
        // path does (see scissorSettings below)
        GrTexture* result = NULL;
        GrIRect bound;
        if (this->createAlphaClipMask(gpu, clipIn, &result, &bound)) {
            fClipMaskInAlpha = true;

            setup_drawstate_aaclip(gpu, result, bound);
            return true;
        }

        // if alpha clip mask creation fails fall through to the stencil
        // buffer method
    }
#endif // GR_AA_CLIP

    // Either a hard (stencil buffer) clip was explicitly requested or 
    // an antialiased clip couldn't be created. In either case, free up
    // the texture in the antialiased mask cache.
    // TODO: this may require more investigation. Ganesh performs a lot of
    // utility draws (e.g., clears, InOrderDrawBuffer playbacks) that hit
    // the stencil buffer path. These may be "incorrectly" clearing the 
    // AA cache.
    fAACache.reset();

    GrRect bounds;
    GrRect rtRect;
    rtRect.setLTRB(0, 0,
                   GrIntToScalar(rt->width()), GrIntToScalar(rt->height()));
    if (clipIn.hasConservativeBounds()) {
        bounds = clipIn.getConservativeBounds();
        if (!bounds.intersect(rtRect)) {
            bounds.setEmpty();
        }
    } else {
        bounds = rtRect;
    }

    bounds.roundOut(&scissorSettings->fScissorRect);
    if  (scissorSettings->fScissorRect.isEmpty()) {
        scissorSettings->fScissorRect.setLTRB(0,0,0,0);
        // TODO: I think we can do an early exit here - after refactoring try:
        //  set fEnableScissoring to true but leave fClipMaskInStencil false
        //  and return - everything is going to be scissored away anyway!
    }
    scissorSettings->fEnableScissoring = true;

    // use the stencil clip if we can't represent the clip as a rectangle.
    fClipMaskInStencil = !clipIn.isRect() && !clipIn.isEmpty() &&
                         !bounds.isEmpty();

    if (fClipMaskInStencil) {
        return this->createStencilClipMask(gpu, clipIn, bounds, scissorSettings);
    }

    return true;
}