| /* | |
| * Copyright 2014 Google Inc. | |
| * | |
| * Use of this source code is governed by a BSD-style license that can be | |
| * found in the LICENSE file. | |
| */ | |
| #include "GrOptDrawState.h" | |
| #include "GrDrawState.h" | |
| #include "GrDrawTargetCaps.h" | |
| #include "GrGpu.h" | |
| #include "GrProcOptInfo.h" | |
| #include "GrXferProcessor.h" | |
| GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, | |
| const GrGeometryProcessor* gp, | |
| const GrPathProcessor* pathProc, | |
| const GrDrawTargetCaps& caps, | |
| const GrScissorState& scissorState, | |
| const GrDeviceCoordTexture* dstCopy, | |
| GrGpu::DrawType drawType) | |
| : fFinalized(false) { | |
| fDrawType = drawType; | |
| // Copy GeometryProcesssor from DS or ODS | |
| if (gp) { | |
| SkASSERT(!pathProc); | |
| SkASSERT(!GrGpu::IsPathRenderingDrawType(drawType)); | |
| fGeometryProcessor.reset(gp); | |
| fPrimitiveProcessor.reset(gp); | |
| } else { | |
| SkASSERT(!gp && pathProc && GrGpu::IsPathRenderingDrawType(drawType)); | |
| fPrimitiveProcessor.reset(pathProc); | |
| } | |
| const GrProcOptInfo& colorPOI = drawState.colorProcInfo(fPrimitiveProcessor); | |
| const GrProcOptInfo& coveragePOI = drawState.coverageProcInfo(fPrimitiveProcessor); | |
| // Create XferProcessor from DS's XPFactory | |
| SkAutoTUnref<GrXferProcessor> xferProcessor( | |
| drawState.getXPFactory()->createXferProcessor(colorPOI, coveragePOI)); | |
| GrColor overrideColor = GrColor_ILLEGAL; | |
| if (colorPOI.firstEffectiveStageIndex() != 0) { | |
| overrideColor = colorPOI.inputColorToEffectiveStage(); | |
| } | |
| GrXferProcessor::OptFlags optFlags; | |
| if (xferProcessor) { | |
| fXferProcessor.reset(xferProcessor.get()); | |
| optFlags = xferProcessor->getOptimizations(colorPOI, | |
| coveragePOI, | |
| drawState.getStencil().doesWrite(), | |
| &overrideColor, | |
| caps); | |
| } | |
| // When path rendering the stencil settings are not always set on the draw state | |
| // so we must check the draw type. In cases where we will skip drawing we simply return a | |
| // null GrOptDrawState. | |
| if (!xferProcessor || (GrXferProcessor::kSkipDraw_OptFlag & optFlags)) { | |
| // Set the fields that don't default init and return. The lack of a render target will | |
| // indicate that this can be skipped. | |
| fFlags = 0; | |
| fDrawFace = GrDrawState::kInvalid_DrawFace; | |
| return; | |
| } | |
| fRenderTarget.reset(drawState.fRenderTarget.get()); | |
| SkASSERT(fRenderTarget); | |
| fScissorState = scissorState; | |
| fStencilSettings = drawState.getStencil(); | |
| fDrawFace = drawState.getDrawFace(); | |
| // TODO move this out of optDrawState | |
| if (dstCopy) { | |
| fDstCopy = *dstCopy; | |
| } | |
| fFlags = 0; | |
| if (drawState.isHWAntialias()) { | |
| fFlags |= kHWAA_Flag; | |
| } | |
| if (drawState.isDither()) { | |
| fFlags |= kDither_Flag; | |
| } | |
| // TODO move local coords completely into GP | |
| bool hasLocalCoords = gp && gp->hasLocalCoords(); | |
| int firstColorStageIdx = colorPOI.firstEffectiveStageIndex(); | |
| // TODO: Once we can handle single or four channel input into coverage stages then we can use | |
| // drawState's coverageProcInfo (like color above) to set this initial information. | |
| int firstCoverageStageIdx = 0; | |
| GrXferProcessor::BlendInfo blendInfo; | |
| fXferProcessor->getBlendInfo(&blendInfo); | |
| this->adjustProgramFromOptimizations(drawState, optFlags, colorPOI, coveragePOI, | |
| &firstColorStageIdx, &firstCoverageStageIdx); | |
| fDescInfo.fRequiresLocalCoordAttrib = hasLocalCoords; | |
| bool usesLocalCoords = false; | |
| // Copy Stages from DS to ODS | |
| for (int i = firstColorStageIdx; i < drawState.numColorStages(); ++i) { | |
| SkNEW_APPEND_TO_TARRAY(&fFragmentStages, | |
| GrPendingFragmentStage, | |
| (drawState.fColorStages[i])); | |
| usesLocalCoords = usesLocalCoords || | |
| drawState.fColorStages[i].processor()->usesLocalCoords(); | |
| } | |
| fNumColorStages = fFragmentStages.count(); | |
| for (int i = firstCoverageStageIdx; i < drawState.numCoverageStages(); ++i) { | |
| SkNEW_APPEND_TO_TARRAY(&fFragmentStages, | |
| GrPendingFragmentStage, | |
| (drawState.fCoverageStages[i])); | |
| usesLocalCoords = usesLocalCoords || | |
| drawState.fCoverageStages[i].processor()->usesLocalCoords(); | |
| } | |
| // let the GP init the batch tracker | |
| GrGeometryProcessor::InitBT init; | |
| init.fColorIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreColor_OptFlag); | |
| init.fOverrideColor = init.fColorIgnored ? GrColor_ILLEGAL : overrideColor; | |
| init.fCoverageIgnored = SkToBool(optFlags & GrXferProcessor::kIgnoreCoverage_OptFlag); | |
| init.fUsesLocalCoords = usesLocalCoords; | |
| fPrimitiveProcessor->initBatchTracker(&fBatchTracker, init); | |
| } | |
| void GrOptDrawState::adjustProgramFromOptimizations(const GrDrawState& ds, | |
| GrXferProcessor::OptFlags flags, | |
| const GrProcOptInfo& colorPOI, | |
| const GrProcOptInfo& coveragePOI, | |
| int* firstColorStageIdx, | |
| int* firstCoverageStageIdx) { | |
| fDescInfo.fReadsDst = false; | |
| fDescInfo.fReadsFragPosition = false; | |
| if ((flags & GrXferProcessor::kIgnoreColor_OptFlag) || | |
| (flags & GrXferProcessor::kOverrideColor_OptFlag)) { | |
| *firstColorStageIdx = ds.numColorStages(); | |
| } else { | |
| fDescInfo.fReadsDst = colorPOI.readsDst(); | |
| fDescInfo.fReadsFragPosition = colorPOI.readsFragPosition(); | |
| } | |
| if (flags & GrXferProcessor::kIgnoreCoverage_OptFlag) { | |
| *firstCoverageStageIdx = ds.numCoverageStages(); | |
| } else { | |
| if (coveragePOI.readsDst()) { | |
| fDescInfo.fReadsDst = true; | |
| } | |
| if (coveragePOI.readsFragPosition()) { | |
| fDescInfo.fReadsFragPosition = true; | |
| } | |
| } | |
| } | |
| void GrOptDrawState::finalize(GrGpu* gpu) { | |
| gpu->buildProgramDesc(*this, fDescInfo, fDrawType, &fDesc); | |
| fFinalized = true; | |
| } | |
| //////////////////////////////////////////////////////////////////////////////// | |
| bool GrOptDrawState::combineIfPossible(const GrOptDrawState& that) { | |
| if (fDescInfo != that.fDescInfo) { | |
| return false; | |
| } | |
| if (this->getRenderTarget() != that.getRenderTarget() || | |
| this->fFragmentStages.count() != that.fFragmentStages.count() || | |
| this->fNumColorStages != that.fNumColorStages || | |
| this->fScissorState != that.fScissorState || | |
| this->fDrawType != that.fDrawType || | |
| this->fFlags != that.fFlags || | |
| this->fStencilSettings != that.fStencilSettings || | |
| this->fDrawFace != that.fDrawFace || | |
| this->fDstCopy.texture() != that.fDstCopy.texture()) { | |
| return false; | |
| } | |
| if (!this->getPrimitiveProcessor()->canMakeEqual(fBatchTracker, | |
| *that.getPrimitiveProcessor(), | |
| that.getBatchTracker())) { | |
| return false; | |
| } | |
| if (!this->getXferProcessor()->isEqual(*that.getXferProcessor())) { | |
| return false; | |
| } | |
| // The program desc comparison should have already assured that the stage counts match. | |
| SkASSERT(this->numFragmentStages() == that.numFragmentStages()); | |
| for (int i = 0; i < this->numFragmentStages(); i++) { | |
| if (this->getFragmentStage(i) != that.getFragmentStage(i)) { | |
| return false; | |
| } | |
| } | |
| // Now update the GrPrimitiveProcessor's batch tracker | |
| fPrimitiveProcessor->makeEqual(&fBatchTracker, that.getBatchTracker()); | |
| return true; | |
| } | |