示例#1
0
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);
}
示例#2
0
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);
}
示例#3
0
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;
            }
        }
    }
}
示例#4
0
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;
}