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

#include "include/core/SkColorSpace.h"
#include "include/core/SkColorType.h"
#include "include/gpu/graphite/PrecompileContext.h"
#include "include/gpu/graphite/precompile/Precompile.h"
#include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
#include "include/private/SkLog.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/ContextUtils.h"
#include "src/gpu/graphite/GraphicsPipeline.h"
#include "src/gpu/graphite/GraphicsPipelineDesc.h"
#include "src/gpu/graphite/GraphicsPipelineHandle.h"
#include "src/gpu/graphite/KeyContext.h"
#include "src/gpu/graphite/PipelineCreationTask.h"
#include "src/gpu/graphite/PipelineData.h"
#include "src/gpu/graphite/PrecompileContextPriv.h"
#include "src/gpu/graphite/PrecompileInternal.h"
#include "src/gpu/graphite/RenderPassDesc.h"
#include "src/gpu/graphite/Renderer.h"
#include "src/gpu/graphite/RendererProvider.h"
#include "src/gpu/graphite/ResourceProvider.h"
#include "src/gpu/graphite/RuntimeEffectDictionary.h"
#include "src/gpu/graphite/TextureInfoPriv.h"
#include "src/gpu/graphite/UniquePaintParamsID.h"
#include "src/gpu/graphite/precompile/PaintOptionsPriv.h"
#include "src/gpu/graphite/precompile/PrecompileColorFiltersPriv.h"

namespace {

using namespace skgpu::graphite;

void compile(SharedContext* sharedContext,
             const KeyContext& keyContext,
             UniquePaintParamsID uniqueID,
             DrawTypeFlags drawTypes,
             const RenderPassDesc& renderPassDesc,
             bool withPrimitiveBlender,
             Coverage coverage) {

    const RendererProvider* rendererProvider = sharedContext->rendererProvider();
    PipelineManager* pipelineManager = sharedContext->pipelineManager();

    for (const Renderer* r : rendererProvider->renderers()) {
        if (!(r->drawTypes() & drawTypes)) {
            continue;
        }

        if (r->emitsPrimitiveColor() != withPrimitiveBlender) {
            // UniqueIDs are explicitly built either w/ or w/o primitiveBlending so must
            // match what the Renderer requires
            continue;
        }

        if (r->coverage() != coverage) {
            // For now, UniqueIDs are explicitly built with a specific type of coverage so must
            // match what the Renderer requires
            continue;
        }

        for (auto&& s : r->steps()) {
            SkASSERT(!s->performsShading() || s->emitsPrimitiveColor() == withPrimitiveBlender);

            UniquePaintParamsID paintID = s->performsShading() ? uniqueID
                                                               : UniquePaintParamsID::Invalid();

            GraphicsPipelineHandle handle = pipelineManager->createHandle(
                    sharedContext,
                    keyContext.rtEffectDict(),
                    { s->renderStepID(), paintID },
                    renderPassDesc,
                    PipelineCreationFlags::kForPrecompilation);
        }
    }
}

} // anonymous namespace

