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

#include "include/core/SkColorSpace.h"
#include "include/core/SkPixmap.h"
#include "include/private/SkColorData.h"

#include "include/gpu/graphite/Context.h"
#include "include/gpu/graphite/Recorder.h"
#include "src/core/SkTraceEvent.h"
#include "src/gpu/graphite/AtlasProvider.h"
#include "src/gpu/graphite/Buffer.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/CommandBuffer.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/DrawList.h"
#include "src/gpu/graphite/DrawPass.h"
#include "src/gpu/graphite/Log.h"
#include "src/gpu/graphite/PathAtlas.h"
#include "src/gpu/graphite/RasterPathAtlas.h"
#include "src/gpu/graphite/RecorderPriv.h"
#include "src/gpu/graphite/ResourceTypes.h"
#include "src/gpu/graphite/SharedContext.h"
#include "src/gpu/graphite/TextureProxy.h"
#include "src/gpu/graphite/TextureProxyView.h"
#include "src/gpu/graphite/compute/DispatchGroup.h"
#include "src/gpu/graphite/geom/BoundsManager.h"
#include "src/gpu/graphite/geom/Geometry.h"
#include "src/gpu/graphite/task/ComputeTask.h"
#include "src/gpu/graphite/task/DrawTask.h"
#include "src/gpu/graphite/task/RenderPassTask.h"
#include "src/gpu/graphite/task/UploadTask.h"
#include "src/gpu/graphite/text/TextAtlasManager.h"

