/*
 * Copyright 2021 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/ops/PathTessellateOp.h"

#include "src/gpu/GrAppliedClip.h"
#include "src/gpu/GrOpFlushState.h"
#include "src/gpu/tessellate/PathWedgeTessellator.h"
#include "src/gpu/tessellate/shaders/GrPathTessellationShader.h"

namespace skgpu::v1 {

void PathTessellateOp::visitProxies(const GrVisitProxyFunc& func) const {
    if (fTessellationProgram) {
        fTessellationProgram->pipeline().visitProxies(func);
    } else {
        fProcessors.visitProxies(func);
    }
}

GrProcessorSet::Analysis PathTessellateOp::finalize(const GrCaps& caps,
                                                    const GrAppliedClip* clip,
                                                    GrClampType clampType) {
    auto analysis = fProcessors.finalize(this->headDraw().fColor,
                                         GrProcessorAnalysisCoverage::kNone,
                                         clip,
                                         nullptr,
                                         caps,
                                         clampType,
                                         &this->headDraw().fColor);
    if (!analysis.usesLocalCoords()) {
        // Since we don't need local coords, we can transform on CPU instead of in the shader. This
        // gives us better batching potential.
        this->headDraw().fPathMatrix = fShaderMatrix;
        fShaderMatrix = SkMatrix::I();
    }
    return analysis;
}

GrDrawOp::CombineResult PathTessellateOp::onCombineIfPossible(GrOp* grOp,
                                                              SkArenaAlloc*,
                                                              const GrCaps&) {
    auto* op = grOp->cast<PathTessellateOp>();
    bool canMerge = fAAType == op->fAAType &&
                    fStencil == op->fStencil &&
                    fProcessors == op->fProcessors &&
                    fShaderMatrix == op->fShaderMatrix;
    if (canMerge) {
        fTotalCombinedPathVerbCnt += op->fTotalCombinedPathVerbCnt;
        fPatchAttribs |= op->fPatchAttribs;

        if (!(fPatchAttribs & PatchAttribs::kColor) &&
            this->headDraw().fColor != op->headDraw().fColor) {
            // Color is no longer uniform. Move it into patch attribs.
            fPatchAttribs |= PatchAttribs::kColor;
        }

        *fPathDrawTail = op->fPathDrawList;
        fPathDrawTail = op->fPathDrawTail;
        return CombineResult::kMerged;
    }

    return CombineResult::kCannotCombine;
}

void PathTessellateOp::prepareTessellator(const GrTessellationShader::ProgramArgs& args,
                                          GrAppliedClip&& appliedClip) {
    SkASSERT(!fTessellator);
    SkASSERT(!fTessellationProgram);
    auto* pipeline = GrTessellationShader::MakePipeline(args, fAAType, std::move(appliedClip),
                                                        std::move(fProcessors));
    fTessellator = PathWedgeTessellator::Make(args.fArena,
                                              args.fCaps->shaderCaps()->infinitySupport(),
                                              fPatchAttribs);
    auto* tessShader = GrPathTessellationShader::Make(args.fArena,
                                                      fShaderMatrix,
                                                      this->headDraw().fColor,
                                                      fTotalCombinedPathVerbCnt,
                                                      *pipeline,
                                                      fTessellator->patchAttribs(),
                                                      *args.fCaps);
    fTessellationProgram = GrTessellationShader::MakeProgram(args, tessShader, pipeline, fStencil);
}

void PathTessellateOp::onPrePrepare(GrRecordingContext* context,
                                    const GrSurfaceProxyView& writeView, GrAppliedClip* clip,
                                    const GrDstProxyView& dstProxyView,
                                    GrXferBarrierFlags renderPassXferBarriers,
                                    GrLoadOp colorLoadOp) {
    // DMSAA is not supported on DDL.
    bool usesMSAASurface = writeView.asRenderTargetProxy()->numSamples() > 1;
    this->prepareTessellator({context->priv().recordTimeAllocator(), writeView, usesMSAASurface,
                             &dstProxyView, renderPassXferBarriers, colorLoadOp,
                             context->priv().caps()},
                             (clip) ? std::move(*clip) : GrAppliedClip::Disabled());
    SkASSERT(fTessellationProgram);
    context->priv().recordProgramInfo(fTessellationProgram);
}

void PathTessellateOp::onPrepare(GrOpFlushState* flushState) {
    if (!fTessellator) {
        this->prepareTessellator({flushState->allocator(), flushState->writeView(),
                                 flushState->usesMSAASurface(), &flushState->dstProxyView(),
                                 flushState->renderPassBarriers(), flushState->colorLoadOp(),
                                 &flushState->caps()}, flushState->detachAppliedClip());
        SkASSERT(fTessellator);
    }
    auto tessShader = &fTessellationProgram->geomProc().cast<GrPathTessellationShader>();
    fTessellator->prepare(flushState,
                          tessShader->maxTessellationSegments(*flushState->caps().shaderCaps()),
                          fShaderMatrix,
                          *fPathDrawList,
                          fTotalCombinedPathVerbCnt,
                          tessShader->willUseTessellationShaders());
}

void PathTessellateOp::onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) {
    SkASSERT(fTessellator);
    SkASSERT(fTessellationProgram);
    flushState->bindPipelineAndScissorClip(*fTessellationProgram, this->bounds());
    flushState->bindTextures(fTessellationProgram->geomProc(), nullptr,
                             fTessellationProgram->pipeline());
    fTessellator->draw(flushState, fTessellationProgram->geomProc().willUseTessellationShaders());
}

} // namespace skgpu::v1
