/* * Copyright 2015 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "GrXferProcessor.h" #include "GrPipeline.h" #include "GrProcOptInfo.h" #include "gl/GrGLCaps.h" GrXferProcessor::GrXferProcessor() : fWillReadDstColor(false) , fDstReadUsesMixedSamples(false) , fDstTextureOffset() { } GrXferProcessor::GrXferProcessor(const DstTexture* dstTexture, bool willReadDstColor, bool hasMixedSamples) : fWillReadDstColor(willReadDstColor) , fDstReadUsesMixedSamples(willReadDstColor && hasMixedSamples) , fDstTextureOffset() { if (dstTexture && dstTexture->texture()) { SkASSERT(willReadDstColor); fDstTexture.reset(dstTexture->texture()); fDstTextureOffset = dstTexture->offset(); this->addTextureSampler(&fDstTexture); } } GrXferProcessor::OptFlags GrXferProcessor::getOptimizations(const GrPipelineAnalysis& analysis, bool doesStencilWrite, GrColor* overrideColor, const GrCaps& caps) const { GrXferProcessor::OptFlags flags = this->onGetOptimizations(analysis, doesStencilWrite, overrideColor, caps); return flags; } bool GrXferProcessor::hasSecondaryOutput() const { if (!this->willReadDstColor()) { return this->onHasSecondaryOutput(); } return this->dstReadUsesMixedSamples(); } void GrXferProcessor::getBlendInfo(BlendInfo* blendInfo) const { blendInfo->reset(); if (!this->willReadDstColor()) { this->onGetBlendInfo(blendInfo); } else if (this->dstReadUsesMixedSamples()) { blendInfo->fDstBlend = kIS2A_GrBlendCoeff; } } void GrXferProcessor::getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const { uint32_t key = this->willReadDstColor() ? 0x1 : 0x0; if (key) { if (const GrTexture* dstTexture = this->getDstTexture()) { key |= 0x2; if (kTopLeft_GrSurfaceOrigin == dstTexture->origin()) { key |= 0x4; } } if (this->dstReadUsesMixedSamples()) { key |= 0x8; } } b->add32(key); this->onGetGLSLProcessorKey(caps, b); } GrXferBarrierType GrXferProcessor::xferBarrierType(const GrRenderTarget* rt, const GrCaps& caps) const { SkASSERT(rt); if (static_cast(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); } #ifdef SK_DEBUG static const char* equation_string(GrBlendEquation eq) { switch (eq) { case kAdd_GrBlendEquation: return "add"; case kSubtract_GrBlendEquation: return "subtract"; case kReverseSubtract_GrBlendEquation: return "reverse_subtract"; case kScreen_GrBlendEquation: return "screen"; case kOverlay_GrBlendEquation: return "overlay"; case kDarken_GrBlendEquation: return "darken"; case kLighten_GrBlendEquation: return "lighten"; case kColorDodge_GrBlendEquation: return "color_dodge"; case kColorBurn_GrBlendEquation: return "color_burn"; case kHardLight_GrBlendEquation: return "hard_light"; case kSoftLight_GrBlendEquation: return "soft_light"; case kDifference_GrBlendEquation: return "difference"; case kExclusion_GrBlendEquation: return "exclusion"; case kMultiply_GrBlendEquation: return "multiply"; case kHSLHue_GrBlendEquation: return "hsl_hue"; case kHSLSaturation_GrBlendEquation: return "hsl_saturation"; case kHSLColor_GrBlendEquation: return "hsl_color"; case kHSLLuminosity_GrBlendEquation: return "hsl_luminosity"; }; return ""; } static const char* coeff_string(GrBlendCoeff coeff) { switch (coeff) { case kZero_GrBlendCoeff: return "zero"; case kOne_GrBlendCoeff: return "one"; case kSC_GrBlendCoeff: return "src_color"; case kISC_GrBlendCoeff: return "inv_src_color"; case kDC_GrBlendCoeff: return "dst_color"; case kIDC_GrBlendCoeff: return "inv_dst_color"; case kSA_GrBlendCoeff: return "src_alpha"; case kISA_GrBlendCoeff: return "inv_src_alpha"; case kDA_GrBlendCoeff: return "dst_alpha"; case kIDA_GrBlendCoeff: return "inv_dst_alpha"; case kConstC_GrBlendCoeff: return "const_color"; case kIConstC_GrBlendCoeff: return "inv_const_color"; case kConstA_GrBlendCoeff: return "const_alpha"; case kIConstA_GrBlendCoeff: return "inv_const_alpha"; case kS2C_GrBlendCoeff: return "src2_color"; case kIS2C_GrBlendCoeff: return "inv_src2_color"; case kS2A_GrBlendCoeff: return "src2_alpha"; case kIS2A_GrBlendCoeff: return "inv_src2_alpha"; } return ""; } SkString GrXferProcessor::BlendInfo::dump() const { SkString out; out.printf("write_color(%d) equation(%s) src_coeff(%s) dst_coeff:(%s) const(0x%08x)", fWriteColor, equation_string(fEquation), coeff_string(fSrcBlend), coeff_string(fDstBlend), fBlendConstant); return out; } #endif /////////////////////////////////////////////////////////////////////////////// using ColorType = GrXPFactory::ColorType; using CoverageType = GrXPFactory::CoverageType; ColorType analysis_color_type(const GrPipelineAnalysis& analysis) { if (analysis.fColorPOI.hasKnownOutputColor()) { return analysis.fColorPOI.isOpaque() ? ColorType::kOpaqueConstant : ColorType::kConstant; } if (analysis.fColorPOI.isOpaque()) { return ColorType::kOpaque; } return ColorType::kUnknown; } CoverageType analysis_coverage_type(const GrPipelineAnalysis& analysis) { if (analysis.fCoveragePOI.isSolidWhite()) { return CoverageType::kNone; } if (analysis.fCoveragePOI.isLCDCoverage()) { return CoverageType::kLCD; } return CoverageType::kSingleChannel; } bool GrXPFactory::WillReadDst(const GrXPFactory* factory, const GrProcOptInfo& colorInput, const GrProcOptInfo& coverageInput) { if (factory) { return factory->willReadsDst(colorInput, coverageInput); } return GrPorterDuffXPFactory::WillSrcOverReadDst(colorInput, coverageInput); } bool GrXPFactory::IsPreCoverageBlendedColorConstant(const GrXPFactory* factory, const GrProcOptInfo& colorInput, GrColor* color) { if (factory) { return factory->isPreCoverageBlendedColorConstant(colorInput, color); } return GrPorterDuffXPFactory::IsSrcOverPreCoverageBlendedColorConstant(colorInput, color); } bool GrXPFactory::willReadDstInShader(const GrCaps& caps, const GrPipelineAnalysis& analysis) const { if (analysis.fUsesPLSDstRead) { return true; } ColorType colorType = analysis_color_type(analysis); CoverageType coverageType = analysis_coverage_type(analysis); return this->willReadDstInShader(caps, colorType, coverageType); } GrXferProcessor* GrXPFactory::createXferProcessor(const GrPipelineAnalysis& analysis, bool hasMixedSamples, const DstTexture* dstTexture, const GrCaps& caps) const { #ifdef SK_DEBUG if (this->willReadDstInShader(caps, analysis)) { if (!caps.shaderCaps()->dstReadInShaderSupport()) { SkASSERT(dstTexture && dstTexture->texture()); } else { SkASSERT(!dstTexture || !dstTexture->texture()); } } else { SkASSERT(!dstTexture || !dstTexture->texture()); } SkASSERT(!hasMixedSamples || caps.shaderCaps()->dualSourceBlendingSupport()); #endif return this->onCreateXferProcessor(caps, analysis, hasMixedSamples, dstTexture); } bool GrXPFactory::willNeedDstTexture(const GrCaps& caps, const GrPipelineAnalysis& analysis) const { return !analysis.fUsesPLSDstRead && !caps.shaderCaps()->dstReadInShaderSupport() && this->willReadDstInShader(caps, analysis); }