/*
 * 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 "GrPipeline.h"

#include "GrAppliedClip.h"
#include "GrCaps.h"
#include "GrGpu.h"
#include "GrPipelineBuilder.h"
#include "GrProcOptInfo.h"
#include "GrRenderTargetContext.h"
#include "GrRenderTargetOpList.h"
#include "GrRenderTargetPriv.h"
#include "GrXferProcessor.h"

#include "ops/GrOp.h"

GrPipelineOptimizations GrPipeline::init(const InitArgs& args) {
    SkASSERT(args.fAnalysis);
    SkASSERT(args.fRenderTarget);

    fRenderTarget.reset(args.fRenderTarget);
    fScissorState = args.fAppliedClip->scissorState();
    fWindowRectsState = args.fAppliedClip->windowRectsState();
    fUserStencilSettings = args.fUserStencil;
    fDrawFace = static_cast<int16_t>(args.fDrawFace);

    fFlags = args.fFlags;
    if (args.fProcessors->usesDistanceVectorField()) {
        fFlags |= kUsesDistanceVectorField_Flag;
    }
    if (args.fAppliedClip->hasStencilClip()) {
        fFlags |= kHasStencilClip_Flag;
    }
    if (!args.fUserStencil->isDisabled(args.fAppliedClip->hasStencilClip())) {
        fFlags |= kStencilEnabled_Flag;
    }
    if (args.fProcessors->disableOutputConversionToSRGB()) {
        fFlags |= kDisableOutputConversionToSRGB_Flag;
    }
    if (args.fProcessors->allowSRGBInputs()) {
        fFlags |= kAllowSRGBInputs_Flag;
    }

    bool isHWAA = kHWAntialias_Flag & args.fFlags;

    // Create XferProcessor from DS's XPFactory
    bool hasMixedSamples = args.fRenderTarget->isMixedSampled() && (isHWAA || isStencilEnabled());
    const GrXPFactory* xpFactory = args.fProcessors->xpFactory();
    sk_sp<GrXferProcessor> xferProcessor;
    if (xpFactory) {
        xferProcessor.reset(xpFactory->createXferProcessor(*args.fAnalysis, hasMixedSamples,
                                                           &args.fDstTexture, *args.fCaps));
        SkASSERT(xferProcessor);
    } else {
        // This may return nullptr in the common case of src-over implemented using hw blending.
        xferProcessor.reset(GrPorterDuffXPFactory::CreateSrcOverXferProcessor(
                *args.fCaps, *args.fAnalysis, hasMixedSamples, &args.fDstTexture));
    }
    GrColor overrideColor = GrColor_ILLEGAL;
    int colorFPsToEliminate = args.fAnalysis->initialColorProcessorsToEliminate(&overrideColor);

    GrXferProcessor::OptFlags optFlags = GrXferProcessor::kNone_OptFlags;

    const GrXferProcessor* xpForOpts = xferProcessor ? xferProcessor.get() :
                                                       &GrPorterDuffXPFactory::SimpleSrcOverXP();
    optFlags = xpForOpts->getOptimizations(
            *args.fAnalysis, args.fUserStencil->doesWrite(args.fAppliedClip->hasStencilClip()),
            &overrideColor, *args.fCaps);

    // No need to have an override color if it isn't even going to be used.
    if (SkToBool(GrXferProcessor::kIgnoreColor_OptFlag & optFlags)) {
        overrideColor = GrColor_ILLEGAL;
    }

    fXferProcessor.reset(xferProcessor.get());

    if ((optFlags & GrXferProcessor::kIgnoreColor_OptFlag) ||
        (optFlags & GrXferProcessor::kOverrideColor_OptFlag)) {
        colorFPsToEliminate = args.fProcessors->numColorFragmentProcessors();
    }

    bool usesLocalCoords = false;

    // Copy GrFragmentProcessors from GrPipelineBuilder to Pipeline, possibly removing some of the
    // color fragment processors.
    fNumColorProcessors = args.fProcessors->numColorFragmentProcessors() - colorFPsToEliminate;
    int numTotalProcessors =
            fNumColorProcessors + args.fProcessors->numCoverageFragmentProcessors();
    if (args.fAppliedClip->clipCoverageFragmentProcessor()) {
        ++numTotalProcessors;
    }
    fFragmentProcessors.reset(numTotalProcessors);
    int currFPIdx = 0;
    for (int i = colorFPsToEliminate; i < args.fProcessors->numColorFragmentProcessors();
         ++i, ++currFPIdx) {
        const GrFragmentProcessor* fp = args.fProcessors->colorFragmentProcessor(i);
        fFragmentProcessors[currFPIdx].reset(fp);
        usesLocalCoords = usesLocalCoords || fp->usesLocalCoords();
    }

    for (int i = 0; i < args.fProcessors->numCoverageFragmentProcessors(); ++i, ++currFPIdx) {
        const GrFragmentProcessor* fp = args.fProcessors->coverageFragmentProcessor(i);
        fFragmentProcessors[currFPIdx].reset(fp);
        usesLocalCoords = usesLocalCoords || fp->usesLocalCoords();
    }
    if (const GrFragmentProcessor* fp = args.fAppliedClip->clipCoverageFragmentProcessor()) {
        fFragmentProcessors[currFPIdx].reset(fp);
        usesLocalCoords = usesLocalCoords || fp->usesLocalCoords();
    }

    // Setup info we need to pass to GrPrimitiveProcessors that are used with this GrPipeline.
    GrPipelineOptimizations optimizations;
    optimizations.fFlags = 0;
    if (GrColor_ILLEGAL != overrideColor) {
        optimizations.fFlags |= GrPipelineOptimizations::kUseOverrideColor_Flag;
        optimizations.fOverrideColor = overrideColor;
    }
    if (usesLocalCoords) {
        optimizations.fFlags |= GrPipelineOptimizations::kReadsLocalCoords_Flag;
    }
    if (SkToBool(optFlags & GrXferProcessor::kCanTweakAlphaForCoverage_OptFlag)) {
        optimizations.fFlags |= GrPipelineOptimizations::kCanTweakAlphaForCoverage_Flag;
    }

    if (GrXPFactory::WillReadDst(xpFactory, *args.fAnalysis)) {
        optimizations.fFlags |= GrPipelineOptimizations::kXPReadsDst_Flag;
    }
    return optimizations;
}

static void add_dependencies_for_processor(const GrFragmentProcessor* proc, GrRenderTarget* rt) {
    GrFragmentProcessor::TextureAccessIter iter(proc);
    while (const GrProcessor::TextureSampler* sampler = iter.next()) {
        SkASSERT(rt->getLastOpList());
        rt->getLastOpList()->addDependency(sampler->texture());
    }
}

void GrPipeline::addDependenciesTo(GrRenderTarget* rt) const {
    for (int i = 0; i < fFragmentProcessors.count(); ++i) {
        add_dependencies_for_processor(fFragmentProcessors[i].get(), rt);
    }

    const GrXferProcessor& xfer = this->getXferProcessor();

    for (int i = 0; i < xfer.numTextureSamplers(); ++i) {
        GrTexture* texture = xfer.textureSampler(i).texture();
        SkASSERT(rt->getLastOpList());
        rt->getLastOpList()->addDependency(texture);
    }
}

GrPipeline::GrPipeline(GrRenderTarget* rt, SkBlendMode blendmode)
    : fRenderTarget(rt)
    , fScissorState()
    , fWindowRectsState()
    , fUserStencilSettings(&GrUserStencilSettings::kUnused)
    , fDrawFace(static_cast<uint16_t>(GrDrawFace::kBoth))
    , fFlags()
    , fXferProcessor(GrPorterDuffXPFactory::CreateNoCoverageXP(blendmode).get())
    , fFragmentProcessors()
    , fNumColorProcessors(0) {
}

////////////////////////////////////////////////////////////////////////////////

bool GrPipeline::AreEqual(const GrPipeline& a, const GrPipeline& b) {
    SkASSERT(&a != &b);

    if (a.getRenderTarget() != b.getRenderTarget() ||
        a.fFragmentProcessors.count() != b.fFragmentProcessors.count() ||
        a.fNumColorProcessors != b.fNumColorProcessors ||
        a.fScissorState != b.fScissorState ||
        !a.fWindowRectsState.cheapEqualTo(b.fWindowRectsState) ||
        a.fFlags != b.fFlags ||
        a.fUserStencilSettings != b.fUserStencilSettings ||
        a.fDrawFace != b.fDrawFace) {
        return false;
    }

    // Most of the time both are nullptr
    if (a.fXferProcessor.get() || b.fXferProcessor.get()) {
        if (!a.getXferProcessor().isEqual(b.getXferProcessor())) {
            return false;
        }
    }

    for (int i = 0; i < a.numFragmentProcessors(); i++) {
        if (!a.getFragmentProcessor(i).isEqual(b.getFragmentProcessor(i))) {
            return false;
        }
    }
    return true;
}