namespace skgpu::graphite {

void Precompile(PrecompileContext* precompileContext,
                const PaintOptions& options,
                DrawTypeFlags drawTypes,
                SkSpan<const RenderPassProperties> renderPassProperties) {

    ShaderCodeDictionary* dict = precompileContext->priv().shaderCodeDictionary();
    const RendererProvider* rendererProvider = precompileContext->priv().rendererProvider();
    SharedContext* sharedContext = precompileContext->priv().sharedContext();
    PipelineManager* pipelineManager = sharedContext->pipelineManager();
    const Caps* caps = precompileContext->priv().caps();

    sk_sp<RuntimeEffectDictionary> rtEffectDict = sk_make_sp<RuntimeEffectDictionary>();

    for (const RenderPassProperties& rpp : renderPassProperties) {
        // TODO: Allow the client to pass in mipmapping and protection too?
        TextureInfo info = caps->getDefaultSampledTextureInfo(rpp.fDstCT,
                                                              Mipmapped::kNo,
                                                              Protected::kNo,
                                                              Renderable::kYes);
        std::optional<Swizzle> writeSwizzle = WriteSwizzleForColorType(
                rpp.fDstCT, TextureInfoPriv::ViewFormat(info));
        if (!writeSwizzle.has_value()) {
            continue; // Skip generating pipelines that would never show up at runtime
        }

        // TODO(robertphillips): address mismatches between the MSAA requirements of the Renderers
        // associated w/ the requested drawTypes and the specified MSAA setting

        // On Native Metal, the LoadOp, StoreOp and clearColor fields don't influence
        // the actual RenderPassDescKey.
        // For Dawn, the LoadOp will sometimes matter. We add an extra LoadOp::kLoad combination
        // when necessary.
        const LoadOp kLoadOps[2] = { LoadOp::kClear, LoadOp::kLoad };

        int numLoadOps = 1;
        if (rpp.fRequiresMSAA &&
            !caps->msaaRenderToSingleSampledSupport() &&
            caps->loadOpAffectsMSAAPipelines()) {
            numLoadOps = 2;
        }

        for (int loadOpIndex = 0; loadOpIndex < numLoadOps; ++loadOpIndex) {
            const RenderPassDesc renderPassDesc =
                    RenderPassDesc::Make(caps,
                                         info,
                                         kLoadOps[loadOpIndex],
                                         StoreOp::kStore,
                                         rpp.fDSFlags,
                                         /* clearColor= */ { .0f, .0f, .0f, .0f },
                                         rpp.fRequiresMSAA,
                                         *writeSwizzle,
                                         caps->getDstReadStrategy());

            SkColorInfo ci(rpp.fDstCT, kPremul_SkAlphaType, rpp.fDstCS);

            // The PipelineDataGatherer handles uniform data; in the pre-compile case we don't need
            // to record the uniform data but the process of generating it is required to create the
            // correct key.
            PipelineDataGatherer gatherer(Layout::kMetal);
            PaintParamsKeyBuilder builder(dict);
            KeyContext keyContext(caps, &builder, &gatherer, dict, rtEffectDict, ci);

            for (Coverage coverage : { Coverage::kNone, Coverage::kSingleChannel }) {
                PrecompileCombinations(
                        sharedContext,
                        options, keyContext,
                        static_cast<DrawTypeFlags>(drawTypes & ~(DrawTypeFlags::kBitmapText_Color |
                                                                 DrawTypeFlags::kBitmapText_LCD |
                                                                 DrawTypeFlags::kSDFText_LCD |
                                                                 DrawTypeFlags::kDrawVertices |
                                                                 DrawTypeFlags::kDropShadows)),
                        /* withPrimitiveBlender= */ false,
                        coverage,
                        renderPassDesc);
            }

            if (drawTypes & DrawTypeFlags::kNonSimpleShape) {
                // Special case handling to pick up the:
                //     "CoverBoundsRenderStep[InverseCover] + (empty)"
                // pipelines.
                const RenderStep* renderStep =
                    rendererProvider->lookup(RenderStep::RenderStepID::kCoverBounds_InverseCover);

                GraphicsPipelineHandle handle = pipelineManager->createHandle(
                        sharedContext,
                        keyContext.rtEffectDict(),
                        { renderStep->renderStepID(), UniquePaintParamsID::Invalid() },
                        renderPassDesc,
                        PipelineCreationFlags::kForPrecompilation);
            }

            if (drawTypes & DrawTypeFlags::kBitmapText_Color) {
                DrawTypeFlags reducedTypes =
                        static_cast<DrawTypeFlags>(drawTypes & (DrawTypeFlags::kBitmapText_Color |
                                                                DrawTypeFlags::kAnalyticClip));
                // For color emoji text, shaders don't affect the final color
                PaintOptions tmp = options;
                tmp.setShaders({});
                tmp.priv().setPrimitiveBlendMode(SkBlendMode::kDstIn);

                // ARGB text doesn't emit coverage and always has a primitive blender
                PrecompileCombinations(sharedContext,
                                       tmp,
                                       keyContext,
                                       reducedTypes,
                                       /* withPrimitiveBlender= */ true,
                                       Coverage::kNone,
                                       renderPassDesc);
            }

            if (drawTypes & (DrawTypeFlags::kBitmapText_LCD | DrawTypeFlags::kSDFText_LCD)) {
                DrawTypeFlags reducedTypes =
                        static_cast<DrawTypeFlags>(drawTypes & (DrawTypeFlags::kBitmapText_LCD |
                                                                DrawTypeFlags::kSDFText_LCD |
                                                                DrawTypeFlags::kAnalyticClip));
                // LCD-based text always emits LCD coverage but never has primitiveBlenders
                PrecompileCombinations(
                        sharedContext,
                        options, keyContext,
                        reducedTypes,
                        /* withPrimitiveBlender= */ false,
                        Coverage::kLCD,
                        renderPassDesc);
            }

            if (drawTypes & DrawTypeFlags::kDrawVertices) {
                DrawTypeFlags reducedTypes =
                        static_cast<DrawTypeFlags>(drawTypes & (DrawTypeFlags::kDrawVertices |
                                                                DrawTypeFlags::kAnalyticClip));
                // drawVertices w/ colors use a primitiveBlender while those w/o don't. It never
                // emits coverage.
                for (bool withPrimitiveBlender : { true, false }) {
                    PrecompileCombinations(sharedContext,
                                           options, keyContext,
                                           reducedTypes,
                                           withPrimitiveBlender,
                                           Coverage::kNone,
                                           renderPassDesc);
                }
            }

            if (drawTypes & DrawTypeFlags::kDropShadows) {
                DrawTypeFlags reducedTypes =
                        static_cast<DrawTypeFlags>(drawTypes & (DrawTypeFlags::kDropShadows |
                                                                DrawTypeFlags::kAnalyticClip));

                PaintOptions newOptions;
                newOptions.setBlendModes(SKSPAN_INIT_ONE(SkBlendMode::kSrcOver));

                // Analytic
                {
                    PrecompileCombinations(sharedContext,
                                           newOptions, keyContext,
                                           reducedTypes,
                                           /* withPrimitiveBlender= */ false,
                                           Coverage::kSingleChannel,
                                           renderPassDesc);
                }

                // Geometric
                {
                    sk_sp<PrecompileColorFilter> cf = PrecompileColorFilters::Compose(
                            {{ PrecompileColorFilters::Blend(SKSPAN_INIT_ONE(SkBlendMode::kModulate)) }},
                            {{ PrecompileColorFiltersPriv::Gaussian() }});

                    newOptions.setColorFilters({{ std::move(cf) }});
                    newOptions.priv().setPrimitiveBlendMode(SkBlendMode::kDst);
                    newOptions.priv().setSkipColorXform(true);

                    PrecompileCombinations(sharedContext,
                                           newOptions, keyContext,
                                           reducedTypes,
                                           /* withPrimitiveBlender= */ true,
                                           Coverage::kNone,
                                           renderPassDesc);
                }
            }
        }
    }
}

void PrecompileCombinations(SharedContext* sharedContext,
                            const PaintOptions& options,
                            const KeyContext& keyContext,
                            DrawTypeFlags drawTypes,
                            bool withPrimitiveBlender,
                            Coverage coverage,
                            const RenderPassDesc& renderPassDescIn) {
    if (drawTypes == DrawTypeFlags::kNone) {
        return;
    }

    options.priv().buildCombinations(
        keyContext,
        drawTypes,
        withPrimitiveBlender,
        coverage,
        renderPassDescIn,
        [sharedContext, &keyContext](UniquePaintParamsID uniqueID,
                                     DrawTypeFlags drawTypes,
                                     bool withPrimitiveBlender,
                                     Coverage coverage,
                                     const RenderPassDesc& renderPassDesc) {
               compile(sharedContext,
                       keyContext,
                       uniqueID,
                       drawTypes,
                       renderPassDesc,
                       withPrimitiveBlender,
                       coverage);
        });
}

} // namespace skgpu::graphite
