void GrDrawTarget::onDrawRect(const SkRect& rect, const SkMatrix* matrix, const SkRect* localRect, const SkMatrix* localMatrix) { GrDrawState::AutoViewMatrixRestore avmr; if (NULL != matrix) { avmr.set(this->drawState(), *matrix); } set_vertex_attributes(this->drawState(), NULL != localRect); AutoReleaseGeometry geo(this, 4, 0); if (!geo.succeeded()) { GrPrintf("Failed to get space for vertices!\n"); return; } size_t vsize = this->drawState()->getVertexSize(); geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize); if (NULL != localRect) { SkPoint* coords = GrTCast<SkPoint*>(GrTCast<intptr_t>(geo.vertices()) + sizeof(SkPoint)); coords->setRectFan(localRect->fLeft, localRect->fTop, localRect->fRight, localRect->fBottom, vsize); if (NULL != localMatrix) { localMatrix->mapPointsWithStride(coords, vsize, 4); } } SkRect bounds; this->getDrawState().getViewMatrix().mapRect(&bounds, rect); this->drawNonIndexed(kTriangleFan_GrPrimitiveType, 0, 4, &bounds); }
void GrSWMaskHelper::DrawToTargetWithPathMask(GrTexture* texture, GrDrawTarget* target, const SkIRect& rect) { GrDrawState* drawState = target->drawState(); GrDrawState::AutoViewMatrixRestore avmr; if (!avmr.setIdentity(drawState)) { return; } GrDrawState::AutoRestoreEffects are(drawState); SkRect dstRect = SkRect::MakeLTRB(SK_Scalar1 * rect.fLeft, SK_Scalar1 * rect.fTop, SK_Scalar1 * rect.fRight, SK_Scalar1 * rect.fBottom); // We want to use device coords to compute the texture coordinates. We set our matrix to be // equal to the view matrix followed by a translation so that the top-left of the device bounds // maps to 0,0, and then a scaling matrix to normalized coords. We apply this matrix to the // vertex positions rather than local coords. SkMatrix maskMatrix; maskMatrix.setIDiv(texture->width(), texture->height()); maskMatrix.preTranslate(SkIntToScalar(-rect.fLeft), SkIntToScalar(-rect.fTop)); maskMatrix.preConcat(drawState->getViewMatrix()); drawState->addCoverageEffect( GrSimpleTextureEffect::Create(texture, maskMatrix, GrTextureParams::kNone_FilterMode, kPosition_GrCoordSet))->unref(); target->drawSimpleRect(dstRect); }
void GrInOrderDrawBuffer::onDrawRect(const SkRect& rect, const SkRect* localRect, const SkMatrix* localMatrix) { GrDrawState* drawState = this->drawState(); GrColor color = drawState->getColor(); set_vertex_attributes(drawState, SkToBool(localRect), color); AutoReleaseGeometry geo(this, 4, 0); if (!geo.succeeded()) { SkDebugf("Failed to get space for vertices!\n"); return; } // Go to device coords to allow batching across matrix changes SkMatrix matrix = drawState->getViewMatrix(); // When the caller has provided an explicit source rect for a stage then we don't want to // modify that stage's matrix. Otherwise if the effect is generating its source rect from // the vertex positions then we have to account for the view matrix change. GrDrawState::AutoViewMatrixRestore avmr; if (!avmr.setIdentity(drawState)) { return; } size_t vstride = drawState->getVertexStride(); geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vstride); matrix.mapPointsWithStride(geo.positions(), vstride, 4); SkRect devBounds; // since we already computed the dev verts, set the bounds hint. This will help us avoid // unnecessary clipping in our onDraw(). get_vertex_bounds(geo.vertices(), vstride, 4, &devBounds); if (localRect) { static const int kLocalOffset = sizeof(SkPoint) + sizeof(GrColor); SkPoint* coords = GrTCast<SkPoint*>(GrTCast<intptr_t>(geo.vertices()) + kLocalOffset); coords->setRectFan(localRect->fLeft, localRect->fTop, localRect->fRight, localRect->fBottom, vstride); if (localMatrix) { localMatrix->mapPointsWithStride(coords, vstride, 4); } } static const int kColorOffset = sizeof(SkPoint); GrColor* vertColor = GrTCast<GrColor*>(GrTCast<intptr_t>(geo.vertices()) + kColorOffset); for (int i = 0; i < 4; ++i) { *vertColor = color; vertColor = (GrColor*) ((intptr_t) vertColor + vstride); } this->setIndexSourceToBuffer(this->getContext()->getQuadIndexBuffer()); this->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds); // to ensure that stashing the drawState ptr is valid SkASSERT(this->drawState() == drawState); }
void GrClipMaskManager::mergeMask(GrTexture* dstMask, GrTexture* srcMask, SkRegion::Op op, const SkIRect& dstBound, const SkIRect& srcBound) { GrDrawState::AutoViewMatrixRestore avmr; GrDrawState* drawState = fGpu->drawState(); SkAssertResult(avmr.setIdentity(drawState)); GrDrawState::AutoRestoreEffects are(drawState); drawState->setRenderTarget(dstMask->asRenderTarget()); setup_boolean_blendcoeffs(drawState, op); SkMatrix sampleM; sampleM.setIDiv(srcMask->width(), srcMask->height()); drawState->addColorEffect( GrTextureDomainEffect::Create(srcMask, sampleM, GrTextureDomain::MakeTexelDomain(srcMask, srcBound), GrTextureDomain::kDecal_Mode, GrTextureParams::kNone_FilterMode))->unref(); fGpu->drawSimpleRect(SkRect::Make(dstBound), NULL); }
void GrGLPathRendering::drawPath(const GrPath* path, SkPath::FillType fill) { GrGLuint id = static_cast<const GrGLPath*>(path)->pathID(); SkASSERT(NULL != fGpu->drawState()->getRenderTarget()); SkASSERT(NULL != fGpu->drawState()->getRenderTarget()->getStencilBuffer()); this->flushPathStencilSettings(fill); SkASSERT(!fHWPathStencilSettings.isTwoSided()); const SkStrokeRec& stroke = path->getStroke(); SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(fill); GrGLenum fillMode = gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face)); GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face); if (nonInvertedFill == fill) { if (stroke.needToApply()) { if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) { GL_CALL(StencilFillPath(id, fillMode, writeMask)); } this->stencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX); } else { this->stencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX); } } else { if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) { GL_CALL(StencilFillPath(id, fillMode, writeMask)); } if (stroke.needToApply()) { GL_CALL(StencilStrokePath(id, 0xffff, writeMask)); } GrDrawState* drawState = fGpu->drawState(); GrDrawState::AutoViewMatrixRestore avmr; SkRect bounds = SkRect::MakeLTRB(0, 0, SkIntToScalar(drawState->getRenderTarget()->width()), SkIntToScalar(drawState->getRenderTarget()->height())); SkMatrix vmi; // 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. SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf; bounds.outset(bloat, bloat); } else { avmr.setIdentity(drawState); } fGpu->drawSimpleRect(bounds); } }
bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path, const SkStrokeRec& stroke, GrDrawTarget* target, bool antiAlias) { SkASSERT(!antiAlias); SkASSERT(!stroke.isHairlineStyle()); GrDrawState* drawState = target->drawState(); SkASSERT(drawState->getStencil().isDisabled()); SkAutoTUnref<GrPath> p(fGpu->createPath(path)); SkPath::FillType nonInvertedFill = SkPath::ConvertToNonInverseFillType(path.getFillType()); target->stencilPath(p, stroke, 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 SkRect bounds = p->getBounds(); SkScalar bloat = drawState->getViewMatrix().getMaxStretch() * SK_ScalarHalf; GrDrawState::AutoViewMatrixRestore avmr; if (nonInvertedFill == path.getFillType()) { 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); SkMatrix vmi; bounds.setLTRB(0, 0, SkIntToScalar(drawState->getRenderTarget()->width()), SkIntToScalar(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 { avmr.setIdentity(drawState); bloat = 0; } *drawState->stencil() = kInvertedStencilPass; } bounds.outset(bloat, bloat); target->drawSimpleRect(bounds, NULL); target->drawState()->stencil()->setDisabled(); return true; }
void GrInOrderDrawBuffer::onDrawRect(const GrRect& rect, const SkMatrix* matrix, const GrRect* localRect, const SkMatrix* localMatrix) { GrDrawState::AutoColorRestore acr; GrDrawState* drawState = this->drawState(); GrColor color = drawState->getColor(); int colorOffset, localOffset; set_vertex_attributes(drawState, this->caps()->dualSourceBlendingSupport() || drawState->hasSolidCoverage(), NULL != localRect, &colorOffset, &localOffset); if (colorOffset >= 0) { // We set the draw state's color to white here. This is done so that any batching performed // in our subclass's onDraw() won't get a false from GrDrawState::op== due to a color // mismatch. TODO: Once vertex layout is owned by GrDrawState it should skip comparing the // constant color in its op== when the kColor layout bit is set and then we can remove // this. acr.set(drawState, 0xFFFFFFFF); } AutoReleaseGeometry geo(this, 4, 0); if (!geo.succeeded()) { GrPrintf("Failed to get space for vertices!\n"); return; } // Go to device coords to allow batching across matrix changes SkMatrix combinedMatrix; if (NULL != matrix) { combinedMatrix = *matrix; } else { combinedMatrix.reset(); } combinedMatrix.postConcat(drawState->getViewMatrix()); // When the caller has provided an explicit source rect for a stage then we don't want to // modify that stage's matrix. Otherwise if the effect is generating its source rect from // the vertex positions then we have to account for the view matrix change. GrDrawState::AutoViewMatrixRestore avmr; if (!avmr.setIdentity(drawState)) { return; } size_t vsize = drawState->getVertexSize(); geo.positions()->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vsize); combinedMatrix.mapPointsWithStride(geo.positions(), vsize, 4); SkRect devBounds; // since we already computed the dev verts, set the bounds hint. This will help us avoid // unnecessary clipping in our onDraw(). get_vertex_bounds(geo.vertices(), vsize, 4, &devBounds); if (localOffset >= 0) { GrPoint* coords = GrTCast<GrPoint*>(GrTCast<intptr_t>(geo.vertices()) + localOffset); coords->setRectFan(localRect->fLeft, localRect->fTop, localRect->fRight, localRect->fBottom, vsize); if (NULL != localMatrix) { localMatrix->mapPointsWithStride(coords, vsize, 4); } } if (colorOffset >= 0) { GrColor* vertColor = GrTCast<GrColor*>(GrTCast<intptr_t>(geo.vertices()) + colorOffset); for (int i = 0; i < 4; ++i) { *vertColor = color; vertColor = (GrColor*) ((intptr_t) vertColor + vsize); } } this->setIndexSourceToBuffer(this->getContext()->getQuadIndexBuffer()); this->drawIndexedInstances(kTriangles_GrPrimitiveType, 1, 4, 6, &devBounds); // to ensure that stashing the drawState ptr is valid GrAssert(this->drawState() == drawState); }
bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path, const SkStrokeRec& origStroke, GrDrawTarget* target, bool stencilOnly) { SkMatrix viewM = target->getDrawState().getViewMatrix(); SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke); SkScalar hairlineCoverage; if (IsStrokeHairlineOrEquivalent(*stroke, target->getDrawState().getViewMatrix(), &hairlineCoverage)) { uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage * target->getDrawState().getCoverage()); target->drawState()->setCoverage(newCoverage); if (!stroke->isHairlineStyle()) { stroke.writable()->setHairlineStyle(); } } SkScalar tol = SK_Scalar1; tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds()); int vertexCnt; int indexCnt; GrPrimitiveType primType; GrDrawTarget::AutoReleaseGeometry arg; if (!this->createGeom(path, *stroke, tol, target, &primType, &vertexCnt, &indexCnt, &arg)) { return false; } SkASSERT(NULL != target); GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit); GrDrawState* drawState = target->drawState(); bool colorWritesWereDisabled = drawState->isColorWriteDisabled(); // face culling doesn't make sense here SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace()); int passCount = 0; const GrStencilSettings* passes[3]; GrDrawState::DrawFace drawFace[3]; bool reverse = false; bool lastPassIsBounds; if (stroke->isHairlineStyle()) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } lastPassIsBounds = false; drawFace[0] = GrDrawState::kBoth_DrawFace; } else { if (single_pass_path(path, *stroke)) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } drawFace[0] = GrDrawState::kBoth_DrawFace; lastPassIsBounds = false; } else { switch (path.getFillType()) { case SkPath::kInverseEvenOdd_FillType: reverse = true; // fallthrough case SkPath::kEvenOdd_FillType: 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 SkPath::kInverseWinding_FillType: reverse = true; // fallthrough case SkPath::kWinding_FillType: 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: SkDEBUGFAIL("Unknown path fFill!"); return false; } } } SkRect devBounds; GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds); 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); } SkRect bounds; GrDrawState::AutoViewMatrixRestore avmr; if (reverse) { SkASSERT(NULL != drawState->getRenderTarget()); // draw over the dev bounds (which will be the whole dst surface for inv fill). bounds = devBounds; SkMatrix vmi; // mapRect through persp matrix may not be correct if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) { vmi.mapRect(&bounds); } else { avmr.setIdentity(drawState); } } else { bounds = path.getBounds(); } GrDrawTarget::AutoGeometryAndStatePush agasp(target, GrDrawTarget::kPreserve_ASRInit); target->drawSimpleRect(bounds, NULL); } else { if (passCount > 1) { drawState->enableState(GrDrawState::kNoColorWrites_StateBit); } if (indexCnt) { target->drawIndexed(primType, 0, 0, vertexCnt, indexCnt, &devBounds); } else { target->drawNonIndexed(primType, 0, vertexCnt, &devBounds); } } } return true; }
bool GrStencilAndCoverPathRenderer::onDrawPath(const SkPath& path, const SkStrokeRec& stroke, GrDrawTarget* target, bool antiAlias) { SkASSERT(!antiAlias); SkASSERT(!stroke.isHairlineStyle()); GrDrawState* drawState = target->drawState(); SkASSERT(drawState->getStencil().isDisabled()); SkAutoTUnref<GrPath> p(get_gr_path(fGpu, path, stroke)); if (path.isInverseFillType()) { 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); drawState->setStencil(kInvertedStencilPass); // fake inverse with a stencil and cover target->stencilPath(p, convert_skpath_filltype(path.getFillType())); GrDrawState::AutoViewMatrixRestore avmr; SkRect bounds = SkRect::MakeLTRB(0, 0, SkIntToScalar(drawState->getRenderTarget()->width()), SkIntToScalar(drawState->getRenderTarget()->height())); SkMatrix vmi; // 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. SkScalar bloat = drawState->getViewMatrix().getMaxScale() * SK_ScalarHalf; bounds.outset(bloat, bloat); } else { avmr.setIdentity(drawState); } target->drawSimpleRect(bounds); } else { GR_STATIC_CONST_SAME_STENCIL(kStencilPass, kZero_StencilOp, kZero_StencilOp, kNotEqual_StencilFunc, 0xffff, 0x0000, 0xffff); drawState->setStencil(kStencilPass); target->drawPath(p, convert_skpath_filltype(path.getFillType())); } target->drawState()->stencil()->setDisabled(); return true; }