Ejemplo n.º 1
0
const GrGLenum* GrGLShaderBuilder::GetTexParamSwizzle(GrPixelConfig config, const GrGLCaps& caps) {
    if (caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(config)) {
        if (caps.textureRedSupport()) {
            static const GrGLenum gRedSmear[] = { GR_GL_RED, GR_GL_RED, GR_GL_RED, GR_GL_RED };
            return gRedSmear;
        } else {
            static const GrGLenum gAlphaSmear[] = { GR_GL_ALPHA, GR_GL_ALPHA,
                                                    GR_GL_ALPHA, GR_GL_ALPHA };
            return gAlphaSmear;
        }
    } else {
        static const GrGLenum gStraight[] = { GR_GL_RED, GR_GL_GREEN, GR_GL_BLUE, GR_GL_ALPHA };
        return gStraight;
    }
}
GrTextureAdjuster::GrTextureAdjuster(GrTexture* original, SkAlphaType alphaType,
                                     const SkIRect& contentArea, uint32_t uniqueID,
                                     SkColorSpace* cs)
    : INHERITED(contentArea.width(), contentArea.height(),
                GrPixelConfigIsAlphaOnly(original->config()))
    , fOriginal(original)
    , fAlphaType(alphaType)
    , fColorSpace(cs)
    , fUniqueID(uniqueID)
{
    SkASSERT(SkIRect::MakeWH(original->width(), original->height()).contains(contentArea));
    if (contentArea.fLeft > 0 || contentArea.fTop > 0 ||
        contentArea.fRight < original->width() || contentArea.fBottom < original->height()) {
        fContentArea.set(contentArea);
    }
}
Ejemplo n.º 3
0
const GrFragmentProcessor* SkImageShader::asFragmentProcessor(GrContext* context,
                                                              const SkMatrix& viewM,
                                                              const SkMatrix* localMatrix,
                                                              SkFilterQuality filterQuality) const {
    SkMatrix matrix;
    matrix.setIDiv(fImage->width(), fImage->height());

    SkMatrix lmInverse;
    if (!this->getLocalMatrix().invert(&lmInverse)) {
        return nullptr;
    }
    if (localMatrix) {
        SkMatrix inv;
        if (!localMatrix->invert(&inv)) {
            return nullptr;
        }
        lmInverse.postConcat(inv);
    }
    matrix.preConcat(lmInverse);

    SkShader::TileMode tm[] = { fTileModeX, fTileModeY };

    // Must set wrap and filter on the sampler before requesting a texture. In two places below
    // we check the matrix scale factors to determine how to interpret the filter quality setting.
    // This completely ignores the complexity of the drawVertices case where explicit local coords
    // are provided by the caller.
    bool doBicubic;
    GrTextureParams::FilterMode textureFilterMode =
    GrSkFilterQualityToGrFilterMode(filterQuality, viewM, this->getLocalMatrix(), &doBicubic);
    GrTextureParams params(tm, textureFilterMode);
    SkAutoTUnref<GrTexture> texture(as_IB(fImage)->asTextureRef(context, params));
    if (!texture) {
        return nullptr;
    }

    SkAutoTUnref<const GrFragmentProcessor> inner;
    if (doBicubic) {
        inner.reset(GrBicubicEffect::Create(texture, matrix, tm));
    } else {
        inner.reset(GrSimpleTextureEffect::Create(texture, matrix, params));
    }

    if (GrPixelConfigIsAlphaOnly(texture->config())) {
        return SkRef(inner.get());
    }
    return GrFragmentProcessor::MulOutputByInputAlpha(inner);
}
Ejemplo n.º 4
0
std::unique_ptr<GrFragmentProcessor> SkImageShader::asFragmentProcessor(
        const GrFPArgs& args) const {
    const auto lm = this->totalLocalMatrix(args.fPreLocalMatrix, args.fPostLocalMatrix);
    SkMatrix lmInverse;
    if (!lm->invert(&lmInverse)) {
        return nullptr;
    }

    GrSamplerState::WrapMode wrapModes[] = {tile_mode_to_wrap_mode(fTileModeX),
                                            tile_mode_to_wrap_mode(fTileModeY)};

    // Must set wrap and filter on the sampler before requesting a texture. In two places below
    // we check the matrix scale factors to determine how to interpret the filter quality setting.
    // This completely ignores the complexity of the drawVertices case where explicit local coords
    // are provided by the caller.
    bool doBicubic;
    GrSamplerState::Filter textureFilterMode = GrSkFilterQualityToGrFilterMode(
            args.fFilterQuality, *args.fViewMatrix, *lm,
            args.fContext->contextPriv().sharpenMipmappedTextures(), &doBicubic);
    GrSamplerState samplerState(wrapModes, textureFilterMode);
    sk_sp<SkColorSpace> texColorSpace;
    SkScalar scaleAdjust[2] = { 1.0f, 1.0f };
    sk_sp<GrTextureProxy> proxy(as_IB(fImage)->asTextureProxyRef(
            args.fContext, samplerState, args.fDstColorSpaceInfo->colorSpace(), &texColorSpace,
            scaleAdjust));
    if (!proxy) {
        return nullptr;
    }

    GrPixelConfig config = proxy->config();
    bool isAlphaOnly = GrPixelConfigIsAlphaOnly(config);

    lmInverse.postScale(scaleAdjust[0], scaleAdjust[1]);

    std::unique_ptr<GrFragmentProcessor> inner;
    if (doBicubic) {
        inner = GrBicubicEffect::Make(std::move(proxy), lmInverse, wrapModes);
    } else {
        inner = GrSimpleTextureEffect::Make(std::move(proxy), lmInverse, samplerState);
    }
    inner = GrColorSpaceXformEffect::Make(std::move(inner), texColorSpace.get(), config,
                                          args.fDstColorSpaceInfo->colorSpace());
    if (isAlphaOnly) {
        return inner;
    }
    return GrFragmentProcessor::MulChildByInputAlpha(std::move(inner));
}
Ejemplo n.º 5
0
GrGLShaderBuilder::DstReadKey GrGLShaderBuilder::KeyForDstRead(const GrTexture* dstCopy,
                                                               const GrGLCaps& caps) {
    uint32_t key = kYesDstRead_DstReadKeyBit;
    if (caps.fbFetchSupport()) {
        return key;
    }
    SkASSERT(NULL != dstCopy);
    if (!caps.textureSwizzleSupport() && GrPixelConfigIsAlphaOnly(dstCopy->config())) {
        // The fact that the config is alpha-only must be considered when generating code.
        key |= kUseAlphaConfig_DstReadKeyBit;
    }
    if (kTopLeft_GrSurfaceOrigin == dstCopy->origin()) {
        key |= kTopLeftOrigin_DstReadKeyBit;
    }
    SkASSERT(static_cast<DstReadKey>(key) == key);
    return static_cast<DstReadKey>(key);
}
Ejemplo n.º 6
0
void GrTextContext::flushGlyphs() {
    if (NULL == fDrawTarget) {
        return;
    }
    GrDrawState* drawState = fDrawTarget->drawState();
    if (fCurrVertex > 0) {
        // setup our sampler state for our text texture/atlas
        drawState->stage(kGlyphMaskStage)->reset();

        GrAssert(GrIsALIGN4(fCurrVertex));
        GrAssert(fCurrTexture);
        GrTextureParams params(SkShader::kRepeat_TileMode, false);
        drawState->createTextureEffect(kGlyphMaskStage, fCurrTexture, SkMatrix::I(), params);

        if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
            if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
                    kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
                    fPaint.hasColorStage()) {
                GrPrintf("LCD Text will not draw correctly.\n");
            }
            // setup blend so that we get mask * paintColor + (1-mask)*dstColor
            drawState->setBlendConstant(fPaint.getColor());
            drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
            // don't modulate by the paint's color in the frag since we're
            // already doing it via the blend const.
            drawState->setColor(0xffffffff);
        } else {
            // set back to normal in case we took LCD path previously.
            drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
            drawState->setColor(fPaint.getColor());
        }

        int nGlyphs = fCurrVertex / 4;
        fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
        fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
                                          nGlyphs,
                                          4, 6);
        fDrawTarget->resetVertexSource();
        fVertices = NULL;
        fMaxVertices = 0;
        fCurrVertex = 0;
        GrSafeSetNull(fCurrTexture);
    }
    drawState->disableStages();
    fDrawTarget = NULL;
}
Ejemplo n.º 7
0
void GrVkCaps::initGLSLCaps(const VkPhysicalDeviceProperties& properties,
                            uint32_t featureFlags) {
    GrGLSLCaps* glslCaps = static_cast<GrGLSLCaps*>(fShaderCaps.get());
    glslCaps->fVersionDeclString = "#version 330\n";


    // fConfigOutputSwizzle will default to RGBA so we only need to set it for alpha only config.
    for (int i = 0; i < kGrPixelConfigCnt; ++i) {
        GrPixelConfig config = static_cast<GrPixelConfig>(i);
        if (GrPixelConfigIsAlphaOnly(config)) {
            glslCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRR();
            glslCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA();
        } else {
            glslCaps->fConfigTextureSwizzle[i] = GrSwizzle::RGBA();
        }
    }

    // Vulkan is based off ES 3.0 so the following should all be supported
    glslCaps->fUsesPrecisionModifiers = true;
    glslCaps->fFlatInterpolationSupport = true;

    // GrShaderCaps

    glslCaps->fShaderDerivativeSupport = true;
    glslCaps->fGeometryShaderSupport = SkToBool(featureFlags & kGeometryShader_GrVkFeatureFlag);

    glslCaps->fDualSourceBlendingSupport = SkToBool(featureFlags & kDualSrcBlend_GrVkFeatureFlag);

    glslCaps->fIntegerSupport = true;

    glslCaps->fMaxVertexSamplers =
    glslCaps->fMaxGeometrySamplers =
    glslCaps->fMaxFragmentSamplers = SkTMin(properties.limits.maxPerStageDescriptorSampledImages,
                                            properties.limits.maxPerStageDescriptorSamplers);
    glslCaps->fMaxCombinedSamplers = SkTMin(properties.limits.maxDescriptorSetSampledImages,
                                            properties.limits.maxDescriptorSetSamplers);
}
Ejemplo n.º 8
0
void GrVkCaps::initGLSLCaps(const VkPhysicalDeviceProperties& properties,
                            uint32_t featureFlags) {
    GrGLSLCaps* glslCaps = static_cast<GrGLSLCaps*>(fShaderCaps.get());
    glslCaps->fVersionDeclString = "#version 330\n";


    // fConfigOutputSwizzle will default to RGBA so we only need to set it for alpha only config.
    for (int i = 0; i < kGrPixelConfigCnt; ++i) {
        GrPixelConfig config = static_cast<GrPixelConfig>(i);
        if (GrPixelConfigIsAlphaOnly(config)) {
            glslCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRR();
            glslCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA();
        } else {
            if (kRGBA_4444_GrPixelConfig == config) {
                // The vulkan spec does not require R4G4B4A4 to be supported for texturing so we
                // store the data in a B4G4R4A4 texture and then swizzle it when doing texture reads
                // or writing to outputs. Since we're not actually changing the data at all, the
                // only extra work is the swizzle in the shader for all operations.
                glslCaps->fConfigTextureSwizzle[i] = GrSwizzle::BGRA();
                glslCaps->fConfigOutputSwizzle[i] = GrSwizzle::BGRA();
            } else {
                glslCaps->fConfigTextureSwizzle[i] = GrSwizzle::RGBA();
            }
        }
    }

    // Vulkan is based off ES 3.0 so the following should all be supported
    glslCaps->fUsesPrecisionModifiers = true;
    glslCaps->fFlatInterpolationSupport = true;

    // GrShaderCaps

    glslCaps->fShaderDerivativeSupport = true;
    glslCaps->fGeometryShaderSupport = SkToBool(featureFlags & kGeometryShader_GrVkFeatureFlag);

    glslCaps->fDualSourceBlendingSupport = SkToBool(featureFlags & kDualSrcBlend_GrVkFeatureFlag);

    glslCaps->fIntegerSupport = true;

    // Assume the minimum precisions mandated by the SPIR-V spec.
    glslCaps->fShaderPrecisionVaries = true;
    for (int s = 0; s < kGrShaderTypeCount; ++s) {
        auto& highp = glslCaps->fFloatPrecisions[s][kHigh_GrSLPrecision];
        highp.fLogRangeLow = highp.fLogRangeHigh = 127;
        highp.fBits = 23;

        auto& mediump = glslCaps->fFloatPrecisions[s][kMedium_GrSLPrecision];
        mediump.fLogRangeLow = mediump.fLogRangeHigh = 14;
        mediump.fBits = 10;

        glslCaps->fFloatPrecisions[s][kLow_GrSLPrecision] = mediump;
    }
    glslCaps->initSamplerPrecisionTable();

    glslCaps->fMaxVertexSamplers =
        glslCaps->fMaxGeometrySamplers =
            glslCaps->fMaxFragmentSamplers = SkTMin(SkTMin(properties.limits.maxPerStageDescriptorSampledImages,
                    properties.limits.maxPerStageDescriptorSamplers),
                    (uint32_t)INT_MAX);
    glslCaps->fMaxCombinedSamplers = SkTMin(SkTMin(properties.limits.maxDescriptorSetSampledImages,
                                            properties.limits.maxDescriptorSetSamplers),
                                            (uint32_t)INT_MAX);
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
static GrTexture* copy_on_gpu(GrTexture* inputTexture, const SkIRect* subset,
                              const CopyParams& copyParams) {
    SkASSERT(!subset || !subset->isEmpty());
    GrContext* context = inputTexture->getContext();
    SkASSERT(context);
    const GrCaps* caps = context->caps();

    // Either it's a cache miss or the original wasn't cached to begin with.
    GrSurfaceDesc rtDesc = inputTexture->desc();
    rtDesc.fFlags = rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
    rtDesc.fWidth = copyParams.fWidth;
    rtDesc.fHeight = copyParams.fHeight;
    rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig);

    // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise,
    // fail.
    if (!caps->isConfigRenderable(rtDesc.fConfig, false)) {
        if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) {
            if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
                rtDesc.fConfig = kAlpha_8_GrPixelConfig;
            } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
                rtDesc.fConfig = kSkia8888_GrPixelConfig;
            } else {
                return nullptr;
            }
        } else if (kRGB_GrColorComponentFlags ==
                   (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) {
            if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
                rtDesc.fConfig = kSkia8888_GrPixelConfig;
            } else {
                return nullptr;
            }
        } else {
            return nullptr;
        }
    }

    SkAutoTUnref<GrTexture> copy(context->textureProvider()->createTexture(rtDesc,
                                                                           SkBudgeted::kYes));
    if (!copy) {
        return nullptr;
    }

    // TODO: If no scaling is being performed then use copySurface.

    GrPaint paint;
    paint.setGammaCorrect(true);

    // TODO: Initializing these values for no reason cause the compiler is complaining
    SkScalar sx = 0.f;
    SkScalar sy = 0.f;
    if (subset) {
        sx = 1.f / inputTexture->width();
        sy = 1.f / inputTexture->height();
    }

    if (copyParams.fFilter != GrTextureParams::kNone_FilterMode && subset &&
        (subset->width() != copyParams.fWidth || subset->height() != copyParams.fHeight)) {
        SkRect domain;
        domain.fLeft = (subset->fLeft + 0.5f) * sx;
        domain.fTop = (subset->fTop + 0.5f)* sy;
        domain.fRight = (subset->fRight - 0.5f) * sx;
        domain.fBottom = (subset->fBottom - 0.5f) * sy;
        // This would cause us to read values from outside the subset. Surely, the caller knows
        // better!
        SkASSERT(copyParams.fFilter != GrTextureParams::kMipMap_FilterMode);
        paint.addColorFragmentProcessor(
            GrTextureDomainEffect::Make(inputTexture, SkMatrix::I(), domain,
                                        GrTextureDomain::kClamp_Mode,
                                        copyParams.fFilter));
    } else {
        GrTextureParams params(SkShader::kClamp_TileMode, copyParams.fFilter);
        paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);
    }
    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);

    SkRect localRect;
    if (subset) {
        localRect = SkRect::Make(*subset);
        localRect.fLeft *= sx;
        localRect.fTop *= sy;
        localRect.fRight *= sx;
        localRect.fBottom *= sy;
    } else {
        localRect = SkRect::MakeWH(1.f, 1.f);
    }

    sk_sp<GrDrawContext> drawContext(context->drawContext(sk_ref_sp(copy->asRenderTarget())));
    if (!drawContext) {
        return nullptr;
    }

    SkRect dstRect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
    drawContext->fillRectToRect(GrNoClip(), paint, SkMatrix::I(), dstRect, localRect);
    return copy.release();
}
Ejemplo n.º 11
0
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;
        }
    }
}
Ejemplo n.º 12
0
// creates a new texture that is the input texture scaled up. If optionalKey is valid it will be
// set on the new texture. stretch controls whether the scaling is done using nearest or bilerp
// filtering and the size to stretch the texture to.
GrTexture* stretch_texture(GrTexture* inputTexture, const SkGrStretch& stretch,
                           SkPixelRef* pixelRef,
                           const GrUniqueKey& optionalKey) {
    SkASSERT(SkGrStretch::kNone_Type != stretch.fType);

    GrContext* context = inputTexture->getContext();
    SkASSERT(context);
    const GrCaps* caps = context->caps();

    // Either it's a cache miss or the original wasn't cached to begin with.
    GrSurfaceDesc rtDesc = inputTexture->desc();
    rtDesc.fFlags =  rtDesc.fFlags | kRenderTarget_GrSurfaceFlag;
    rtDesc.fWidth  = stretch.fWidth;
    rtDesc.fHeight = stretch.fHeight;
    rtDesc.fConfig = GrMakePixelConfigUncompressed(rtDesc.fConfig);

    // If the config isn't renderable try converting to either A8 or an 32 bit config. Otherwise,
    // fail.
    if (!caps->isConfigRenderable(rtDesc.fConfig, false)) {
        if (GrPixelConfigIsAlphaOnly(rtDesc.fConfig)) {
            if (caps->isConfigRenderable(kAlpha_8_GrPixelConfig, false)) {
                rtDesc.fConfig = kAlpha_8_GrPixelConfig;
            } else if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
                rtDesc.fConfig = kSkia8888_GrPixelConfig;
            } else {
                return nullptr;
            }
        } else if (kRGB_GrColorComponentFlags ==
                   (kRGB_GrColorComponentFlags & GrPixelConfigComponentMask(rtDesc.fConfig))) {
            if (caps->isConfigRenderable(kSkia8888_GrPixelConfig, false)) {
                rtDesc.fConfig = kSkia8888_GrPixelConfig;
            } else {
                return nullptr;
            }
        } else {
            return nullptr;
        }
    }

    SkAutoTUnref<GrTexture> stretched(GrCreateTextureForPixels(context, optionalKey, rtDesc,
                                                               pixelRef, nullptr,0));
    if (!stretched) {
        return nullptr;
    }
    GrPaint paint;

    // If filtering is not desired then we want to ensure all texels in the resampled image are
    // copies of texels from the original.
    GrTextureParams params(SkShader::kClamp_TileMode,
                           SkGrStretch::kBilerp_Type == stretch.fType ?
                              GrTextureParams::kBilerp_FilterMode :
                              GrTextureParams::kNone_FilterMode);
    paint.addColorTextureProcessor(inputTexture, SkMatrix::I(), params);

    SkRect rect = SkRect::MakeWH(SkIntToScalar(rtDesc.fWidth), SkIntToScalar(rtDesc.fHeight));
    SkRect localRect = SkRect::MakeWH(1.f, 1.f);

    SkAutoTUnref<GrDrawContext> drawContext(context->drawContext());
    if (!drawContext) {
        return nullptr;
    }

    drawContext->drawNonAARectToRect(stretched->asRenderTarget(), GrClip::WideOpen(), paint,
                                     SkMatrix::I(), rect, localRect);

    return stretched.detach();
}
Ejemplo n.º 13
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;
            }
        }
    }
}
Ejemplo n.º 14
0
void GrVkCaps::initShaderCaps(const VkPhysicalDeviceProperties& properties, uint32_t featureFlags) {
    GrShaderCaps* shaderCaps = fShaderCaps.get();
    shaderCaps->fVersionDeclString = "#version 330\n";


    // fConfigOutputSwizzle will default to RGBA so we only need to set it for alpha only config.
    for (int i = 0; i < kGrPixelConfigCnt; ++i) {
        GrPixelConfig config = static_cast<GrPixelConfig>(i);
        if (GrPixelConfigIsAlphaOnly(config)) {
            shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRR();
            shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::AAAA();
        } else {
            if (kGray_8_GrPixelConfig == config) {
                shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RRRA();
            } else if (kRGBA_4444_GrPixelConfig == config) {
                // The vulkan spec does not require R4G4B4A4 to be supported for texturing so we
                // store the data in a B4G4R4A4 texture and then swizzle it when doing texture reads
                // or writing to outputs. Since we're not actually changing the data at all, the
                // only extra work is the swizzle in the shader for all operations.
                shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::BGRA();
                shaderCaps->fConfigOutputSwizzle[i] = GrSwizzle::BGRA();
            } else {
                shaderCaps->fConfigTextureSwizzle[i] = GrSwizzle::RGBA();
            }
        }
    }

    if (kImagination_VkVendor == properties.vendorID) {
        shaderCaps->fAtan2ImplementedAsAtanYOverX = true;
    }

    // Vulkan is based off ES 3.0 so the following should all be supported
    shaderCaps->fUsesPrecisionModifiers = true;
    shaderCaps->fFlatInterpolationSupport = true;

    // GrShaderCaps

    shaderCaps->fShaderDerivativeSupport = true;
    shaderCaps->fGeometryShaderSupport = SkToBool(featureFlags & kGeometryShader_GrVkFeatureFlag);

    shaderCaps->fDualSourceBlendingSupport = SkToBool(featureFlags & kDualSrcBlend_GrVkFeatureFlag);
    if (kAMD_VkVendor == properties.vendorID) {
        // Currently DualSourceBlending is not working on AMD. vkCreateGraphicsPipeline fails when
        // using a draw with dual source. Looking into whether it is driver bug or issue with our
        // SPIR-V. Bug skia:6405
        shaderCaps->fDualSourceBlendingSupport = false;
    }

    shaderCaps->fIntegerSupport = true;
    shaderCaps->fTexelBufferSupport = true;
    shaderCaps->fTexelFetchSupport = true;
    shaderCaps->fVertexIDSupport = true;

    // Assume the minimum precisions mandated by the SPIR-V spec.
    shaderCaps->fShaderPrecisionVaries = true;
    for (int s = 0; s < kGrShaderTypeCount; ++s) {
        auto& highp = shaderCaps->fFloatPrecisions[s][kHigh_GrSLPrecision];
        highp.fLogRangeLow = highp.fLogRangeHigh = 127;
        highp.fBits = 23;

        auto& mediump = shaderCaps->fFloatPrecisions[s][kMedium_GrSLPrecision];
        mediump.fLogRangeLow = mediump.fLogRangeHigh = 14;
        mediump.fBits = 10;

        shaderCaps->fFloatPrecisions[s][kLow_GrSLPrecision] = mediump;
    }
    shaderCaps->initSamplerPrecisionTable();

    shaderCaps->fMaxVertexSamplers =
    shaderCaps->fMaxGeometrySamplers =
    shaderCaps->fMaxFragmentSamplers = SkTMin(
                                       SkTMin(properties.limits.maxPerStageDescriptorSampledImages,
                                              properties.limits.maxPerStageDescriptorSamplers),
                                              (uint32_t)INT_MAX);
    shaderCaps->fMaxCombinedSamplers = SkTMin(
                                       SkTMin(properties.limits.maxDescriptorSetSampledImages,
                                              properties.limits.maxDescriptorSetSamplers),
                                              (uint32_t)INT_MAX);
}