namespace skgpu::graphite {

sk_sp<DrawContext> DrawContext::Make(sk_sp<TextureProxy> target,
                                     SkISize deviceSize,
                                     const SkColorInfo& colorInfo,
                                     const SkSurfaceProps& props) {
    if (!target) {
        return nullptr;
    }

    // Accept an approximate-fit texture, but make sure it's at least as large as the device's
    // logical size.
    // TODO: validate that the color type and alpha type are compatible with the target's info
    SkASSERT(target->isFullyLazy() || (target->dimensions().width() >= deviceSize.width() &&
                                       target->dimensions().height() >= deviceSize.height()));
    SkImageInfo imageInfo = SkImageInfo::Make(deviceSize, colorInfo);
    return sk_sp<DrawContext>(new DrawContext(std::move(target), imageInfo, props));
}

DrawContext::DrawContext(sk_sp<TextureProxy> target,
                         const SkImageInfo& ii,
                         const SkSurfaceProps& props)
        : fTarget(std::move(target))
        , fImageInfo(ii)
        , fSurfaceProps(props)
        , fCurrentDrawTask(sk_make_sp<DrawTask>(fTarget))
        , fPendingDraws(std::make_unique<DrawList>())
        , fPendingUploads(std::make_unique<UploadList>()) {
    // TBD - Will probably want DrawLists (and its internal commands) to come from an arena
    // that the DC manages.
}

DrawContext::~DrawContext() = default;

TextureProxyView DrawContext::readSurfaceView(const Caps* caps) {
    TextureProxy* proxy = this->target();

    if (!caps->isTexturable(proxy->textureInfo())) {
        return {};
    }

    Swizzle swizzle = caps->getReadSwizzle(this->imageInfo().colorType(),
                                           proxy->textureInfo());

    return TextureProxyView(sk_ref_sp(proxy), swizzle);
}

void DrawContext::clear(const SkColor4f& clearColor) {
    fPendingLoadOp = LoadOp::kClear;
    SkPMColor4f pmColor = clearColor.premul();
    fPendingClearColor = pmColor.array();

    // A fullscreen clear will overwrite anything that came before, so start a new DrawList.
    // NOTE: Eventually the current DrawTask should be reset, once there are no longer implicit
    // dependencies on atlas tasks between DrawContexts. When that's resolved, the only tasks in the
    // current DrawTask are those that directly impact the target, which becomes irrelevant with the
    // clear op overwriting it. For now, preserve the previous tasks that might include atlas
    // uploads that are not explicitly shared between DrawContexts.
    fPendingDraws = std::make_unique<DrawList>();
    if (fComputePathAtlas) {
        fComputePathAtlas->reset();
    }
}

void DrawContext::recordDraw(const Renderer* renderer,
                             const Transform& localToDevice,
                             const Geometry& geometry,
                             const Clip& clip,
                             DrawOrder ordering,
                             const PaintParams* paint,
                             const StrokeStyle* stroke) {
    SkASSERT(SkIRect::MakeSize(this->imageInfo().dimensions()).contains(clip.scissor()));
    fPendingDraws->recordDraw(renderer, localToDevice, geometry, clip, ordering, paint, stroke);
}

bool DrawContext::recordUpload(Recorder* recorder,
                               sk_sp<TextureProxy> targetProxy,
                               const SkColorInfo& srcColorInfo,
                               const SkColorInfo& dstColorInfo,
                               const std::vector<MipLevel>& levels,
                               const SkIRect& dstRect,
                               std::unique_ptr<ConditionalUploadContext> condContext) {
    // Our caller should have clipped to the bounds of the surface already.
    SkASSERT(targetProxy->isFullyLazy() ||
             SkIRect::MakeSize(targetProxy->dimensions()).contains(dstRect));
    return fPendingUploads->recordUpload(recorder,
                                         std::move(targetProxy),
                                         srcColorInfo,
                                         dstColorInfo,
                                         levels,
                                         dstRect,
                                         std::move(condContext));
}

PathAtlas* DrawContext::getComputePathAtlas(Recorder* recorder) {
    if (!fComputePathAtlas) {
        fComputePathAtlas = recorder->priv().atlasProvider()->createComputePathAtlas(recorder);
    }
    return fComputePathAtlas.get();
}

void DrawContext::flush(Recorder* recorder) {
    if (fPendingUploads->size() > 0) {
        TRACE_EVENT_INSTANT1("skia.gpu", TRACE_FUNC, TRACE_EVENT_SCOPE_THREAD,
                             "# uploads", fPendingUploads->size());
        fCurrentDrawTask->addTask(UploadTask::Make(fPendingUploads.get()));
        // The UploadTask steals the collected upload instances, automatically resetting this list
        SkASSERT(fPendingUploads->size() == 0);
    }

    // Generate compute dispatches that render into the atlas texture used by pending draws.
    // TODO: Once compute atlas caching is implemented, DrawContext might not hold onto to this
    // at which point a recordDispatch() could be added and it stores a pending dispatches list that
    // much like how uploads are handled. In that case, Device would be responsible for triggering
    // the recording of dispatches, but that may happen naturally in AtlasProvider::recordUploads().
    if (fComputePathAtlas) {
        auto dispatchGroup = fComputePathAtlas->recordDispatches(recorder);
        fComputePathAtlas->reset();

        if (dispatchGroup) {
            // For now this check is valid as all coverage mask draws involve dispatches
            SkASSERT(fPendingDraws->hasCoverageMaskDraws());

            TRACE_EVENT_INSTANT1("skia.gpu", TRACE_FUNC, TRACE_EVENT_SCOPE_THREAD,
                                 "# dispatches", dispatchGroup->dispatches().size());
            ComputeTask::DispatchGroupList dispatches;
            dispatches.emplace_back(std::move(dispatchGroup));
            fCurrentDrawTask->addTask(ComputeTask::Make(std::move(dispatches)));
        } // else no pending compute work needed to be recorded
    } // else platform doesn't support compute or atlas was never initialized.

    if (fPendingDraws->renderStepCount() == 0 && fPendingLoadOp != LoadOp::kClear) {
        // Nothing will be rasterized to the target that warrants a RenderPassTask, but we preserve
        // any added uploads or compute tasks since those could also affect the target w/o
        // rasterizing anything directly.
        return;
    }

    // Convert the pending draws and load/store ops into a DrawPass that will be executed after
    // the collected uploads and compute dispatches.
    // TODO: At this point, there's only ever one DrawPass in a RenderPassTask to a target. When
    // subpasses are implemented, they will either be collected alongside fPendingDraws or added
    // to the RenderPassTask separately.
    std::unique_ptr<DrawPass> pass = DrawPass::Make(recorder,
                                                    std::move(fPendingDraws),
                                                    fTarget,
                                                    this->imageInfo(),
                                                    std::make_pair(fPendingLoadOp, fPendingStoreOp),
                                                    fPendingClearColor);
    fPendingDraws = std::make_unique<DrawList>();
    fPendingLoadOp = LoadOp::kLoad;
    fPendingStoreOp = StoreOp::kStore;

    if (pass) {
        SkASSERT(fTarget.get() == pass->target());

        const Caps* caps = recorder->priv().caps();
        auto [loadOp, storeOp] = pass->ops();
        auto writeSwizzle = caps->getWriteSwizzle(this->colorInfo().colorType(),
                                                  fTarget->textureInfo());

        RenderPassDesc desc = RenderPassDesc::Make(caps, fTarget->textureInfo(), loadOp, storeOp,
                                                   pass->depthStencilFlags(),
                                                   pass->clearColor(),
                                                   pass->requiresMSAA(),
                                                   writeSwizzle);

        RenderPassTask::DrawPassList passes;
        passes.emplace_back(std::move(pass));
        fCurrentDrawTask->addTask(RenderPassTask::Make(std::move(passes), desc, fTarget));
    }
    // else pass creation failed, DrawPass will have logged why. Don't discard the previously
    // accumulated tasks, however, since they may represent operations on an atlas that other
    // DrawContexts now implicitly depend on.
}

sk_sp<Task> DrawContext::snapDrawTask(Recorder* recorder) {
    // If flush() was explicitly called earlier and no new work was recorded, this call to flush()
    // is a no-op and shouldn't hurt performance.
    this->flush(recorder);

    if (!fCurrentDrawTask->hasTasks()) {
        return nullptr;
    }

    sk_sp<Task> snappedTask = std::move(fCurrentDrawTask);
    fCurrentDrawTask = sk_make_sp<DrawTask>(fTarget);
    return snappedTask;
}

RenderPassDesc RenderPassDesc::Make(const Caps* caps,
                                    const TextureInfo& targetInfo,
                                    LoadOp loadOp,
                                    StoreOp storeOp,
                                    SkEnumBitMask<DepthStencilFlags> depthStencilFlags,
                                    const std::array<float, 4>& clearColor,
                                    bool requiresMSAA,
                                    Swizzle writeSwizzle) {
    RenderPassDesc desc;
    desc.fWriteSwizzle = writeSwizzle;
    desc.fSampleCount = 1;
    // It doesn't make sense to have a storeOp for our main target not be store. Why are we doing
    // this DrawPass then
    SkASSERT(storeOp == StoreOp::kStore);
    if (requiresMSAA) {
        if (caps->msaaRenderToSingleSampledSupport()) {
            desc.fColorAttachment.fTextureInfo = targetInfo;
            desc.fColorAttachment.fLoadOp = loadOp;
            desc.fColorAttachment.fStoreOp = storeOp;
            desc.fSampleCount = caps->defaultMSAASamplesCount();
        } else {
            // TODO: If the resolve texture isn't readable, the MSAA color attachment will need to
            // be persistently associated with the framebuffer, in which case it's not discardable.
            auto msaaTextureInfo = caps->getDefaultMSAATextureInfo(targetInfo, Discardable::kYes);
            if (msaaTextureInfo.isValid()) {
                desc.fColorAttachment.fTextureInfo = msaaTextureInfo;
                if (loadOp != LoadOp::kClear) {
                    desc.fColorAttachment.fLoadOp = LoadOp::kDiscard;
                } else {
                    desc.fColorAttachment.fLoadOp = LoadOp::kClear;
                }
                desc.fColorAttachment.fStoreOp = StoreOp::kDiscard;

                desc.fColorResolveAttachment.fTextureInfo = targetInfo;
                if (loadOp != LoadOp::kLoad) {
                    desc.fColorResolveAttachment.fLoadOp = LoadOp::kDiscard;
                } else {
                    desc.fColorResolveAttachment.fLoadOp = LoadOp::kLoad;
                }
                desc.fColorResolveAttachment.fStoreOp = storeOp;

                desc.fSampleCount = msaaTextureInfo.numSamples();
            } else {
                // fall back to single sampled
                desc.fColorAttachment.fTextureInfo = targetInfo;
                desc.fColorAttachment.fLoadOp = loadOp;
                desc.fColorAttachment.fStoreOp = storeOp;
            }
        }
    } else {
        desc.fColorAttachment.fTextureInfo = targetInfo;
        desc.fColorAttachment.fLoadOp = loadOp;
        desc.fColorAttachment.fStoreOp = storeOp;
    }
    desc.fClearColor = clearColor;

    if (depthStencilFlags != DepthStencilFlags::kNone) {
        desc.fDepthStencilAttachment.fTextureInfo = caps->getDefaultDepthStencilTextureInfo(
                depthStencilFlags, desc.fSampleCount, targetInfo.isProtected());
        // Always clear the depth and stencil to 0 at the start of a DrawPass, but discard at the
        // end since their contents do not affect the next frame.
        desc.fDepthStencilAttachment.fLoadOp = LoadOp::kClear;
        desc.fClearDepth = 0.f;
        desc.fClearStencil = 0;
        desc.fDepthStencilAttachment.fStoreOp = StoreOp::kDiscard;
    }

    return desc;
}

} // namespace skgpu::graphite
