static GrSLType get_sampler_type(const GrTextureAccess& access) { GrGLTexture* glTexture = static_cast<GrGLTexture*>(access.getTexture()); if (glTexture->target() == GR_GL_TEXTURE_EXTERNAL) { return kSamplerExternal_GrSLType; } else { SkASSERT(glTexture->target() == GR_GL_TEXTURE_2D); return kSampler2D_GrSLType; } }
void GrGpuGLShaders::flushTexelSize(int s) { const int& uni = fProgramData->fUniLocations.fStages[s].fNormalizedTexelSizeUni; if (GrGLProgram::kUnusedUniform != uni) { GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; if (texture->allocatedWidth() != fProgramData->fTextureWidth[s] || texture->allocatedHeight() != fProgramData->fTextureWidth[s]) { float texelSize[] = {1.f / texture->allocatedWidth(), 1.f / texture->allocatedHeight()}; GL_CALL(Uniform2fv(uni, 1, texelSize)); } } }
void GrGpuGLShaders::flushTextureDomain(int s) { const GrGLint& uni = fProgramData->fUniLocations.fStages[s].fTexDomUni; if (GrGLProgram::kUnusedUniform != uni) { const GrRect &texDom = fCurrDrawState.fSamplerStates[s].getTextureDomain(); if (((1 << s) & fDirtyFlags.fTextureChangedMask) || fProgramData->fTextureDomain[s] != texDom) { fProgramData->fTextureDomain[s] = texDom; float values[4] = { GrScalarToFloat(texDom.left()), GrScalarToFloat(texDom.top()), GrScalarToFloat(texDom.right()), GrScalarToFloat(texDom.bottom()) }; GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; GrGLTexture::Orientation orientation = texture->orientation(); // vertical flip if necessary if (GrGLTexture::kBottomUp_Orientation == orientation) { values[1] = 1.0f - values[1]; values[3] = 1.0f - values[3]; // The top and bottom were just flipped, so correct the ordering // of elements so that values = (l, t, r, b). SkTSwap(values[1], values[3]); } values[0] *= SkScalarToFloat(texture->contentScaleX()); values[2] *= SkScalarToFloat(texture->contentScaleX()); values[1] *= SkScalarToFloat(texture->contentScaleY()); values[3] *= SkScalarToFloat(texture->contentScaleY()); GL_CALL(Uniform4fv(uni, 1, values)); } } }
bool GrGpuGLFixed::flushGraphicsState(GrPrimitiveType type) { bool usingTextures[kNumStages]; for (int s = 0; s < kNumStages; ++s) { usingTextures[s] = VertexUsesStage(s, fGeometrySrc.fVertexLayout); if (usingTextures[s] && fCurrDrawState.fSamplerStates[s].isGradient()) { unimpl("Fixed pipe doesn't support radial/sweep gradients"); return false; } } if (GR_GL_SUPPORT_ES1) { if (BlendCoefReferencesConstant(fCurrDrawState.fSrcBlend) || BlendCoefReferencesConstant(fCurrDrawState.fDstBlend)) { unimpl("ES1 doesn't support blend constant"); return false; } } if (!flushGLStateCommon(type)) { return false; } if (fDirtyFlags.fRenderTargetChanged) { flushProjectionMatrix(); } for (int s = 0; s < kNumStages; ++s) { bool wasUsingTexture = VertexUsesStage(s, fHWGeometryState.fVertexLayout); if (usingTextures[s] != wasUsingTexture) { setTextureUnit(s); if (usingTextures[s]) { GR_GL(Enable(GR_GL_TEXTURE_2D)); } else { GR_GL(Disable(GR_GL_TEXTURE_2D)); } } } uint32_t vertColor = (fGeometrySrc.fVertexLayout & kColor_VertexLayoutBit); uint32_t prevVertColor = (fHWGeometryState.fVertexLayout & kColor_VertexLayoutBit); if (vertColor != prevVertColor) { if (vertColor) { GR_GL(ShadeModel(GR_GL_SMOOTH)); // invalidate the immediate mode color fHWDrawState.fColor = GrColor_ILLEGAL; } else { GR_GL(ShadeModel(GR_GL_FLAT)); } } if (!vertColor && fHWDrawState.fColor != fCurrDrawState.fColor) { GR_GL(Color4ub(GrColorUnpackR(fCurrDrawState.fColor), GrColorUnpackG(fCurrDrawState.fColor), GrColorUnpackB(fCurrDrawState.fColor), GrColorUnpackA(fCurrDrawState.fColor))); fHWDrawState.fColor = fCurrDrawState.fColor; } // set texture environment, decide whether we are modulating by RGB or A. for (int s = 0; s < kNumStages; ++s) { if (usingTextures[s]) { GrGLTexture* texture = (GrGLTexture*)fCurrDrawState.fTextures[s]; if (NULL != texture) { TextureEnvRGBOperands nextRGBOperand0 = (GrPixelConfigIsAlphaOnly(texture->config())) ? kAlpha_TextureEnvRGBOperand : kColor_TextureEnvRGBOperand; if (fHWRGBOperand0[s] != nextRGBOperand0) { setTextureUnit(s); GR_GL(TexEnvi(GR_GL_TEXTURE_ENV, GR_GL_OPERAND0_RGB, (nextRGBOperand0==kAlpha_TextureEnvRGBOperand) ? GR_GL_SRC_ALPHA : GR_GL_SRC_COLOR)); fHWRGBOperand0[s] = nextRGBOperand0; } if (((1 << s) & fDirtyFlags.fTextureChangedMask) || (fHWDrawState.fSamplerStates[s].getMatrix() != getSamplerMatrix(s))) { GrMatrix texMat = getSamplerMatrix(s); AdjustTextureMatrix(texture, GrSamplerState::kNormal_SampleMode, &texMat); GrGpuMatrix glm; glm.set(texMat); setTextureUnit(s); GR_GL(MatrixMode(GR_GL_TEXTURE)); GR_GL(LoadMatrixf(glm.fMat)); recordHWSamplerMatrix(s, getSamplerMatrix(s)); } } else { GrAssert(!"Rendering with texture vert flag set but no bound texture"); return false; } } } if (fHWDrawState.fViewMatrix != fCurrDrawState.fViewMatrix) { GrGpuMatrix glm; glm.set(fCurrDrawState.fViewMatrix); GR_GL(MatrixMode(GR_GL_MODELVIEW)); GR_GL(LoadMatrixf(glm.fMat)); fHWDrawState.fViewMatrix = fCurrDrawState.fViewMatrix; } resetDirtyFlags(); return true; }
void GrGpuGLShaders::buildProgram(GrPrimitiveType type) { // Must initialize all fields or cache will have false negatives! fCurrentProgram.fProgramDesc.fVertexLayout = fGeometrySrc.fVertexLayout; fCurrentProgram.fProgramDesc.fOptFlags = 0; if (kPoints_PrimitiveType != type) { fCurrentProgram.fProgramDesc.fOptFlags |= GrGLProgram::ProgramDesc::kNotPoints_OptFlagBit; } #if GR_AGGRESSIVE_SHADER_OPTS if (!(fCurrentProgram.fProgramDesc.fVertexLayout & kColor_VertexLayoutBit) && (0xffffffff == fCurrDrawState.fColor)) { fCurrentProgram.fProgramDesc.fOptFlags |= GrGLProgram::ProgramDesc::kVertexColorAllOnes_OptFlagBit; } #endif for (int s = 0; s < kNumStages; ++s) { GrGLProgram::ProgramDesc::StageDesc& stage = fCurrentProgram.fProgramDesc.fStages[s]; stage.fEnabled = VertexUsesStage(s, fGeometrySrc.fVertexLayout); if (stage.fEnabled) { GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; GrAssert(NULL != texture); // we matrix to invert when orientation is TopDown, so make sure // we aren't in that case before flagging as identity. if (TextureMatrixIsIdentity(texture, fCurrDrawState.fSamplerStates[s])) { stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kIdentityMatrix_OptFlagBit; } else if (!getSamplerMatrix(s).hasPerspective()) { stage.fOptFlags = GrGLProgram::ProgramDesc::StageDesc::kNoPerspective_OptFlagBit; } else { stage.fOptFlags = 0; } switch (fCurrDrawState.fSamplerStates[s].getSampleMode()) { case GrSamplerState::kNormal_SampleMode: stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kIdentity_CoordMapping; break; case GrSamplerState::kRadial_SampleMode: stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadialGradient_CoordMapping; break; case GrSamplerState::kRadial2_SampleMode: stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kRadial2Gradient_CoordMapping; break; case GrSamplerState::kSweep_SampleMode: stage.fCoordMapping = GrGLProgram::ProgramDesc::StageDesc::kSweepGradient_CoordMapping; break; default: GrAssert(!"Unexpected sample mode!"); break; } if (GrPixelConfigIsAlphaOnly(texture->config())) { stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kAlpha_Modulation; } else { stage.fModulation = GrGLProgram::ProgramDesc::StageDesc::kColor_Modulation; } if (fCurrDrawState.fEffects[s]) { fCurrentProgram.fStageEffects[s] = GrGLEffect::Create(fCurrDrawState.fEffects[s]); } else { delete fCurrentProgram.fStageEffects[s]; fCurrentProgram.fStageEffects[s] = NULL; } } else { stage.fOptFlags = 0; stage.fCoordMapping = (GrGLProgram::ProgramDesc::StageDesc::CoordMapping)0; stage.fModulation = (GrGLProgram::ProgramDesc::StageDesc::Modulation)0; fCurrentProgram.fStageEffects[s] = NULL; } } }
void GrGpuGLShaders::buildProgram(GrPrimitiveType type, BlendOptFlags blendOpts, GrBlendCoeff dstCoeff) { ProgramDesc& desc = fCurrentProgram.fProgramDesc; // 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); // fColorType 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 : fCurrDrawState.fColorFilterXfermode; // 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 == fCurrDrawState.fColor); if (GR_AGGRESSIVE_SHADER_OPTS && colorIsTransBlack) { desc.fColorType = ProgramDesc::kTransBlack_ColorType; } else if (GR_AGGRESSIVE_SHADER_OPTS && colorIsSolidWhite) { desc.fColorType = ProgramDesc::kSolidWhite_ColorType; } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeColors) { desc.fColorType = ProgramDesc::kUniform_ColorType; } else { desc.fColorType = ProgramDesc::kAttribute_ColorType; } desc.fEdgeAANumEdges = skipCoverage ? 0 : fCurrDrawState.fEdgeAANumEdges; desc.fEdgeAAConcave = desc.fEdgeAANumEdges > 0 && SkToBool(fCurrDrawState.fFlagBits & kEdgeAAConcave_StateBit); int lastEnabledStage = -1; if (!skipCoverage && (desc.fVertexLayout & GrDrawTarget::kEdge_VertexLayoutBit)) { desc.fVertexEdgeType = fCurrDrawState.fVertexEdgeType; } 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 < fCurrDrawState.fFirstCoverageStage ? skipColor : skipCoverage; if (!skip && stage.isEnabled()) { lastEnabledStage = s; GrGLTexture* texture = (GrGLTexture*) fCurrDrawState.fTextures[s]; GrAssert(NULL != texture); const GrSamplerState& sampler = fCurrDrawState.fSamplerStates[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 (!getSamplerMatrix(s).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; } if (GrPixelConfigIsAlphaOnly(texture->config())) { stage.fModulation = StageDesc::kAlpha_Modulation; } else { stage.fModulation = StageDesc::kColor_Modulation; } if (sampler.getFilter() == GrSamplerState::kConvolution_Filter) { stage.fKernelWidth = sampler.getKernelWidth(); } else { stage.fKernelWidth = 0; } } else { stage.fOptFlags = 0; stage.fCoordMapping = (StageDesc::CoordMapping)0; stage.fModulation = (StageDesc::Modulation)0; stage.fFetchMode = (StageDesc::FetchMode) 0; stage.fKernelWidth = 0; } } 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 = fCurrDrawState.fFirstCoverageStage <= lastEnabledStage; if (hasCoverage) { firstCoverageStage = fCurrDrawState.fFirstCoverageStage; } // 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; } } } }