void GrGpu::writeTexturePixels(GrTexture* texture, int left, int top, int width, int height, GrPixelConfig config, const void* buffer, size_t rowBytes) { GrAssert(GrPixelConfigIsUnpremultiplied(config) == GrPixelConfigIsUnpremultiplied(texture->config())); this->handleDirtyContext(); this->onWriteTexturePixels(texture, left, top, width, height, config, buffer, rowBytes); }
bool GrGpu::readPixels(GrRenderTarget* target, int left, int top, int width, int height, GrPixelConfig config, void* buffer, size_t rowBytes, bool invertY) { GrAssert(GrPixelConfigIsUnpremultiplied(config) == GrPixelConfigIsUnpremultiplied(target->config())); this->handleDirtyContext(); return this->onReadPixels(target, left, top, width, height, config, buffer, rowBytes, invertY); }
void GrGpuGLShaders::buildProgram(GrPrimitiveType type, BlendOptFlags blendOpts, GrBlendCoeff dstCoeff, GrCustomStage** customStages) { 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->getVertexLayout(); desc.fEmitsPointSize = kPoints_PrimitiveType == type; bool requiresAttributeColors = !skipColor && SkToBool(desc.fVertexLayout & kColor_VertexLayoutBit); bool requiresAttributeCoverage = !skipCoverage && SkToBool(desc.fVertexLayout & kCoverage_VertexLayoutBit); // fColorInput/fCoverageInput records how colors are specified for the. // program. So we strip the bits from the layout to avoid false negatives // when searching for an existing program in the cache. desc.fVertexLayout &= ~(kColor_VertexLayoutBit | kCoverage_VertexLayoutBit); desc.fColorFilterXfermode = skipColor ? SkXfermode::kDst_Mode : drawState.getColorFilterMode(); desc.fColorMatrixEnabled = drawState.isStateFlagEnabled(GrDrawState::kColorMatrix_StateBit); // 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; } bool covIsSolidWhite = !requiresAttributeCoverage && 0xffffffff == drawState.getCoverage(); if (skipCoverage) { desc.fCoverageInput = ProgramDesc::kTransBlack_ColorInput; } else if (covIsSolidWhite) { desc.fCoverageInput = ProgramDesc::kSolidWhite_ColorInput; } else if (GR_GL_NO_CONSTANT_ATTRIBUTES && !requiresAttributeCoverage) { desc.fCoverageInput = ProgramDesc::kUniform_ColorInput; } else { desc.fCoverageInput = ProgramDesc::kAttribute_ColorInput; } 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; case GrSamplerState::kDilate_Filter: stage.fFetchMode = StageDesc::kDilate_FetchMode; break; case GrSamplerState::kErode_Filter: stage.fFetchMode = StageDesc::kErode_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().textureSwizzleSupport()) { if (GrPixelConfigIsAlphaOnly(texture->config())) { // if we don't have texture swizzle support then // the shader must smear the single channel after // reading the texture if (this->glCaps().textureRedSupport()) { // we can use R8 textures so use kSmearRed stage.fInConfigFlags |= StageDesc::kSmearRed_InConfigFlag; } else { // we can use A8 textures so use kSmearAlpha stage.fInConfigFlags |= StageDesc::kSmearAlpha_InConfigFlag; } } else if (sampler.swapsRAndB()) { stage.fInConfigFlags |= StageDesc::kSwapRAndB_InConfigFlag; } } if (GrPixelConfigIsUnpremultiplied(texture->config())) { // The shader generator assumes that color channels are bytes // when rounding. GrAssert(4 == GrBytesPerPixel(texture->config())); if (kUpOnWrite_DownOnRead_UnpremulConversion == fUnpremulConversion) { stage.fInConfigFlags |= StageDesc::kMulRGBByAlpha_RoundDown_InConfigFlag; } else { stage.fInConfigFlags |= StageDesc::kMulRGBByAlpha_RoundUp_InConfigFlag; } } if (sampler.getFilter() == GrSamplerState::kDilate_Filter || sampler.getFilter() == GrSamplerState::kErode_Filter) { stage.fKernelWidth = sampler.getKernelWidth(); } else { stage.fKernelWidth = 0; } setup_custom_stage(&stage, sampler, customStages, &fCurrentProgram, s); } else { stage.fOptFlags = 0; stage.fCoordMapping = (StageDesc::CoordMapping) 0; stage.fInConfigFlags = 0; stage.fFetchMode = (StageDesc::FetchMode) 0; stage.fKernelWidth = 0; stage.fCustomStageKey = 0; customStages[s] = NULL; } } if (GrPixelConfigIsUnpremultiplied(drawState.getRenderTarget()->config())) { // The shader generator assumes that color channels are bytes // when rounding. GrAssert(4 == GrBytesPerPixel(drawState.getRenderTarget()->config())); if (kUpOnWrite_DownOnRead_UnpremulConversion == fUnpremulConversion) { desc.fOutputConfig = ProgramDesc::kUnpremultiplied_RoundUp_OutputConfig; } else { desc.fOutputConfig = ProgramDesc::kUnpremultiplied_RoundDown_OutputConfig; } } else { desc.fOutputConfig = ProgramDesc::kPremultiplied_OutputConfig; } 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 = requiresAttributeCoverage || (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::checkDraw(GrPrimitiveType type, int startVertex, int startIndex, int vertexCount, int indexCount) const { #if GR_DEBUG const GeometrySrcState& geoSrc = fGeoSrcStateStack.back(); int maxVertex = startVertex + vertexCount; int maxValidVertex; switch (geoSrc.fVertexSrc) { case kNone_GeometrySrcType: GrCrash("Attempting to draw without vertex src."); case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: maxValidVertex = geoSrc.fVertexCount; break; case kBuffer_GeometrySrcType: maxValidVertex = geoSrc.fVertexBuffer->sizeInBytes() / VertexSize(geoSrc.fVertexLayout); break; } if (maxVertex > maxValidVertex) { GrCrash("Drawing outside valid vertex range."); } if (indexCount > 0) { int maxIndex = startIndex + indexCount; int maxValidIndex; switch (geoSrc.fIndexSrc) { case kNone_GeometrySrcType: GrCrash("Attempting to draw indexed geom without index src."); case kReserved_GeometrySrcType: // fallthrough case kArray_GeometrySrcType: maxValidIndex = geoSrc.fIndexCount; break; case kBuffer_GeometrySrcType: maxValidIndex = geoSrc.fIndexBuffer->sizeInBytes() / sizeof(uint16_t); break; } if (maxIndex > maxValidIndex) { GrCrash("Index reads outside valid index range."); } } GrAssert(NULL != this->getDrawState().getRenderTarget()); for (int i = 0; i < GrDrawState::kNumStages; ++i) { if (this->getDrawState().getTexture(i)) { GrAssert(this->getDrawState().getTexture(i)->asRenderTarget() != this->getDrawState().getRenderTarget()); } } #endif const GrDrawState& drawState = this->getDrawState(); if (NULL == drawState.getRenderTarget()) { return false; } if (GrPixelConfigIsUnpremultiplied(drawState.getRenderTarget()->config())) { if (kOne_BlendCoeff != drawState.getSrcBlendCoeff() || kZero_BlendCoeff != drawState.getDstBlendCoeff()) { return false; } } for (int s = 0; s < GrDrawState::kNumStages; ++s) { // We don't support using unpremultiplied textures with filters (other // than nearest). Alpha-premulling is not distributive WRT to filtering. // We'd have to filter each texel before filtering. We could do this for // our custom filters but we would also have to disable bilerp and do // a custom bilerp in the shader. Until Skia itself supports unpremul // configs there is no pressure to implement this. if (this->isStageEnabled(s) && GrPixelConfigIsUnpremultiplied(drawState.getTexture(s)->config()) && GrSamplerState::kNearest_Filter != drawState.getSampler(s).getFilter()) { return false; } } return true; }