GrDrawTarget::AutoDeviceCoordDraw::AutoDeviceCoordDraw( GrDrawTarget* target, GrDrawState::StageMask stageMask) { GrAssert(NULL != target); GrDrawState* drawState = target->drawState(); fDrawTarget = target; fViewMatrix = drawState->getViewMatrix(); fStageMask = stageMask; if (fStageMask) { GrMatrix invVM; if (fViewMatrix.invert(&invVM)) { for (int s = 0; s < GrDrawState::kNumStages; ++s) { if (fStageMask & (1 << s)) { fSamplerMatrices[s] = drawState->getSampler(s).getMatrix(); } } drawState->preConcatSamplerMatrices(fStageMask, invVM); } else { // sad trombone sound fStageMask = 0; } } drawState->viewMatrix()->reset(); }
void GrAAHairLinePathRenderer::drawPath(GrDrawState::StageMask stageMask) { if (!this->createGeom(stageMask)) { return; } GrDrawState* drawState = fTarget->drawState(); GrDrawTarget::AutoStateRestore asr; if (!drawState->getViewMatrix().hasPerspective()) { asr.set(fTarget); GrMatrix ivm; if (drawState->getViewInverse(&ivm)) { drawState->preConcatSamplerMatrices(stageMask, ivm); } drawState->setViewMatrix(GrMatrix::I()); } // TODO: See whether rendering lines as degenerate quads improves perf // when we have a mix fTarget->setIndexSourceToBuffer(fLinesIndexBuffer); int lines = 0; int nBufLines = fLinesIndexBuffer->maxQuads(); while (lines < fLineSegmentCnt) { int n = GrMin(fLineSegmentCnt-lines, nBufLines); drawState->setVertexEdgeType(GrDrawState::kHairLine_EdgeType); fTarget->drawIndexed(kTriangles_PrimitiveType, kVertsPerLineSeg*lines, // startV 0, // startI kVertsPerLineSeg*n, // vCount kIdxsPerLineSeg*n); // iCount lines += n; } fTarget->setIndexSourceToBuffer(fQuadsIndexBuffer); int quads = 0; while (quads < fQuadCnt) { int n = GrMin(fQuadCnt-quads, kNumQuadsInIdxBuffer); drawState->setVertexEdgeType(GrDrawState::kHairQuad_EdgeType); fTarget->drawIndexed(kTriangles_PrimitiveType, 4*fLineSegmentCnt + kVertsPerQuad*quads, // startV 0, // startI kVertsPerQuad*n, // vCount kIdxsPerQuad*n); // iCount quads += n; } }
bool GrAAConvexPathRenderer::onDrawPath(const SkPath& origPath, GrPathFill fill, const GrVec* translate, GrDrawTarget* target, GrDrawState::StageMask stageMask, bool antiAlias) { const SkPath* path = &origPath; if (path->isEmpty()) { return true; } GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit); GrDrawState* drawState = target->drawState(); GrMatrix vm = drawState->getViewMatrix(); if (NULL != translate) { vm.postTranslate(translate->fX, translate->fY); } GrMatrix ivm; if (vm.invert(&ivm)) { drawState->preConcatSamplerMatrices(stageMask, ivm); } drawState->viewMatrix()->reset(); GrVertexLayout layout = 0; for (int s = 0; s < GrDrawState::kNumStages; ++s) { if ((1 << s) & stageMask) { layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s); } } layout |= GrDrawTarget::kEdge_VertexLayoutBit; // We use the fact that SkPath::transform path does subdivision based on // perspective. Otherwise, we apply the view matrix when copying to the // segment representation. SkPath tmpPath; if (vm.hasPerspective()) { origPath.transform(vm, &tmpPath); path = &tmpPath; vm.reset(); } QuadVertex *verts; uint16_t* idxs; int vCount; int iCount; enum { kPreallocSegmentCnt = 512 / sizeof(Segment), }; SkSTArray<kPreallocSegmentCnt, Segment, true> segments; SkPoint fanPt; if (!get_segments(*path, vm, &segments, &fanPt, &vCount, &iCount)) { return false; } GrDrawTarget::AutoReleaseGeometry arg(target, layout, vCount, iCount); if (!arg.succeeded()) { return false; } verts = reinterpret_cast<QuadVertex*>(arg.vertices()); idxs = reinterpret_cast<uint16_t*>(arg.indices()); create_vertices(segments, fanPt, verts, idxs); drawState->setVertexEdgeType(GrDrawState::kQuad_EdgeType); target->drawIndexed(kTriangles_PrimitiveType, 0, // start vertex 0, // start index vCount, iCount); return true; }
void GrDefaultPathRenderer::onDrawPath(GrDrawState::StageMask stageMask, bool stencilOnly) { GrMatrix viewM = fTarget->getDrawState().getViewMatrix(); GrScalar tol = GR_Scalar1; tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, fPath->getBounds()); GrDrawState* drawState = fTarget->drawState(); // 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 || stageMask != fPreviousStages) { if (!this->createGeom(tol, stageMask)) { return; } } GrAssert(NULL != fTarget); GrDrawTarget::AutoStateRestore asr(fTarget); 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_PathFill == fFill) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } lastPassIsBounds = false; drawFace[0] = GrDrawState::kBoth_DrawFace; } else { if (single_pass_path(*fTarget, *fPath, fFill)) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } drawFace[0] = GrDrawState::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] = GrDrawState::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] = 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; } } } { 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; 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 { if (stageMask) { if (!drawState->getViewInverse(&vmi)) { GrPrintf("Could not invert matrix."); return; } drawState->preConcatSamplerMatrices(stageMask, vmi); } drawState->setViewMatrix(GrMatrix::I()); } } else { bounds = fPath->getBounds(); bounds.offset(fTranslate); } GrDrawTarget::AutoGeometryPush agp(fTarget); fTarget->drawSimpleRect(bounds, NULL, stageMask); } else { if (passCount > 1) { drawState->enableState(GrDrawState::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]; } } } } } }
bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, GrPathFill fill, const GrVec* translate, GrDrawTarget* target, GrDrawState::StageMask stageMask, bool antiAlias) { int lineCnt; int quadCnt; GrDrawTarget::AutoReleaseGeometry arg; if (!this->createGeom(path, translate, target, stageMask, &lineCnt, &quadCnt, &arg)) { return false; } GrDrawTarget::AutoStateRestore asr; GrDrawState* drawState = target->drawState(); if (!drawState->getViewMatrix().hasPerspective()) { // we are going to whack the view matrix to identity to remove // perspective. asr.set(target, GrDrawTarget::kPreserve_ASRInit); drawState = target->drawState(); GrMatrix ivm; if (drawState->getViewInverse(&ivm)) { drawState->preConcatSamplerMatrices(stageMask, ivm); } drawState->viewMatrix()->reset(); } // TODO: See whether rendering lines as degenerate quads improves perf // when we have a mix target->setIndexSourceToBuffer(fLinesIndexBuffer); int lines = 0; int nBufLines = fLinesIndexBuffer->maxQuads(); while (lines < lineCnt) { int n = GrMin(lineCnt - lines, nBufLines); drawState->setVertexEdgeType(GrDrawState::kHairLine_EdgeType); target->drawIndexed(kTriangles_GrPrimitiveType, kVertsPerLineSeg*lines, // startV 0, // startI kVertsPerLineSeg*n, // vCount kIdxsPerLineSeg*n); // iCount lines += n; } target->setIndexSourceToBuffer(fQuadsIndexBuffer); int quads = 0; while (quads < quadCnt) { int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); drawState->setVertexEdgeType(GrDrawState::kHairQuad_EdgeType); target->drawIndexed(kTriangles_GrPrimitiveType, 4 * lineCnt + kVertsPerQuad*quads, // startV 0, // startI kVertsPerQuad*n, // vCount kIdxsPerQuad*n); // iCount quads += n; } return true; }