/* * Copyright 2012 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "GrDrawState.h" #include "GrGpuVertex.h" #include "GrPaint.h" void GrDrawState::setFromPaint(const GrPaint& paint) { for (int i = 0; i < GrPaint::kMaxColorStages; ++i) { int s = i + GrPaint::kFirstColorStage; if (paint.isColorStageEnabled(i)) { fStages[s] = paint.getColorStage(i); } else { fStages[s].setEffect(NULL); } } this->setFirstCoverageStage(GrPaint::kFirstCoverageStage); for (int i = 0; i < GrPaint::kMaxCoverageStages; ++i) { int s = i + GrPaint::kFirstCoverageStage; if (paint.isCoverageStageEnabled(i)) { fStages[s] = paint.getCoverageStage(i); } else { fStages[s].setEffect(NULL); } } // disable all stages not accessible via the paint for (int s = GrPaint::kTotalStages; s < GrDrawState::kNumStages; ++s) { this->disableStage(s); } this->setColor(paint.getColor()); this->setState(GrDrawState::kDither_StateBit, paint.isDither()); this->setState(GrDrawState::kHWAntialias_StateBit, paint.isAntiAlias()); this->setBlendFunc(paint.getSrcBlendCoeff(), paint.getDstBlendCoeff()); this->setColorFilter(paint.getColorFilterColor(), paint.getColorFilterMode()); this->setCoverage(paint.getCoverage()); } //////////////////////////////////////////////////////////////////////////////// namespace { /** * This function generates some masks that we like to have known at compile * time. When the number of stages or tex coords is bumped or the way bits * are defined in GrDrawState.h changes this function should be rerun to * generate the new masks. (We attempted to force the compiler to generate the * masks using recursive templates but always wound up with static initializers * under gcc, even if they were just a series of immediate->memory moves.) * */ void gen_mask_arrays(GrVertexLayout* stageTexCoordMasks, GrVertexLayout* texCoordMasks) { for (int s = 0; s < GrDrawState::kNumStages; ++s) { stageTexCoordMasks[s] = 0; for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { stageTexCoordMasks[s] |= GrDrawState::StageTexCoordVertexLayoutBit(s, t); } } for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { texCoordMasks[t] = 0; for (int s = 0; s < GrDrawState::kNumStages; ++s) { texCoordMasks[t] |= GrDrawState::StageTexCoordVertexLayoutBit(s, t); } } } /** * Uncomment and run the gen_globals function to generate * the code that declares the global masks. * * #if 0'ed out to avoid unused function warning. */ #if 0 void gen_globals() { GrVertexLayout stageTexCoordMasks[GrDrawState::kNumStages]; GrVertexLayout texCoordMasks[GrDrawState::kMaxTexCoords]; gen_mask_arrays(stageTexCoordMasks, texCoordMasks); GrPrintf("const GrVertexLayout gStageTexCoordMasks[] = {\n"); for (int s = 0; s < GrDrawState::kNumStages; ++s) { GrPrintf(" 0x%x,\n", stageTexCoordMasks[s]); } GrPrintf("};\n"); GrPrintf("GR_STATIC_ASSERT(GrDrawState::kNumStages == GR_ARRAY_COUNT(gStageTexCoordMasks));\n\n"); GrPrintf("const GrVertexLayout gTexCoordMasks[] = {\n"); for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { GrPrintf(" 0x%x,\n", texCoordMasks[t]); } GrPrintf("};\n"); GrPrintf("GR_STATIC_ASSERT(GrDrawState::kMaxTexCoords == GR_ARRAY_COUNT(gTexCoordMasks));\n"); } #endif /* These values were generated by the above function */ const GrVertexLayout gStageTexCoordMasks[] = { 0x108421, 0x210842, 0x421084, 0x842108, 0x1084210, }; GR_STATIC_ASSERT(GrDrawState::kNumStages == GR_ARRAY_COUNT(gStageTexCoordMasks)); const GrVertexLayout gTexCoordMasks[] = { 0x1f, 0x3e0, 0x7c00, 0xf8000, 0x1f00000, }; GR_STATIC_ASSERT(GrDrawState::kMaxTexCoords == GR_ARRAY_COUNT(gTexCoordMasks)); #ifdef SK_DEBUG bool check_layout(GrVertexLayout layout) { // can only have 1 or 0 bits set for each stage. for (int s = 0; s < GrDrawState::kNumStages; ++s) { int stageBits = layout & gStageTexCoordMasks[s]; if (stageBits && !GrIsPow2(stageBits)) { return false; } } return true; } #endif int num_tex_coords(GrVertexLayout layout) { int cnt = 0; // figure out how many tex coordinates are present for (int t = 0; t < GrDrawState::kMaxTexCoords; ++t) { if (gTexCoordMasks[t] & layout) { ++cnt; } } return cnt; } } //unnamed namespace size_t GrDrawState::VertexSize(GrVertexLayout vertexLayout) { GrAssert(check_layout(vertexLayout)); size_t vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ? sizeof(GrGpuTextVertex) : sizeof(GrPoint); size_t size = vecSize; // position size += num_tex_coords(vertexLayout) * vecSize; if (vertexLayout & kColor_VertexLayoutBit) { size += sizeof(GrColor); } if (vertexLayout & kCoverage_VertexLayoutBit) { size += sizeof(GrColor); } if (vertexLayout & kEdge_VertexLayoutBit) { size += 4 * sizeof(SkScalar); } return size; } //////////////////////////////////////////////////////////////////////////////// /** * Functions for computing offsets of various components from the layout * bitfield. * * Order of vertex components: * Position * Tex Coord 0 * ... * Tex Coord GrDrawState::kMaxTexCoords-1 * Color * Coverage */ int GrDrawState::VertexStageCoordOffset(int stageIdx, GrVertexLayout vertexLayout) { GrAssert(check_layout(vertexLayout)); if (!StageUsesTexCoords(vertexLayout, stageIdx)) { return 0; } int tcIdx = VertexTexCoordsForStage(stageIdx, vertexLayout); if (tcIdx >= 0) { int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ? sizeof(GrGpuTextVertex) : sizeof(GrPoint); int offset = vecSize; // position // figure out how many tex coordinates are present and precede this one. for (int t = 0; t < tcIdx; ++t) { if (gTexCoordMasks[t] & vertexLayout) { offset += vecSize; } } return offset; } return -1; } int GrDrawState::VertexColorOffset(GrVertexLayout vertexLayout) { GrAssert(check_layout(vertexLayout)); if (vertexLayout & kColor_VertexLayoutBit) { int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ? sizeof(GrGpuTextVertex) : sizeof(GrPoint); return vecSize * (num_tex_coords(vertexLayout) + 1); //+1 for pos } return -1; } int GrDrawState::VertexCoverageOffset(GrVertexLayout vertexLayout) { GrAssert(check_layout(vertexLayout)); if (vertexLayout & kCoverage_VertexLayoutBit) { int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ? sizeof(GrGpuTextVertex) : sizeof(GrPoint); int offset = vecSize * (num_tex_coords(vertexLayout) + 1); if (vertexLayout & kColor_VertexLayoutBit) { offset += sizeof(GrColor); } return offset; } return -1; } int GrDrawState::VertexEdgeOffset(GrVertexLayout vertexLayout) { GrAssert(check_layout(vertexLayout)); // edge pts are after the pos, tex coords, and color if (vertexLayout & kEdge_VertexLayoutBit) { int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ? sizeof(GrGpuTextVertex) : sizeof(GrPoint); int offset = vecSize * (num_tex_coords(vertexLayout) + 1); //+1 for pos if (vertexLayout & kColor_VertexLayoutBit) { offset += sizeof(GrColor); } if (vertexLayout & kCoverage_VertexLayoutBit) { offset += sizeof(GrColor); } return offset; } return -1; } int GrDrawState::VertexSizeAndOffsetsByIdx( GrVertexLayout vertexLayout, int texCoordOffsetsByIdx[kMaxTexCoords], int* colorOffset, int* coverageOffset, int* edgeOffset) { GrAssert(check_layout(vertexLayout)); int vecSize = (vertexLayout & kTextFormat_VertexLayoutBit) ? sizeof(GrGpuTextVertex) : sizeof(GrPoint); int size = vecSize; // position for (int t = 0; t < kMaxTexCoords; ++t) { if (gTexCoordMasks[t] & vertexLayout) { if (NULL != texCoordOffsetsByIdx) { texCoordOffsetsByIdx[t] = size; } size += vecSize; } else { if (NULL != texCoordOffsetsByIdx) { texCoordOffsetsByIdx[t] = -1; } } } if (kColor_VertexLayoutBit & vertexLayout) { if (NULL != colorOffset) { *colorOffset = size; } size += sizeof(GrColor); } else { if (NULL != colorOffset) { *colorOffset = -1; } } if (kCoverage_VertexLayoutBit & vertexLayout) { if (NULL != coverageOffset) { *coverageOffset = size; } size += sizeof(GrColor); } else { if (NULL != coverageOffset) { *coverageOffset = -1; } } if (kEdge_VertexLayoutBit & vertexLayout) { if (NULL != edgeOffset) { *edgeOffset = size; } size += 4 * sizeof(SkScalar); } else { if (NULL != edgeOffset) { *edgeOffset = -1; } } return size; } int GrDrawState::VertexSizeAndOffsetsByStage( GrVertexLayout vertexLayout, int texCoordOffsetsByStage[GrDrawState::kNumStages], int* colorOffset, int* coverageOffset, int* edgeOffset) { GrAssert(check_layout(vertexLayout)); int texCoordOffsetsByIdx[kMaxTexCoords]; int size = VertexSizeAndOffsetsByIdx(vertexLayout, (NULL == texCoordOffsetsByStage) ? NULL : texCoordOffsetsByIdx, colorOffset, coverageOffset, edgeOffset); if (NULL != texCoordOffsetsByStage) { for (int s = 0; s < GrDrawState::kNumStages; ++s) { int tcIdx = VertexTexCoordsForStage(s, vertexLayout); texCoordOffsetsByStage[s] = tcIdx < 0 ? 0 : texCoordOffsetsByIdx[tcIdx]; } } return size; } //////////////////////////////////////////////////////////////////////////////// bool GrDrawState::VertexUsesTexCoordIdx(int coordIndex, GrVertexLayout vertexLayout) { GrAssert(coordIndex < kMaxTexCoords); GrAssert(check_layout(vertexLayout)); return !!(gTexCoordMasks[coordIndex] & vertexLayout); } int GrDrawState::VertexTexCoordsForStage(int stageIdx, GrVertexLayout vertexLayout) { GrAssert(stageIdx < GrDrawState::kNumStages); GrAssert(check_layout(vertexLayout)); int bit = vertexLayout & gStageTexCoordMasks[stageIdx]; if (bit) { // figure out which set of texture coordates is used // bits are ordered T0S0, T0S1, T0S2, ..., T1S0, T1S1, ... // and start at bit 0. GR_STATIC_ASSERT(sizeof(GrVertexLayout) <= sizeof(uint32_t)); return (32 - SkCLZ(bit) - 1) / GrDrawState::kNumStages; } return -1; } //////////////////////////////////////////////////////////////////////////////// void GrDrawState::VertexLayoutUnitTest() { // Ensure that our globals mask arrays are correct GrVertexLayout stageTexCoordMasks[GrDrawState::kNumStages]; GrVertexLayout texCoordMasks[kMaxTexCoords]; gen_mask_arrays(stageTexCoordMasks, texCoordMasks); for (int s = 0; s < GrDrawState::kNumStages; ++s) { GrAssert(stageTexCoordMasks[s] == gStageTexCoordMasks[s]); } for (int t = 0; t < kMaxTexCoords; ++t) { GrAssert(texCoordMasks[t] == gTexCoordMasks[t]); } // not necessarily exhaustive static bool run; if (!run) { run = true; for (int s = 0; s < GrDrawState::kNumStages; ++s) { GrVertexLayout stageMask = 0; for (int t = 0; t < kMaxTexCoords; ++t) { stageMask |= StageTexCoordVertexLayoutBit(s,t); } GrAssert(1 == kMaxTexCoords || !check_layout(stageMask)); GrAssert(gStageTexCoordMasks[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 < GrDrawState::kNumStages; ++s) { tcMask |= StageTexCoordVertexLayoutBit(s,t); 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 < GrDrawState::kNumStages; ++s2) { GrAssert(-1 == VertexTexCoordsForStage(s2, tcMask)); #if GR_DEBUG GrVertexLayout posAsTex = tcMask; #endif GrAssert(0 == VertexStageCoordOffset(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(gTexCoordMasks[t] == tcMask); GrAssert(check_layout(tcMask)); int stageOffsets[GrDrawState::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 < GrDrawState::kNumStages; ++s) { GrAssert(sizeof(GrPoint) == stageOffsets[s]); GrAssert(sizeof(GrPoint) == VertexStageCoordOffset(s, tcMask)); } } } } //////////////////////////////////////////////////////////////////////////////// bool GrDrawState::StageUsesTexCoords(GrVertexLayout layout, int stageIdx) { return SkToBool(layout & gStageTexCoordMasks[stageIdx]); } bool GrDrawState::srcAlphaWillBeOne(GrVertexLayout layout) const { uint32_t validComponentFlags; GrColor color; // Check if per-vertex or constant color may have partial alpha if (layout & kColor_VertexLayoutBit) { validComponentFlags = 0; } else { validComponentFlags = GrEffect::kAll_ValidComponentFlags; color = this->getColor(); } // Run through the color stages int stageCnt = getFirstCoverageStage(); for (int s = 0; s < stageCnt; ++s) { const GrEffectRef* effect = this->getStage(s).getEffect(); if (NULL != effect) { (*effect)->getConstantColorComponents(&color, &validComponentFlags); } } // Check if the color filter could introduce an alpha. // We could skip the above work when this is true, but it is rare and the right fix is to make // the color filter a GrEffect and implement getConstantColorComponents() for it. if (SkXfermode::kDst_Mode != this->getColorFilterMode()) { validComponentFlags = 0; } // Check whether coverage is treated as color. If so we run through the coverage computation. if (this->isCoverageDrawing()) { GrColor coverageColor = this->getCoverage(); GrColor oldColor = color; color = 0; for (int c = 0; c < 4; ++c) { if (validComponentFlags & (1 << c)) { U8CPU a = (oldColor >> (c * 8)) & 0xff; U8CPU b = (coverageColor >> (c * 8)) & 0xff; color |= (SkMulDiv255Round(a, b) << (c * 8)); } } for (int s = this->getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) { const GrEffectRef* effect = this->getStage(s).getEffect(); if (NULL != effect) { (*effect)->getConstantColorComponents(&color, &validComponentFlags); } } } return (GrEffect::kA_ValidComponentFlag & validComponentFlags) && 0xff == GrColorUnpackA(color); } bool GrDrawState::hasSolidCoverage(GrVertexLayout layout) const { // If we're drawing coverage directly then coverage is effectively treated as color. if (this->isCoverageDrawing()) { return true; } GrColor coverage; uint32_t validComponentFlags; // Initialize to an unknown starting coverage if per-vertex coverage is specified. if (layout & kCoverage_VertexLayoutBit) { validComponentFlags = 0; } else { coverage = fCommon.fCoverage; validComponentFlags = GrEffect::kAll_ValidComponentFlags; } // Run through the coverage stages and see if the coverage will be all ones at the end. for (int s = this->getFirstCoverageStage(); s < GrDrawState::kNumStages; ++s) { const GrEffectRef* effect = this->getStage(s).getEffect(); if (NULL != effect) { (*effect)->getConstantColorComponents(&coverage, &validComponentFlags); } } return (GrEffect::kAll_ValidComponentFlags == validComponentFlags) && (0xffffffff == coverage); } //////////////////////////////////////////////////////////////////////////////// void GrDrawState::AutoViewMatrixRestore::restore() { if (NULL != fDrawState) { fDrawState->setViewMatrix(fViewMatrix); for (int s = 0; s < GrDrawState::kNumStages; ++s) { if (fRestoreMask & (1 << s)) { fDrawState->fStages[s].restoreCoordChange(fSavedCoordChanges[s]); } } } fDrawState = NULL; } void GrDrawState::AutoViewMatrixRestore::set(GrDrawState* drawState, const SkMatrix& preconcatMatrix, uint32_t explicitCoordStageMask) { this->restore(); fDrawState = drawState; if (NULL == drawState) { return; } fRestoreMask = 0; fViewMatrix = drawState->getViewMatrix(); drawState->preConcatViewMatrix(preconcatMatrix); for (int s = 0; s < GrDrawState::kNumStages; ++s) { if (!(explicitCoordStageMask & (1 << s)) && drawState->isStageEnabled(s)) { fRestoreMask |= (1 << s); fDrawState->fStages[s].saveCoordChange(&fSavedCoordChanges[s]); drawState->fStages[s].preConcatCoordChange(preconcatMatrix); } } } //////////////////////////////////////////////////////////////////////////////// void GrDrawState::AutoDeviceCoordDraw::restore() { if (NULL != fDrawState) { fDrawState->setViewMatrix(fViewMatrix); for (int s = 0; s < GrDrawState::kNumStages; ++s) { if (fRestoreMask & (1 << s)) { fDrawState->fStages[s].restoreCoordChange(fSavedCoordChanges[s]); } } } fDrawState = NULL; } bool GrDrawState::AutoDeviceCoordDraw::set(GrDrawState* drawState, uint32_t explicitCoordStageMask) { GrAssert(NULL != drawState); this->restore(); fDrawState = drawState; if (NULL == fDrawState) { return false; } fViewMatrix = drawState->getViewMatrix(); fRestoreMask = 0; SkMatrix invVM; bool inverted = false; for (int s = 0; s < GrDrawState::kNumStages; ++s) { if (!(explicitCoordStageMask & (1 << s)) && drawState->isStageEnabled(s)) { if (!inverted && !fViewMatrix.invert(&invVM)) { // sad trombone sound fDrawState = NULL; return false; } else { inverted = true; } fRestoreMask |= (1 << s); GrEffectStage* stage = drawState->fStages + s; stage->saveCoordChange(&fSavedCoordChanges[s]); stage->preConcatCoordChange(invVM); } } drawState->viewMatrix()->reset(); return true; }