GrPixelConfig SkImageInfo2GrPixelConfig(const SkColorType type, SkColorSpace* cs, const GrCaps& caps) { switch (type) { case kUnknown_SkColorType: return kUnknown_GrPixelConfig; case kAlpha_8_SkColorType: return kAlpha_8_GrPixelConfig; case kRGB_565_SkColorType: return kRGB_565_GrPixelConfig; case kARGB_4444_SkColorType: return kRGBA_4444_GrPixelConfig; case kRGBA_8888_SkColorType: return (caps.srgbSupport() && cs && cs->gammaCloseToSRGB()) ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig; // TODO: We're checking for srgbSupport, but we can then end up picking sBGRA as our pixel // config (which may not be supported). We need a better test here. case kRGB_888x_SkColorType: return kUnknown_GrPixelConfig; case kBGRA_8888_SkColorType: return (caps.srgbSupport() && cs && cs->gammaCloseToSRGB()) ? kSBGRA_8888_GrPixelConfig : kBGRA_8888_GrPixelConfig; case kRGBA_1010102_SkColorType: return kRGBA_1010102_GrPixelConfig; case kRGB_101010x_SkColorType: return kUnknown_GrPixelConfig; case kGray_8_SkColorType: return kGray_8_GrPixelConfig; case kRGBA_F16_SkColorType: return kRGBA_half_GrPixelConfig; } SkASSERT(0); // shouldn't get here return kUnknown_GrPixelConfig; }
bool GrPorterDuffXPFactory::SrcOverWillNeedDstTexture(const GrCaps& caps, const GrPipelineOptimizations& optimizations) { if (caps.shaderCaps()->dstReadInShaderSupport() || caps.shaderCaps()->dualSourceBlendingSupport()) { return false; } // When we have four channel coverage we always need to read the dst in order to correctly // blend. The one exception is when we are using srcover mode and we know the input color // into the XP. if (optimizations.fCoveragePOI.isFourChannelOutput()) { if (kRGBA_GrColorComponentFlags == optimizations.fColorPOI.validFlags() && !caps.shaderCaps()->dstReadInShaderSupport()) { return false; } return get_lcd_blend_formula(optimizations.fCoveragePOI, SkBlendMode::kSrcOver).hasSecondaryOutput(); } // We fallback on the shader XP when the blend formula would use dual source blending but we // don't have support for it. static const bool kHasMixedSamples = false; SkASSERT(!caps.usesMixedSamples()); // We never use mixed samples without dual source blending. return get_blend_formula(optimizations.fColorPOI, optimizations.fCoveragePOI, kHasMixedSamples, SkBlendMode::kSrcOver).hasSecondaryOutput(); }
GrCCPRAtlas::GrCCPRAtlas(const GrCaps& caps, int minWidth, int minHeight) : fMaxAtlasSize(caps.maxRenderTargetSize()) , fDrawBounds{0, 0} { SkASSERT(fMaxAtlasSize <= caps.maxTextureSize()); SkASSERT(SkTMax(minWidth, minHeight) <= fMaxAtlasSize); int initialSize = GrNextPow2(SkTMax(minWidth, minHeight)); initialSize = SkTMax(int(kMinSize), initialSize); initialSize = SkTMin(initialSize, fMaxAtlasSize); fHeight = fWidth = initialSize; fTopNode = skstd::make_unique<Node>(nullptr, 0, 0, initialSize, initialSize); }
// Deferred version // TODO: we can probably munge the 'desc' in both the wrapped and deferred // cases to make the sampleConfig/numSamples stuff more rational. GrRenderTargetProxy::GrRenderTargetProxy(const GrCaps& caps, const GrSurfaceDesc& desc, SkBackingFit fit, SkBudgeted budgeted, uint32_t flags) : INHERITED(desc, fit, budgeted, flags) , fRenderTargetFlags(GrRenderTarget::Flags::kNone) { // Since we know the newly created render target will be internal, we are able to precompute // what the flags will ultimately end up being. if (caps.usesMixedSamples() && fDesc.fSampleCnt > 0) { fRenderTargetFlags |= GrRenderTarget::Flags::kMixedSampled; } if (caps.maxWindowRectangles() > 0) { fRenderTargetFlags |= GrRenderTarget::Flags::kWindowRectsSupport; } }
static bool can_use_hw_blend_equation(GrBlendEquation equation, const GrProcOptInfo& coveragePOI, const GrCaps& caps) { if (!caps.advancedBlendEquationSupport()) { return false; } if (coveragePOI.isFourChannelOutput()) { return false; // LCD coverage must be applied after the blend equation. } if (caps.canUseAdvancedBlendEquation(equation)) { return false; } return true; }
bool GrXPFactory::willNeedDstTexture(const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI, bool hasMixedSamples) const { return (this->willReadDstColor(caps, colorPOI, coveragePOI, hasMixedSamples) && !caps.shaderCaps()->dstReadInShaderSupport()); }
bool GrTextureUsageSupported(const GrCaps& caps, int width, int height, SkImageUsageType usage) { if (caps.npotTextureTileSupport()) { return true; } const bool is_pow2 = SkIsPow2(width) && SkIsPow2(height); return is_pow2 || kUntiled_SkImageUsageType == usage; }
void GrMakeKeyFromImageID(GrUniqueKey* key, uint32_t imageID, U16CPU width, U16CPU height, SkIPoint origin, const GrCaps& caps, SkImageUsageType usage) { const Stretch::Type stretches[] = { Stretch::kNone_Type, // kUntiled_SkImageUsageType Stretch::kNearest_Type, // kTiled_Unfiltered_SkImageUsageType Stretch::kBilerp_Type, // kTiled_Filtered_SkImageUsageType }; const bool isPow2 = SkIsPow2(width) && SkIsPow2(height); const bool needToStretch = !isPow2 && usage != kUntiled_SkImageUsageType && !caps.npotTextureTileSupport(); if (needToStretch) { GrUniqueKey tmpKey; make_unstretched_key(&tmpKey, imageID, width, height, origin); Stretch stretch; stretch.fType = stretches[usage]; stretch.fWidth = SkNextPow2(width); stretch.fHeight = SkNextPow2(height); if (!make_stretched_key(tmpKey, stretch, key)) { goto UNSTRETCHED; } } else { UNSTRETCHED: make_unstretched_key(key, imageID, width, height, origin); } }
GrXferBarrierType GrXferProcessor::xferBarrierType(const GrRenderTarget* rt, const GrCaps& caps) const { SkASSERT(rt); if (static_cast<const GrSurface*>(rt) == this->getDstTexture()) { // Texture barriers are required when a shader reads and renders to the same texture. SkASSERT(caps.textureBarrierSupport()); return kTexture_GrXferBarrierType; } return this->onXferBarrier(rt, caps); }
bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& coveragePOI) const { if (coveragePOI.isFourChannelOutput()) { return false; // The LCD XP never does a dst read. } // We fallback on the shader XP when the blend formula would use dual source blending but we // don't have support for it. return !caps.shaderCaps()->dualSourceBlendingSupport() && get_blend_formula(fXfermode, colorPOI, coveragePOI).hasSecondaryOutput(); }
GrXPFactory::AnalysisProperties GrXPFactory::GetAnalysisProperties( const GrXPFactory* factory, const GrProcessorAnalysisColor& color, const GrProcessorAnalysisCoverage& coverage, const GrCaps& caps) { AnalysisProperties result; if (factory) { result = factory->analysisProperties(color, coverage, caps); } else { result = GrPorterDuffXPFactory::SrcOverAnalysisProperties(color, coverage, caps); } SkASSERT(!(result & AnalysisProperties::kRequiresDstTexture)); if ((result & AnalysisProperties::kReadsDstInShader) && !caps.shaderCaps()->dstReadInShaderSupport()) { result |= AnalysisProperties::kRequiresDstTexture; if (caps.textureBarrierSupport()) { result |= AnalysisProperties::kRequiresBarrierBetweenOverlappingDraws; } } return result; }
sk_sp<const GrXferProcessor> GrXPFactory::MakeXferProcessor(const GrXPFactory* factory, const GrProcessorAnalysisColor& color, GrProcessorAnalysisCoverage coverage, bool hasMixedSamples, const GrCaps& caps) { SkASSERT(!hasMixedSamples || caps.shaderCaps()->dualSourceBlendingSupport()); if (factory) { return factory->makeXferProcessor(color, coverage, hasMixedSamples, caps); } else { return GrPorterDuffXPFactory::MakeSrcOverXferProcessor(color, coverage, hasMixedSamples, caps); } }
bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI, bool hasMixedSamples) const { if (caps.shaderCaps()->dualSourceBlendingSupport()) { return false; } if (covPOI.isFourChannelOutput()) { return false; // The LCD XP will abort rather than doing a dst read. } // We fallback on the shader XP when the blend formula would use dual source blending but we // don't have support for it. return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).hasSecondaryOutput(); }
bool GrPorterDuffXPFactory::willReadDstColor(const GrCaps& caps, const GrProcOptInfo& colorPOI, const GrProcOptInfo& covPOI, bool hasMixedSamples) const { if (caps.shaderCaps()->dualSourceBlendingSupport()) { return false; } // When we have four channel coverage we always need to read the dst in order to correctly // blend. The one exception is when we are using srcover mode and we know the input color into // the XP. if (covPOI.isFourChannelOutput()) { if (SkXfermode::kSrcOver_Mode == fXfermode && kRGBA_GrColorComponentFlags == colorPOI.validFlags() && !caps.shaderCaps()->dstReadInShaderSupport()) { return false; } return get_lcd_blend_formula(covPOI, fXfermode).hasSecondaryOutput(); } // We fallback on the shader XP when the blend formula would use dual source blending but we // don't have support for it. return get_blend_formula(colorPOI, covPOI, hasMixedSamples, fXfermode).hasSecondaryOutput(); }
int GrRenderTargetProxy::maxWindowRectangles(const GrCaps& caps) const { return (fRenderTargetFlags & GrRenderTarget::Flags::kWindowRectsSupport) ? caps.maxWindowRectangles() : 0; }
GrXferBarrierType CustomXP::onXferBarrier(const GrRenderTarget* rt, const GrCaps& caps) const { if (this->hasHWBlendEquation() && !caps.advancedCoherentBlendEquationSupport()) { return kBlend_GrXferBarrierType; } return kNone_GrXferBarrierType; }
bool GrXPFactory::willNeedDstTexture(const GrCaps& caps, const GrPipelineOptimizations& optimizations, bool hasMixedSamples) const { return (this->willReadDstColor(caps, optimizations, hasMixedSamples) && !caps.shaderCaps()->dstReadInShaderSupport()); }
GrRenderTarget::SampleConfig GrRenderTarget::ComputeSampleConfig(const GrCaps& caps, int sampleCnt) { return (caps.usesMixedSamples() && sampleCnt > 0) ? GrRenderTarget::kStencil_SampleConfig : GrRenderTarget::kUnified_SampleConfig; }
std::unique_ptr<GrFillRRectOp> GrFillRRectOp::Make( GrRecordingContext* ctx, GrAAType aaType, const SkMatrix& viewMatrix, const SkRRect& rrect, const GrCaps& caps, GrPaint&& paint) { if (!caps.instanceAttribSupport()) { return nullptr; } Flags flags = Flags::kNone; if (GrAAType::kCoverage == aaType) { // TODO: Support perspective in a follow-on CL. This shouldn't be difficult, since we // already use HW derivatives. The only trick will be adjusting the AA outset to account for // perspective. (i.e., outset = 0.5 * z.) if (viewMatrix.hasPerspective()) { return nullptr; } if (can_use_hw_derivatives_with_coverage(*caps.shaderCaps(), viewMatrix, rrect)) { // HW derivatives (more specifically, fwidth()) are consistently faster on all platforms // in coverage mode. We use them as long as the approximation will be accurate enough. flags |= Flags::kUseHWDerivatives; } } else { if (GrAAType::kMSAA == aaType) { if (!caps.sampleLocationsSupport() || !caps.shaderCaps()->sampleVariablesSupport()) { return nullptr; } } if (viewMatrix.hasPerspective()) { // HW derivatives are consistently slower on all platforms in sample mask mode. We // therefore only use them when there is perspective, since then we can't interpolate // the symbolic screen-space gradient. flags |= Flags::kUseHWDerivatives | Flags::kHasPerspective; } } // Produce a matrix that draws the round rect from normalized [-1, -1, +1, +1] space. float l = rrect.rect().left(), r = rrect.rect().right(), t = rrect.rect().top(), b = rrect.rect().bottom(); SkMatrix m; // Unmap the normalized rect [-1, -1, +1, +1] back to [l, t, r, b]. m.setScaleTranslate((r - l)/2, (b - t)/2, (l + r)/2, (t + b)/2); // Map to device space. m.postConcat(viewMatrix); SkRect devBounds; if (!(flags & Flags::kHasPerspective)) { // Since m is an affine matrix that maps the rect [-1, -1, +1, +1] into the shape's // device-space quad, it's quite simple to find the bounding rectangle: devBounds = SkRect::MakeXYWH(m.getTranslateX(), m.getTranslateY(), 0, 0); devBounds.outset(SkScalarAbs(m.getScaleX()) + SkScalarAbs(m.getSkewX()), SkScalarAbs(m.getSkewY()) + SkScalarAbs(m.getScaleY())); } else { viewMatrix.mapRect(&devBounds, rrect.rect()); } if (GrAAType::kMSAA == aaType && caps.preferTrianglesOverSampleMask()) { // We are on a platform that prefers fine triangles instead of using the sample mask. See if // the round rect is large enough that it will be faster for us to send it off to the // default path renderer instead. The 200x200 threshold was arrived at using the // "shapes_rrect" benchmark on an ARM Galaxy S9. if (devBounds.height() * devBounds.width() > 200 * 200) { return nullptr; } } GrOpMemoryPool* pool = ctx->priv().opMemoryPool(); return pool->allocate<GrFillRRectOp>(aaType, rrect, flags, m, std::move(paint), devBounds); }