const char* GrGLSLVectorHomogCoord(int count) { static const char* HOMOGS[] = {"ERROR", "", ".y", ".z", ".w"}; GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(HOMOGS)); return HOMOGS[count]; }
void GrGpu::finalizeReservedIndices() { GrAssert(NULL != fIndexPool); fIndexPool->unlock(); }
bool GrAAHairLinePathRenderer::createGeom(GrDrawTarget::StageBitfield stages) { int rtHeight = fTarget->getRenderTarget()->height(); GrIRect clip; if (fTarget->getClip().hasConservativeBounds()) { GrRect clipRect = fTarget->getClip().getConservativeBounds(); clipRect.roundOut(&clip); } else { clip.setLargest(); } // If none of the inputs that affect generation of path geometry have // have changed since last previous path draw then we can reuse the // previous geoemtry. if (stages == fPreviousStages && fPreviousViewMatrix == fTarget->getViewMatrix() && fPreviousTranslate == fTranslate && rtHeight == fPreviousRTHeight && fClipRect == clip) { return true; } GrVertexLayout layout = GrDrawTarget::kEdge_VertexLayoutBit; for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { if ((1 << s) & stages) { layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s); } } GrMatrix viewM = fTarget->getViewMatrix(); SkAlignedSTStorage<128, GrPoint> lineStorage; SkAlignedSTStorage<128, GrPoint> quadStorage; PtArray lines(&lineStorage); PtArray quads(&quadStorage); IntArray qSubdivs; fQuadCnt = generate_lines_and_quads(*fPath, viewM, fTranslate, clip, &lines, &quads, &qSubdivs); fLineSegmentCnt = lines.count() / 2; int vertCnt = kVertsPerLineSeg * fLineSegmentCnt + kVertsPerQuad * fQuadCnt; GrAssert(sizeof(Vertex) == GrDrawTarget::VertexSize(layout)); Vertex* verts; if (!fTarget->reserveVertexSpace(layout, vertCnt, (void**)&verts)) { return false; } Vertex* base = verts; const GrMatrix* toDevice = NULL; const GrMatrix* toSrc = NULL; GrMatrix ivm; if (viewM.hasPerspective()) { if (viewM.invert(&ivm)) { toDevice = &viewM; toSrc = &ivm; } } for (int i = 0; i < fLineSegmentCnt; ++i) { add_line(&lines[2*i], rtHeight, toSrc, &verts); } int unsubdivQuadCnt = quads.count() / 3; for (int i = 0; i < unsubdivQuadCnt; ++i) { GrAssert(qSubdivs[i] >= 0); add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts); } fPreviousStages = stages; fPreviousViewMatrix = fTarget->getViewMatrix(); fPreviousRTHeight = rtHeight; fClipRect = clip; fPreviousTranslate = fTranslate; return true; }
GrPath* GrGpu::createPath(const SkPath& path) { GrAssert(fCaps.pathStencilingSupport()); this->handleDirtyContext(); return this->onCreatePath(path); }
void GrGpu::geometrySourceWillPop(const GeometrySrcState& restoredState) { // if popping last entry then pops are unbalanced with pushes GrAssert(fGeomPoolStateStack.count() > 1); fGeomPoolStateStack.pop_back(); }
bool GrGpuGLShaders::flushGraphicsState(GrPrimitiveType type) { if (!flushGLStateCommon(type)) { return false; } const GrDrawState& drawState = this->getDrawState(); if (fDirtyFlags.fRenderTargetChanged) { // our coords are in pixel space and the GL matrices map to NDC // so if the viewport changed, our matrix is now wrong. fHWDrawState.setViewMatrix(GrMatrix::InvalidMatrix()); // we assume all shader matrices may be wrong after viewport changes fProgramCache->invalidateViewMatrices(); } GrBlendCoeff srcCoeff; GrBlendCoeff dstCoeff; BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff); if (kSkipDraw_BlendOptFlag & blendOpts) { return false; } this->buildProgram(type, blendOpts, dstCoeff); fProgramData = fProgramCache->getProgramData(fCurrentProgram); if (NULL == fProgramData) { GrAssert(!"Failed to create program!"); return false; } if (fHWProgramID != fProgramData->fProgramID) { GL_CALL(UseProgram(fProgramData->fProgramID)); fHWProgramID = fProgramData->fProgramID; } fCurrentProgram.overrideBlend(&srcCoeff, &dstCoeff); this->flushBlend(type, srcCoeff, dstCoeff); GrColor color; if (blendOpts & kEmitTransBlack_BlendOptFlag) { color = 0; } else if (blendOpts & kEmitCoverage_BlendOptFlag) { color = 0xffffffff; } else { color = drawState.getColor(); } this->flushColor(color); this->flushViewMatrix(); for (int s = 0; s < GrDrawState::kNumStages; ++s) { this->flushTextureMatrix(s); this->flushRadial2(s); this->flushConvolution(s); this->flushTexelSize(s); this->flushTextureDomain(s); } this->flushEdgeAAData(); resetDirtyFlags(); return true; }
void GrGpu::insertResource(GrResource* resource) { GrAssert(NULL != resource); GrAssert(this == resource->getGpu()); fResourceList.addToHead(resource); }
void GrInOrderDrawBuffer::drawRect(const GrRect& rect, const SkMatrix* matrix, const GrRect* srcRects[], const SkMatrix* srcMatrices[]) { GrAssert(!(NULL == fQuadIndexBuffer && fCurrQuad)); GrAssert(!(fDraws.empty() && fCurrQuad)); GrAssert(!(0 != fMaxQuads && NULL == fQuadIndexBuffer)); GrDrawState* drawState = this->drawState(); // if we have a quad IB then either append to the previous run of // rects or start a new run if (fMaxQuads) { bool appendToPreviousDraw = false; GrVertexLayout layout = GetRectVertexLayout(srcRects); // Batching across colors means we move the draw color into the // rect's vertex colors to allow greater batching (a lot of rects // in a row differing only in color is a common occurence in tables). bool batchAcrossColors = true; if (!this->getCaps().dualSourceBlendingSupport()) { for (int s = 0; s < GrDrawState::kNumStages; ++s) { if (this->getDrawState().isStageEnabled(s)) { // We disable batching across colors when there is a texture // present because (by pushing the the color to the vertices) // Ganesh loses track of the rect's opacity. This, in turn, can // cause some of the blending optimizations to be disabled. This // becomes a huge problem on some of the smaller devices where // shader derivatives and dual source blending aren't supported. // In those cases paths are often drawn to a texture and then // drawn as a texture (using this method). Because dual source // blending is disabled (and the blend optimizations are short // circuited) some of the more esoteric blend modes can no longer // be supported. // TODO: add tracking of batchAcrossColors's opacity batchAcrossColors = false; break; } } } if (batchAcrossColors) { layout |= GrDrawState::kColor_VertexLayoutBit; } AutoReleaseGeometry geo(this, layout, 4, 0); if (!geo.succeeded()) { GrPrintf("Failed to get space for vertices!\n"); return; } SkMatrix combinedMatrix = drawState->getViewMatrix(); // We go to device space so that matrix changes allow us to concat // rect draws. When the caller has provided explicit source rects // then we don't want to modify the stages' matrices. Otherwise // we have to account for the view matrix change in the stage // matrices. uint32_t explicitCoordMask = 0; if (srcRects) { for (int s = 0; s < GrDrawState::kNumStages; ++s) { if (srcRects[s]) { explicitCoordMask |= (1 << s); } } } GrDrawState::AutoDeviceCoordDraw adcd(this->drawState(), explicitCoordMask); if (!adcd.succeeded()) { return; } if (NULL != matrix) { combinedMatrix.preConcat(*matrix); } SetRectVertices(rect, &combinedMatrix, srcRects, srcMatrices, this->getDrawState().getColor(), layout, geo.vertices()); // Now that the paint's color is stored in the vertices set it to // white so that the following code can batch all the rects regardless // of paint color GrDrawState::AutoColorRestore acr(this->drawState(), batchAcrossColors ? SK_ColorWHITE : this->getDrawState().getColor()); // we don't want to miss an opportunity to batch rects together // simply because the clip has changed if the clip doesn't affect // the rect. bool disabledClip = false; if (drawState->isClipState()) { GrRect devClipRect; bool isIntersectionOfRects = false; const GrClipData* clip = this->getClip(); clip->fClipStack->getConservativeBounds(-clip->fOrigin.fX, -clip->fOrigin.fY, drawState->getRenderTarget()->width(), drawState->getRenderTarget()->height(), &devClipRect, &isIntersectionOfRects); if (isIntersectionOfRects) { // If the clip rect touches the edge of the viewport, extended it // out (close) to infinity to avoid bogus intersections. // We might consider a more exact clip to viewport if this // conservative test fails. const GrRenderTarget* target = drawState->getRenderTarget(); if (0 >= devClipRect.fLeft) { devClipRect.fLeft = SK_ScalarMin; } if (target->width() <= devClipRect.fRight) { devClipRect.fRight = SK_ScalarMax; } if (0 >= devClipRect.top()) { devClipRect.fTop = SK_ScalarMin; } if (target->height() <= devClipRect.fBottom) { devClipRect.fBottom = SK_ScalarMax; } int stride = GrDrawState::VertexSize(layout); bool insideClip = true; for (int v = 0; v < 4; ++v) { const GrPoint& p = *GrDrawState::GetVertexPoint(geo.vertices(), v, stride); if (!devClipRect.contains(p)) { insideClip = false; break; } } if (insideClip) { drawState->disableState(GrDrawState::kClip_StateBit); disabledClip = true; } } } if (!this->needsNewClip() && !this->needsNewState() && fCurrQuad > 0 && fCurrQuad < fMaxQuads && layout == fLastRectVertexLayout) { int vsize = GrDrawState::VertexSize(layout); Draw& lastDraw = fDraws.back(); GrAssert(lastDraw.fIndexBuffer == fQuadIndexBuffer); GrAssert(kTriangles_GrPrimitiveType == lastDraw.fPrimitiveType); GrAssert(0 == lastDraw.fVertexCount % 4); GrAssert(0 == lastDraw.fIndexCount % 6); GrAssert(0 == lastDraw.fStartIndex); GeometryPoolState& poolState = fGeoPoolStateStack.back(); appendToPreviousDraw = kDraw_Cmd == fCmds.back() && lastDraw.fVertexBuffer == poolState.fPoolVertexBuffer && (fCurrQuad * 4 + lastDraw.fStartVertex) == poolState.fPoolStartVertex; if (appendToPreviousDraw) { lastDraw.fVertexCount += 4; lastDraw.fIndexCount += 6; fCurrQuad += 1; // we reserved above, so we should be the first // use of this vertex reservation. GrAssert(0 == poolState.fUsedPoolVertexBytes); poolState.fUsedPoolVertexBytes = 4 * vsize; } } if (!appendToPreviousDraw) { this->setIndexSourceToBuffer(fQuadIndexBuffer); this->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 4, 6); fCurrQuad = 1; fLastRectVertexLayout = layout; } if (disabledClip) { drawState->enableState(GrDrawState::kClip_StateBit); } fInstancedDrawTracker.reset(); } else { INHERITED::drawRect(rect, matrix, srcRects, srcMatrices); } }
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::AutoDeviceCoordDraw adcd(drawState); if (!adcd.succeeded()) { 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); }
void GrInOrderDrawBuffer::drawIndexedInstances(GrPrimitiveType type, int instanceCount, int verticesPerInstance, int indicesPerInstance) { if (!verticesPerInstance || !indicesPerInstance) { return; } const GeometrySrcState& geomSrc = this->getGeomSrc(); // we only attempt to concat the case when reserved verts are used with // an index buffer. if (kReserved_GeometrySrcType == geomSrc.fVertexSrc && kBuffer_GeometrySrcType == geomSrc.fIndexSrc) { if (this->needsNewClip()) { this->recordClip(); } if (this->needsNewState()) { this->recordState(); } Draw* draw = NULL; // if the last draw used the same indices/vertices per shape then we // may be able to append to it. if (kDraw_Cmd == fCmds.back() && verticesPerInstance == fInstancedDrawTracker.fVerticesPerInstance && indicesPerInstance == fInstancedDrawTracker.fIndicesPerInstance) { GrAssert(fDraws.count()); draw = &fDraws.back(); } GeometryPoolState& poolState = fGeoPoolStateStack.back(); const GrVertexBuffer* vertexBuffer = poolState.fPoolVertexBuffer; // Check whether the draw is compatible with this draw in order to // append if (NULL == draw || draw->fIndexBuffer != geomSrc.fIndexBuffer || draw->fPrimitiveType != type || draw->fVertexBuffer != vertexBuffer) { draw = this->recordDraw(); draw->fPrimitiveType = type; draw->fStartVertex = poolState.fPoolStartVertex; draw->fStartIndex = 0; draw->fVertexCount = 0; draw->fIndexCount = 0; draw->fVertexLayout = geomSrc.fVertexLayout; draw->fVertexBuffer = vertexBuffer; vertexBuffer->ref(); draw->fIndexBuffer = geomSrc.fIndexBuffer; geomSrc.fIndexBuffer->ref(); } else { GrAssert(!(draw->fIndexCount % indicesPerInstance)); GrAssert(!(draw->fVertexCount % verticesPerInstance)); GrAssert(poolState.fPoolStartVertex == draw->fStartVertex + draw->fVertexCount); } // how many instances can be in a single draw int maxInstancesPerDraw = this->indexCountInCurrentSource() / indicesPerInstance; if (!maxInstancesPerDraw) { return; } // how many instances should be concat'ed onto draw int instancesToConcat = maxInstancesPerDraw - draw->fVertexCount / verticesPerInstance; if (maxInstancesPerDraw > instanceCount) { maxInstancesPerDraw = instanceCount; if (instancesToConcat > instanceCount) { instancesToConcat = instanceCount; } } // update the amount of reserved data actually referenced in draws size_t vertexBytes = instanceCount * verticesPerInstance * GrDrawState::VertexSize(draw->fVertexLayout); poolState.fUsedPoolVertexBytes = GrMax(poolState.fUsedPoolVertexBytes, vertexBytes); while (instanceCount) { if (!instancesToConcat) { int startVertex = draw->fStartVertex + draw->fVertexCount; draw = this->recordDraw(); draw->fPrimitiveType = type; draw->fStartVertex = startVertex; draw->fStartIndex = 0; draw->fVertexCount = 0; draw->fIndexCount = 0; draw->fVertexLayout = geomSrc.fVertexLayout; draw->fVertexBuffer = vertexBuffer; vertexBuffer->ref(); draw->fIndexBuffer = geomSrc.fIndexBuffer; geomSrc.fIndexBuffer->ref(); instancesToConcat = maxInstancesPerDraw; } draw->fVertexCount += instancesToConcat * verticesPerInstance; draw->fIndexCount += instancesToConcat * indicesPerInstance; instanceCount -= instancesToConcat; instancesToConcat = 0; } // update draw tracking for next draw fCurrQuad = 0; fInstancedDrawTracker.fVerticesPerInstance = verticesPerInstance; fInstancedDrawTracker.fIndicesPerInstance = indicesPerInstance; } else { this->INHERITED::drawIndexedInstances(type, instanceCount, verticesPerInstance, indicesPerInstance); } }
bool GrInOrderDrawBuffer::flushTo(GrDrawTarget* target) { GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc); GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc); GrAssert(NULL != target); GrAssert(target != this); // not considered and why? int numCmds = fCmds.count(); if (0 == numCmds) { return false; } fVertexPool.unlock(); fIndexPool.unlock(); GrDrawTarget::AutoClipRestore acr(target); AutoGeometryPush agp(target); GrDrawState playbackState; GrDrawState* prevDrawState = target->drawState(); prevDrawState->ref(); target->setDrawState(&playbackState); GrClipData clipData; int currState = 0; int currClip = 0; int currClear = 0; int currDraw = 0; int currStencilPath = 0; for (int c = 0; c < numCmds; ++c) { switch (fCmds[c]) { case kDraw_Cmd: { const Draw& draw = fDraws[currDraw]; target->setVertexSourceToBuffer(draw.fVertexLayout, draw.fVertexBuffer); if (draw.fIndexCount) { target->setIndexSourceToBuffer(draw.fIndexBuffer); } if (draw.fIndexCount) { target->drawIndexed(draw.fPrimitiveType, draw.fStartVertex, draw.fStartIndex, draw.fVertexCount, draw.fIndexCount); } else { target->drawNonIndexed(draw.fPrimitiveType, draw.fStartVertex, draw.fVertexCount); } ++currDraw; break; } case kStencilPath_Cmd: { const StencilPath& sp = fStencilPaths[currStencilPath]; target->stencilPath(sp.fPath.get(), sp.fStroke, sp.fFill); ++currStencilPath; break; } case kSetState_Cmd: fStates[currState].restoreTo(&playbackState); ++currState; break; case kSetClip_Cmd: clipData.fClipStack = &fClips[currClip]; clipData.fOrigin = fClipOrigins[currClip]; target->setClip(&clipData); ++currClip; break; case kClear_Cmd: target->clear(&fClears[currClear].fRect, fClears[currClear].fColor, fClears[currClear].fRenderTarget); ++currClear; break; } } // we should have consumed all the states, clips, etc. GrAssert(fStates.count() == currState); GrAssert(fClips.count() == currClip); GrAssert(fClipOrigins.count() == currClip); GrAssert(fClears.count() == currClear); GrAssert(fDraws.count() == currDraw); target->setDrawState(prevDrawState); prevDrawState->unref(); this->reset(); return true; }
bool GrInOrderDrawBuffer::needsNewState() const { // we should have recorded a default state in reset() GrAssert(!fStates.empty()); return fStates.back() != this->getDrawState(); }
void GrMemoryPool::validate() { #ifdef SK_DEBUG BlockHeader* block = fHead; BlockHeader* prev = NULL; GrAssert(block); int allocCount = 0; do { allocCount += block->fLiveCount; GrAssert(prev == block->fPrev); if (NULL != prev) { GrAssert(prev->fNext == block); } intptr_t b = reinterpret_cast<intptr_t>(block); size_t ptrOffset = block->fCurrPtr - b; size_t totalSize = ptrOffset + block->fFreeSize; size_t userSize = totalSize - kHeaderSize; intptr_t userStart = b + kHeaderSize; GrAssert(!(b % kAlignment)); GrAssert(!(totalSize % kAlignment)); GrAssert(!(userSize % kAlignment)); GrAssert(!(block->fCurrPtr % kAlignment)); if (fHead != block) { GrAssert(block->fLiveCount); GrAssert(userSize >= fMinAllocSize); } else { GrAssert(userSize == fPreallocSize); } if (!block->fLiveCount) { GrAssert(ptrOffset == kHeaderSize); GrAssert(userStart == block->fCurrPtr); } else { GrAssert(block == *reinterpret_cast<BlockHeader**>(userStart)); } prev = block; } while ((block = block->fNext)); GrAssert(allocCount == fAllocationCnt); GrAssert(prev == fTail); #endif }
const char* GrGLSLVectorNonhomogCoords(int count) { static const char* NONHOMOGS[] = {"ERROR", "", ".x", ".xy", ".xyz"}; GrAssert(count >= 1 && count < (int)GR_ARRAY_COUNT(NONHOMOGS)); return NONHOMOGS[count]; }
void GrDrawTarget::setSamplerState(int stage, const GrSamplerState& state) { GrAssert(stage >= 0 && stage < kNumStages); fCurrDrawState.fSamplerStates[stage] = state; }
bool GrInOrderDrawBuffer::flush() { GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fVertexSrc); GrAssert(kReserved_GeometrySrcType != this->getGeomSrc().fIndexSrc); int numCmds = fCmds.count(); if (0 == numCmds) { return false; } GrAssert(!fFlushing); GrAutoTRestore<bool> flushRestore(&fFlushing); fFlushing = true; fVertexPool.unlock(); fIndexPool.unlock(); GrDrawTarget::AutoClipRestore acr(fDstGpu); AutoGeometryAndStatePush agasp(fDstGpu, kPreserve_ASRInit); GrDrawState playbackState; GrDrawState* prevDrawState = fDstGpu->drawState(); prevDrawState->ref(); fDstGpu->setDrawState(&playbackState); GrClipData clipData; int currState = 0; int currClip = 0; int currClear = 0; int currDraw = 0; int currStencilPath = 0; int currCopySurface = 0; for (int c = 0; c < numCmds; ++c) { switch (fCmds[c]) { case kDraw_Cmd: { const DrawRecord& draw = fDraws[currDraw]; fDstGpu->setVertexSourceToBuffer(draw.fVertexBuffer); if (draw.isIndexed()) { fDstGpu->setIndexSourceToBuffer(draw.fIndexBuffer); } fDstGpu->executeDraw(draw); ++currDraw; break; } case kStencilPath_Cmd: { const StencilPath& sp = fStencilPaths[currStencilPath]; fDstGpu->stencilPath(sp.fPath.get(), sp.fStroke, sp.fFill); ++currStencilPath; break; } case kSetState_Cmd: fStates[currState].restoreTo(&playbackState); ++currState; break; case kSetClip_Cmd: clipData.fClipStack = &fClips[currClip]; clipData.fOrigin = fClipOrigins[currClip]; fDstGpu->setClip(&clipData); ++currClip; break; case kClear_Cmd: fDstGpu->clear(&fClears[currClear].fRect, fClears[currClear].fColor, fClears[currClear].fRenderTarget); ++currClear; break; case kCopySurface_Cmd: fDstGpu->copySurface(fCopySurfaces[currCopySurface].fDst.get(), fCopySurfaces[currCopySurface].fSrc.get(), fCopySurfaces[currCopySurface].fSrcRect, fCopySurfaces[currCopySurface].fDstPoint); ++currCopySurface; break; } } // we should have consumed all the states, clips, etc. GrAssert(fStates.count() == currState); GrAssert(fClips.count() == currClip); GrAssert(fClipOrigins.count() == currClip); GrAssert(fClears.count() == currClear); GrAssert(fDraws.count() == currDraw); GrAssert(fCopySurfaces.count() == currCopySurface); fDstGpu->setDrawState(prevDrawState); prevDrawState->unref(); this->reset(); return true; }
GrDrawTarget::BlendOptFlags GrDrawTarget::getBlendOpts(bool forceCoverage, GrBlendCoeff* srcCoeff, GrBlendCoeff* dstCoeff) const { const GrVertexLayout& layout = this->getGeomSrc().fVertexLayout; GrBlendCoeff bogusSrcCoeff, bogusDstCoeff; if (NULL == srcCoeff) { srcCoeff = &bogusSrcCoeff; } *srcCoeff = fCurrDrawState.fSrcBlend; if (NULL == dstCoeff) { dstCoeff = &bogusDstCoeff; } *dstCoeff = fCurrDrawState.fDstBlend; // We don't ever expect source coeffecients to reference the source GrAssert(kSA_BlendCoeff != *srcCoeff && kISA_BlendCoeff != *srcCoeff && kSC_BlendCoeff != *srcCoeff && kISC_BlendCoeff != *srcCoeff); // same for dst GrAssert(kDA_BlendCoeff != *dstCoeff && kIDA_BlendCoeff != *dstCoeff && kDC_BlendCoeff != *dstCoeff && kIDC_BlendCoeff != *dstCoeff); if (SkToBool(kNoColorWrites_StateBit & fCurrDrawState.fFlagBits)) { *srcCoeff = kZero_BlendCoeff; *dstCoeff = kOne_BlendCoeff; } bool srcAIsOne = this->srcAlphaWillBeOne(); bool dstCoeffIsOne = kOne_BlendCoeff == *dstCoeff || (kSA_BlendCoeff == *dstCoeff && srcAIsOne); bool dstCoeffIsZero = kZero_BlendCoeff == *dstCoeff || (kISA_BlendCoeff == *dstCoeff && srcAIsOne); // When coeffs are (0,1) there is no reason to draw at all, unless // stenciling is enabled. Having color writes disabled is effectively // (0,1). if ((kZero_BlendCoeff == *srcCoeff && dstCoeffIsOne)) { if (fCurrDrawState.fStencilSettings.doesWrite()) { if (fCaps.fShaderSupport) { return kDisableBlend_BlendOptFlag | kEmitTransBlack_BlendOptFlag; } else { return kDisableBlend_BlendOptFlag; } } else { return kSkipDraw_BlendOptFlag; } } // check for coverage due to edge aa or coverage texture stage bool hasCoverage = forceCoverage || fCurrDrawState.fEdgeAANumEdges > 0 || (layout & kCoverage_VertexLayoutBit) || (layout & kEdge_VertexLayoutBit); for (int s = fCurrDrawState.fFirstCoverageStage; !hasCoverage && s < kNumStages; ++s) { if (StageWillBeUsed(s, layout, fCurrDrawState)) { hasCoverage = true; } } // if we don't have coverage we can check whether the dst // has to read at all. If not, we'll disable blending. if (!hasCoverage) { if (dstCoeffIsZero) { if (kOne_BlendCoeff == *srcCoeff) { // if there is no coverage and coeffs are (1,0) then we // won't need to read the dst at all, it gets replaced by src return kDisableBlend_BlendOptFlag; } else if (kZero_BlendCoeff == *srcCoeff && fCaps.fShaderSupport) { // if the op is "clear" then we don't need to emit a color // or blend, just write transparent black into the dst. *srcCoeff = kOne_BlendCoeff; *dstCoeff = kZero_BlendCoeff; return kDisableBlend_BlendOptFlag | kEmitTransBlack_BlendOptFlag; } } } else { // check whether coverage can be safely rolled into alpha // of if we can skip color computation and just emit coverage if (this->canTweakAlphaForCoverage()) { return kCoverageAsAlpha_BlendOptFlag; } // We haven't implemented support for these optimizations in the // fixed pipe (which is on its deathbed) if (fCaps.fShaderSupport) { if (dstCoeffIsZero) { if (kZero_BlendCoeff == *srcCoeff) { // the source color is not included in the blend // the dst coeff is effectively zero so blend works out to: // (c)(0)D + (1-c)D = (1-c)D. *dstCoeff = kISA_BlendCoeff; return kEmitCoverage_BlendOptFlag; } else if (srcAIsOne) { // the dst coeff is effectively zero so blend works out to: // cS + (c)(0)D + (1-c)D = cS + (1-c)D. // If Sa is 1 then we can replace Sa with c // and set dst coeff to 1-Sa. *dstCoeff = kISA_BlendCoeff; return kCoverageAsAlpha_BlendOptFlag; } } else if (dstCoeffIsOne) { // the dst coeff is effectively one so blend works out to: // cS + (c)(1)D + (1-c)D = cS + D. *dstCoeff = kOne_BlendCoeff; return kCoverageAsAlpha_BlendOptFlag; } } } return kNone_BlendOpt; }
void GrDrawTarget::setEdgeAAData(const Edge* edges, int numEdges) { GrAssert(numEdges <= kMaxEdges); memcpy(fCurrDrawState.fEdgeAAEdges, edges, numEdges * sizeof(Edge)); fCurrDrawState.fEdgeAANumEdges = numEdges; }
void GrGpuGLShaders::buildProgram(GrPrimitiveType type, BlendOptFlags blendOpts, GrBlendCoeff dstCoeff) { ProgramDesc& desc = fCurrentProgram.fProgramDesc; const GrDrawState& drawState = this->getDrawState(); // This should already have been caught GrAssert(!(kSkipDraw_BlendOptFlag & blendOpts)); bool skipCoverage = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag); bool skipColor = SkToBool(blendOpts & (kEmitTransBlack_BlendOptFlag | kEmitCoverage_BlendOptFlag)); // The descriptor is used as a cache key. Thus when a field of the // descriptor will not affect program generation (because of the vertex // layout in use or other descriptor field settings) it should be set // to a canonical value to avoid duplicate programs with different keys. // Must initialize all fields or cache will have false negatives! desc.fVertexLayout = this->getGeomSrc().fVertexLayout; desc.fEmitsPointSize = kPoints_PrimitiveType == type; bool requiresAttributeColors = !skipColor && SkToBool(desc.fVertexLayout & kColor_VertexLayoutBit); // fColorInput records how colors are specified for the program. Strip // the bit from the layout to avoid false negatives when searching for an // existing program in the cache. desc.fVertexLayout &= ~(kColor_VertexLayoutBit); desc.fColorFilterXfermode = skipColor ? SkXfermode::kDst_Mode : drawState.getColorFilterMode(); // no reason to do edge aa or look at per-vertex coverage if coverage is // ignored if (skipCoverage) { desc.fVertexLayout &= ~(kEdge_VertexLayoutBit | kCoverage_VertexLayoutBit); } bool colorIsTransBlack = SkToBool(blendOpts & kEmitTransBlack_BlendOptFlag); bool colorIsSolidWhite = (blendOpts & kEmitCoverage_BlendOptFlag) || (!requiresAttributeColors && 0xffffffff == drawState.getColor()); if (GR_AGGRESSIVE_SHADER_OPTS && colorIsTransBlack) { desc.fColorInput = ProgramDesc::kTransBlack_ColorInput; } else if (GR_AGGRESSIVE_SHADER_OPTS && colorIsSolidWhite) { desc.fColorInput = ProgramDesc::kSolidWhite_ColorInput; } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) { desc.fColorInput = ProgramDesc::kUniform_ColorInput; } else { desc.fColorInput = ProgramDesc::kAttribute_ColorInput; } desc.fEdgeAANumEdges = skipCoverage ? 0 : drawState.getNumAAEdges(); desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 && drawState.isConcaveEdgeAAState(); int lastEnabledStage = -1; if (!skipCoverage && (desc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit)) { desc.fVertexEdgeType = drawState.getVertexEdgeType(); } else { // use canonical value when not set to avoid cache misses desc.fVertexEdgeType = GrDrawState::kHairLine_EdgeType; } for (int s = 0; s < GrDrawState::kNumStages; ++s) { StageDesc& stage = desc.fStages[s]; stage.fOptFlags = 0; stage.setEnabled(this->isStageEnabled(s)); bool skip = s < drawState.getFirstCoverageStage() ? skipColor : skipCoverage; if (!skip && stage.isEnabled()) { lastEnabledStage = s; const GrGLTexture* texture = static_cast<const GrGLTexture*>(drawState.getTexture(s)); GrAssert(NULL != texture); const GrSamplerState& sampler = drawState.getSampler(s); // we matrix to invert when orientation is TopDown, so make sure // we aren't in that case before flagging as identity. if (TextureMatrixIsIdentity(texture, sampler)) { stage.fOptFlags |= StageDesc::kIdentityMatrix_OptFlagBit; } else if (!sampler.getMatrix().hasPerspective()) { stage.fOptFlags |= StageDesc::kNoPerspective_OptFlagBit; } switch (sampler.getSampleMode()) { case GrSamplerState::kNormal_SampleMode: stage.fCoordMapping = StageDesc::kIdentity_CoordMapping; break; case GrSamplerState::kRadial_SampleMode: stage.fCoordMapping = StageDesc::kRadialGradient_CoordMapping; break; case GrSamplerState::kRadial2_SampleMode: if (sampler.radial2IsDegenerate()) { stage.fCoordMapping = StageDesc::kRadial2GradientDegenerate_CoordMapping; } else { stage.fCoordMapping = StageDesc::kRadial2Gradient_CoordMapping; } break; case GrSamplerState::kSweep_SampleMode: stage.fCoordMapping = StageDesc::kSweepGradient_CoordMapping; break; default: GrCrash("Unexpected sample mode!"); break; } switch (sampler.getFilter()) { // these both can use a regular texture2D() case GrSamplerState::kNearest_Filter: case GrSamplerState::kBilinear_Filter: stage.fFetchMode = StageDesc::kSingle_FetchMode; break; // performs 4 texture2D()s case GrSamplerState::k4x4Downsample_Filter: stage.fFetchMode = StageDesc::k2x2_FetchMode; break; // performs fKernelWidth texture2D()s case GrSamplerState::kConvolution_Filter: stage.fFetchMode = StageDesc::kConvolution_FetchMode; break; default: GrCrash("Unexpected filter!"); break; } if (sampler.hasTextureDomain()) { GrAssert(GrSamplerState::kClamp_WrapMode == sampler.getWrapX() && GrSamplerState::kClamp_WrapMode == sampler.getWrapY()); stage.fOptFlags |= StageDesc::kCustomTextureDomain_OptFlagBit; } stage.fInConfigFlags = 0; if (!this->glCaps().fTextureSwizzleSupport) { if (GrPixelConfigIsAlphaOnly(texture->config())) { // if we don't have texture swizzle support then // the shader must do an alpha smear after reading // the texture stage.fInConfigFlags |= StageDesc::kSmearAlpha_InConfigFlag; } else if (sampler.swapsRAndB()) { stage.fInConfigFlags |= StageDesc::kSwapRAndB_InConfigFlag; } } if (GrPixelConfigIsUnpremultiplied(texture->config())) { stage.fInConfigFlags |= StageDesc::kMulRGBByAlpha_InConfigFlag; } if (sampler.getFilter() == GrSamplerState::kConvolution_Filter) { stage.fKernelWidth = sampler.getKernelWidth(); } else { stage.fKernelWidth = 0; } } else { stage.fOptFlags = 0; stage.fCoordMapping = (StageDesc::CoordMapping) 0; stage.fInConfigFlags = 0; stage.fFetchMode = (StageDesc::FetchMode) 0; stage.fKernelWidth = 0; } } if (GrPixelConfigIsUnpremultiplied(drawState.getRenderTarget()->config())) { desc.fOutputPM = ProgramDesc::kNo_OutputPM; } else { desc.fOutputPM = ProgramDesc::kYes_OutputPM; } desc.fDualSrcOutput = ProgramDesc::kNone_DualSrcOutput; // currently the experimental GS will only work with triangle prims // (and it doesn't do anything other than pass through values from // the VS to the FS anyway). #if 0 && GR_GL_EXPERIMENTAL_GS desc.fExperimentalGS = this->getCaps().fGeometryShaderSupport; #endif // we want to avoid generating programs with different "first cov stage" // values when they would compute the same result. // We set field in the desc to kNumStages when either there are no // coverage stages or the distinction between coverage and color is // immaterial. int firstCoverageStage = GrDrawState::kNumStages; desc.fFirstCoverageStage = GrDrawState::kNumStages; bool hasCoverage = drawState.getFirstCoverageStage() <= lastEnabledStage; if (hasCoverage) { firstCoverageStage = drawState.getFirstCoverageStage(); } // other coverage inputs if (!hasCoverage) { hasCoverage = desc.fEdgeAANumEdges || (desc.fVertexLayout & GrDrawTarget::kCoverage_VertexLayoutBit) || (desc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit); } if (hasCoverage) { // color filter is applied between color/coverage computation if (SkXfermode::kDst_Mode != desc.fColorFilterXfermode) { desc.fFirstCoverageStage = firstCoverageStage; } if (this->getCaps().fDualSourceBlendingSupport && !(blendOpts & (kEmitCoverage_BlendOptFlag | kCoverageAsAlpha_BlendOptFlag))) { if (kZero_BlendCoeff == dstCoeff) { // write the coverage value to second color desc.fDualSrcOutput = ProgramDesc::kCoverage_DualSrcOutput; desc.fFirstCoverageStage = firstCoverageStage; } else if (kSA_BlendCoeff == dstCoeff) { // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially // cover desc.fDualSrcOutput = ProgramDesc::kCoverageISA_DualSrcOutput; desc.fFirstCoverageStage = firstCoverageStage; } else if (kSC_BlendCoeff == dstCoeff) { // SA dst coeff becomes 1-(1-SA)*coverage when dst is partially // cover desc.fDualSrcOutput = ProgramDesc::kCoverageISC_DualSrcOutput; desc.fFirstCoverageStage = firstCoverageStage; } } } }
bool GrDrawTarget::VertexUsesStage(int stage, GrVertexLayout vertexLayout) { GrAssert(stage < kNumStages); GrAssert(check_layout(vertexLayout)); return !!(stage_mask(stage) & vertexLayout); }
void GrGpu::removeResource(GrResource* resource) { GrAssert(NULL != resource); GrAssert(this == resource->getGpu()); fResourceList.remove(resource); }
bool GrDrawTarget::VertexUsesTexCoordIdx(int coordIndex, GrVertexLayout vertexLayout) { GrAssert(coordIndex < kMaxTexCoords); GrAssert(check_layout(vertexLayout)); return !!(tex_coord_idx_mask(coordIndex) & vertexLayout); }
void GrGpu::resolveRenderTarget(GrRenderTarget* target) { GrAssert(target); this->handleDirtyContext(); this->onResolveRenderTarget(target); }
void GrDrawTarget::VertexLayoutUnitTest() { // not necessarily exhaustive static bool run; if (!run) { run = true; for (int s = 0; s < kNumStages; ++s) { GrAssert(!VertexUsesStage(s, 0)); GrAssert(-1 == VertexStageCoordOffset(s, 0)); GrVertexLayout stageMask = 0; for (int t = 0; t < kMaxTexCoords; ++t) { stageMask |= StageTexCoordVertexLayoutBit(s,t); } GrAssert(1 == kMaxTexCoords || !check_layout(stageMask)); GrAssert(stage_tex_coord_mask(s) == stageMask); stageMask |= StagePosAsTexCoordVertexLayoutBit(s); GrAssert(stage_mask(s) == stageMask); GrAssert(!check_layout(stageMask)); } for (int t = 0; t < kMaxTexCoords; ++t) { GrVertexLayout tcMask = 0; GrAssert(!VertexUsesTexCoordIdx(t, 0)); for (int s = 0; s < kNumStages; ++s) { tcMask |= StageTexCoordVertexLayoutBit(s,t); GrAssert(VertexUsesStage(s, tcMask)); GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask)); GrAssert(VertexUsesTexCoordIdx(t, tcMask)); GrAssert(2*sizeof(GrPoint) == VertexSize(tcMask)); GrAssert(t == VertexTexCoordsForStage(s, tcMask)); for (int s2 = s + 1; s2 < kNumStages; ++s2) { GrAssert(-1 == VertexStageCoordOffset(s2, tcMask)); GrAssert(!VertexUsesStage(s2, tcMask)); GrAssert(-1 == VertexTexCoordsForStage(s2, tcMask)); #if GR_DEBUG GrVertexLayout posAsTex = tcMask | StagePosAsTexCoordVertexLayoutBit(s2); #endif GrAssert(0 == VertexStageCoordOffset(s2, posAsTex)); GrAssert(VertexUsesStage(s2, posAsTex)); GrAssert(2*sizeof(GrPoint) == VertexSize(posAsTex)); GrAssert(-1 == VertexTexCoordsForStage(s2, posAsTex)); GrAssert(-1 == VertexEdgeOffset(posAsTex)); } GrAssert(-1 == VertexEdgeOffset(tcMask)); GrAssert(-1 == VertexColorOffset(tcMask)); GrAssert(-1 == VertexCoverageOffset(tcMask)); #if GR_DEBUG GrVertexLayout withColor = tcMask | kColor_VertexLayoutBit; #endif GrAssert(-1 == VertexCoverageOffset(withColor)); GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColor)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColor)); #if GR_DEBUG GrVertexLayout withEdge = tcMask | kEdge_VertexLayoutBit; #endif GrAssert(-1 == VertexColorOffset(withEdge)); GrAssert(2*sizeof(GrPoint) == VertexEdgeOffset(withEdge)); GrAssert(4*sizeof(GrPoint) == VertexSize(withEdge)); #if GR_DEBUG GrVertexLayout withColorAndEdge = withColor | kEdge_VertexLayoutBit; #endif GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withColorAndEdge)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexEdgeOffset(withColorAndEdge)); GrAssert(4*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withColorAndEdge)); #if GR_DEBUG GrVertexLayout withCoverage = tcMask | kCoverage_VertexLayoutBit; #endif GrAssert(-1 == VertexColorOffset(withCoverage)); GrAssert(2*sizeof(GrPoint) == VertexCoverageOffset(withCoverage)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexSize(withCoverage)); #if GR_DEBUG GrVertexLayout withCoverageAndColor = tcMask | kCoverage_VertexLayoutBit | kColor_VertexLayoutBit; #endif GrAssert(2*sizeof(GrPoint) == VertexColorOffset(withCoverageAndColor)); GrAssert(2*sizeof(GrPoint) + sizeof(GrColor) == VertexCoverageOffset(withCoverageAndColor)); GrAssert(2*sizeof(GrPoint) + 2 * sizeof(GrColor) == VertexSize(withCoverageAndColor)); } GrAssert(tex_coord_idx_mask(t) == tcMask); GrAssert(check_layout(tcMask)); int stageOffsets[kNumStages]; int colorOffset; int edgeOffset; int coverageOffset; int size; size = VertexSizeAndOffsetsByStage(tcMask, stageOffsets, &colorOffset, &coverageOffset, &edgeOffset); GrAssert(2*sizeof(GrPoint) == size); GrAssert(-1 == colorOffset); GrAssert(-1 == coverageOffset); GrAssert(-1 == edgeOffset); for (int s = 0; s < kNumStages; ++s) { GrAssert(VertexUsesStage(s, tcMask)); GrAssert(sizeof(GrPoint) == stageOffsets[s]); GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask)); } } } }
void GrGpu::finalizeReservedVertices() { GrAssert(NULL != fVertexPool); fVertexPool->unlock(); }
void GrDrawTarget::setTexture(int stage, GrTexture* tex) { GrAssert(stage >= 0 && stage < kNumStages); fCurrDrawState.fTextures[stage] = tex; }
void GrDefaultPathRenderer::drawPathHelper(GrDrawTarget* target, GrDrawTarget::StageBitfield stages, GrPathIter* 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 = gTolerance; if (!useStretch) { // TODO: deal with perspective in some better way. tol /= 10; } else { GrScalar sinv = GR_Scalar1 / stretch; tol = GrMul(tol, sinv); } GrScalar tolSqd = GrMul(tol, tol); path->rewind(); int subpathCnt; int maxPts = worst_case_point_count(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); path->rewind(); // 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; for (;;) { GrPathCmd cmd = path->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: { generate_quadratic_points(pts[0], pts[1], pts[2], tolSqd, &vert, quadratic_point_count(pts, tol)); break; } case kCubic_PathCmd: { generate_cubic_points(pts[0], pts[1], pts[2], pts[3], tolSqd, &vert, cubic_point_count(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]; } } } }
GrTexture* GrDrawTarget::getTexture(int stage) { GrAssert(stage >= 0 && stage < kNumStages); return fCurrDrawState.fTextures[stage]; }
bool GrGpuGL::flushGraphicsState(DrawType type) { const GrDrawState& drawState = this->getDrawState(); // GrGpu::setupClipAndFlushState should have already checked this // and bailed if not true. GrAssert(NULL != drawState.getRenderTarget()); if (kStencilPath_DrawType != type) { this->flushMiscFixedFunctionState(); GrBlendCoeff srcCoeff; GrBlendCoeff dstCoeff; BlendOptFlags blendOpts = this->getBlendOpts(false, &srcCoeff, &dstCoeff); if (kSkipDraw_BlendOptFlag & blendOpts) { return false; } const GrEffectStage* stages[GrDrawState::kNumStages]; for (int i = 0; i < GrDrawState::kNumStages; ++i) { stages[i] = drawState.isStageEnabled(i) ? &drawState.getStage(i) : NULL; } GrGLProgram::Desc desc; this->buildProgram(kDrawPoints_DrawType == type, blendOpts, dstCoeff, &desc); fCurrentProgram.reset(fProgramCache->getProgram(desc, stages)); if (NULL == fCurrentProgram.get()) { GrAssert(!"Failed to create program!"); return false; } fCurrentProgram.get()->ref(); if (fHWProgramID != fCurrentProgram->fProgramID) { GL_CALL(UseProgram(fCurrentProgram->fProgramID)); fHWProgramID = fCurrentProgram->fProgramID; } fCurrentProgram->overrideBlend(&srcCoeff, &dstCoeff); this->flushBlend(kDrawLines_DrawType == type, srcCoeff, dstCoeff); GrColor color; GrColor coverage; if (blendOpts & kEmitTransBlack_BlendOptFlag) { color = 0; coverage = 0; } else if (blendOpts & kEmitCoverage_BlendOptFlag) { color = 0xffffffff; coverage = drawState.getCoverage(); } else { color = drawState.getColor(); coverage = drawState.getCoverage(); } this->flushColor(color); this->flushCoverage(coverage); fCurrentProgram->setData(drawState); for (int s = 0; s < GrDrawState::kNumStages; ++s) { if (this->isStageEnabled(s)) { this->flushBoundTextureAndParams(s); } } } this->flushStencil(type); this->flushViewMatrix(type); this->flushScissor(); this->flushAAState(type); GrIRect* devRect = NULL; GrIRect devClipBounds; if (drawState.isClipState()) { fClip->getConservativeBounds(drawState.getRenderTarget(), &devClipBounds); devRect = &devClipBounds; } // This must come after textures are flushed because a texture may need // to be msaa-resolved (which will modify bound FBO state). this->flushRenderTarget(devRect); return true; }
void GrEffect::addVertexAttrib(GrSLType type) { GrAssert(fVertexAttribTypes.count() < kMaxVertexAttribs); fVertexAttribTypes.push_back(type); }