/*
 * Copyright 2020 Google LLC.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "src/gpu/tessellate/GrStrokeTessellateOp.h"

#include "src/core/SkPathPriv.h"
#include "src/gpu/GrRecordingContextPriv.h"
#include "src/gpu/tessellate/GrStrokePatchBuilder.h"
#include "src/gpu/tessellate/GrStrokeTessellateShader.h"

static SkPMColor4f get_paint_constant_blended_color(const GrPaint& paint) {
    SkPMColor4f constantColor;
    // Patches can overlap, so until a stencil technique is implemented, the provided paints must be
    // constant blended colors.
    SkAssertResult(paint.isConstantBlendedColor(&constantColor));
    return constantColor;
}

GrStrokeTessellateOp::GrStrokeTessellateOp(GrAAType aaType, const SkMatrix& viewMatrix,
                                           const SkStrokeRec& stroke, const SkPath& path,
                                           GrPaint&& paint)
        : GrDrawOp(ClassID())
        , fAAType(aaType)
        , fViewMatrix(viewMatrix)
        , fMatrixScale(fViewMatrix.getMaxScale())
        , fStroke(stroke)
        , fColor(get_paint_constant_blended_color(paint))
        , fProcessors(std::move(paint))
        , fPaths(path)
        , fTotalCombinedVerbCnt(path.countVerbs()) {
    SkASSERT(fAAType != GrAAType::kCoverage);  // No mixed samples support yet.
    SkASSERT(fMatrixScale >= 0);
    SkRect devBounds = path.getBounds();
    float inflationRadius = fStroke.getInflationRadius();
    devBounds.outset(inflationRadius, inflationRadius);
    viewMatrix.mapRect(&devBounds, devBounds);
    this->setBounds(devBounds, HasAABloat(GrAAType::kCoverage == fAAType), IsHairline::kNo);
}

GrDrawOp::FixedFunctionFlags GrStrokeTessellateOp::fixedFunctionFlags() const {
    auto flags = FixedFunctionFlags::kNone;
    if (GrAAType::kNone != fAAType) {
        flags |= FixedFunctionFlags::kUsesHWAA;
    }
    return flags;
}

GrProcessorSet::Analysis GrStrokeTessellateOp::finalize(const GrCaps& caps,
                                                        const GrAppliedClip* clip,
                                                        bool hasMixedSampledCoverage,
                                                        GrClampType clampType) {
    return fProcessors.finalize(fColor, GrProcessorAnalysisCoverage::kNone, clip,
                                &GrUserStencilSettings::kUnused, hasMixedSampledCoverage, caps,
                                clampType, &fColor);
}

GrOp::CombineResult GrStrokeTessellateOp::onCombineIfPossible(GrOp* grOp,
                                                              GrRecordingContext::Arenas* arenas,
                                                              const GrCaps&) {
    auto* op = grOp->cast<GrStrokeTessellateOp>();
    if (fColor != op->fColor ||
        fViewMatrix != op->fViewMatrix ||
        fAAType != op->fAAType ||
        !fStroke.hasEqualEffect(op->fStroke) ||
        fProcessors != op->fProcessors) {
        return CombineResult::kCannotCombine;
    }

    fPaths.concat(std::move(op->fPaths), arenas->recordTimeAllocator());
    fTotalCombinedVerbCnt += op->fTotalCombinedVerbCnt;

    return CombineResult::kMerged;
}

void GrStrokeTessellateOp::onPrePrepare(GrRecordingContext* context,
                                        const GrSurfaceProxyView* writeView, GrAppliedClip* clip,
                                        const GrXferProcessor::DstProxyView& dstProxyView,
                                        GrXferBarrierFlags renderPassXferBarriers) {
    this->prePrepareColorProgram(context->priv().recordTimeAllocator(), writeView, std::move(*clip),
                                 dstProxyView, renderPassXferBarriers, *context->priv().caps());
    context->priv().recordProgramInfo(fColorProgram);
}

void GrStrokeTessellateOp::prePrepareColorProgram(SkArenaAlloc* arena,
                                                  const GrSurfaceProxyView* writeView,
                                                  GrAppliedClip&& clip,
                                                  const GrXferProcessor::DstProxyView& dstProxyView,
                                                  GrXferBarrierFlags renderPassXferBarriers,
                                                  const GrCaps& caps) {
    auto* strokeShader = arena->make<GrStrokeTessellateShader>(fStroke, fMatrixScale, fViewMatrix,
                                                               fColor);
    auto pipelineFlags = GrPipeline::InputFlags::kNone;
    if (GrAAType::kNone != fAAType) {
        pipelineFlags |= GrPipeline::InputFlags::kHWAntialias;
        SkASSERT(writeView->asRenderTargetProxy()->numSamples() > 1);  // No mixed samples yet.
        SkASSERT(fAAType != GrAAType::kCoverage);  // No mixed samples yet.
    }
    fColorProgram = GrPathShader::MakeProgramInfo(strokeShader, arena, writeView, pipelineFlags,
                                                  std::move(fProcessors), std::move(clip),
                                                  dstProxyView, renderPassXferBarriers, caps);
}

void GrStrokeTessellateOp::onPrepare(GrOpFlushState* flushState) {
    if (!fColorProgram) {
        this->prePrepareColorProgram(flushState->allocator(), flushState->writeView(),
                                     flushState->detachAppliedClip(), flushState->dstProxyView(),
                                     flushState->renderPassBarriers(), flushState->caps());
    }
    GrStrokePatchBuilder builder(flushState, &fPatchChunks, fMatrixScale, fStroke,
                                 fTotalCombinedVerbCnt);
    for (const SkPath& path : fPaths) {
        builder.addPath(path);
    }
}

void GrStrokeTessellateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
    SkASSERT(fColorProgram);
    SkASSERT(chainBounds == this->bounds());

    flushState->bindPipelineAndScissorClip(*fColorProgram, this->bounds());
    flushState->bindTextures(fColorProgram->primProc(), nullptr, fColorProgram->pipeline());
    for (const auto& chunk : fPatchChunks) {
        if (chunk.fPatchBuffer) {
            flushState->bindBuffers(nullptr, nullptr, std::move(chunk.fPatchBuffer));
            flushState->draw(chunk.fPatchCount, chunk.fBasePatch);
        }
    }
}
