/*
 * Copyright 2023 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/compute/DispatchGroup.h"

#include "include/gpu/graphite/Recorder.h"
#include "src/gpu/graphite/BufferManager.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/CommandBuffer.h"
#include "src/gpu/graphite/ComputePipeline.h"
#include "src/gpu/graphite/Log.h"
#include "src/gpu/graphite/PipelineData.h"
#include "src/gpu/graphite/RecorderPriv.h"
#include "src/gpu/graphite/ResourceProvider.h"
#include "src/gpu/graphite/Texture.h"
#include "src/gpu/graphite/UniformManager.h"

namespace skgpu::graphite {

DispatchGroup::~DispatchGroup() = default;

bool DispatchGroup::prepareResources(ResourceProvider* resourceProvider) {
    fPipelines.reserve(fPipelines.size() + fPipelineDescs.size());
    for (const ComputePipelineDesc& desc : fPipelineDescs) {
        auto pipeline = resourceProvider->findOrCreateComputePipeline(desc);
        if (!pipeline) {
            SKGPU_LOG_W("Failed to create ComputePipeline for dispatch group. Dropping group!");
            return false;
        }
        fPipelines.push_back(std::move(pipeline));
    }

    for (int i = 0; i < fTextures.size(); ++i) {
        if (!fTextures[i]->textureInfo().isValid()) {
            SKGPU_LOG_W("Failed to validate bound texture. Dropping dispatch group!");
            return false;
        }
        if (!TextureProxy::InstantiateIfNotLazy(resourceProvider, fTextures[i].get())) {
            SKGPU_LOG_W("Failed to instantiate bound texture. Dropping dispatch group!");
            return false;
        }
    }

    // The DispatchGroup may be long lived on a Recording and we no longer need ComputePipelineDescs
    // once we've created pipelines.
    fPipelineDescs.clear();

    return true;
}

void DispatchGroup::addResourceRefs(CommandBuffer* commandBuffer) const {
    for (int i = 0; i < fPipelines.size(); ++i) {
        commandBuffer->trackResource(fPipelines[i]);
    }
    for (int i = 0; i < fTextures.size(); ++i) {
        commandBuffer->trackResource(fTextures[i]->refTexture());
    }
}

const Texture* DispatchGroup::getTexture(TextureIndex index) const {
    SkASSERT(index < SkToSizeT(fTextures.size()));
    SkASSERT(fTextures[index]);
    SkASSERT(fTextures[index]->texture());
    return fTextures[index]->texture();
}

using Builder = DispatchGroup::Builder;

Builder::Builder(Recorder* recorder) : fObj(new DispatchGroup()), fRecorder(recorder) {
    SkASSERT(fRecorder);
}

bool Builder::appendStep(const ComputeStep* step,
                         const DrawParams& params,
                         int ssboIndex,
                         std::optional<WorkgroupSize> globalSize) {
    SkASSERT(fObj);
    SkASSERT(step);

    Dispatch dispatch;

    // Process the step's resources.
    auto resources = step->resources();
    dispatch.fBindings.reserve(resources.size());

    // `nextIndex` matches the declaration order of resources as specified by the ComputeStep.
    int nextIndex = 0;

    // We assign buffer and texture indices from separate ranges. This is compatible with how
    // Graphite assigns indices in all of its backends: on Metal these map directly to
    // the `buffer()` and `texture()` index ranges; on Dawn/Vulkan these are allocated from separate
    // bind groups/descriptor sets.
    //
    // TODO(armansito): This also happens to be compatible with the binding index reassignment
    // scheme that the vello_shaders crate implements for WGSL->MSL translation (see
    // https://github.com/linebender/vello/blob/main/crates/shaders/src/compile/msl.rs#L10). However
    // Vello WGSL bindings are currently all assigned from the same bind group without separate
    // assignments for textures and buffers. We'll need to figure out how to re-map these on
    // Graphite's Dawn backend which should use the WGSL text directly.
    int bufferIndex = 0;
    int texIndex = 0;
    for (const ComputeStep::ResourceDesc& r : resources) {
        SkASSERT(r.fSlot == -1 || (r.fSlot >= 0 && r.fSlot < kMaxComputeDataFlowSlots));
        int index = nextIndex++;

        DispatchResourceOptional maybeResource;

        using DataFlow = ComputeStep::DataFlow;
        switch (r.fFlow) {
            case DataFlow::kVertexOutput:
            case DataFlow::kIndexOutput:
            case DataFlow::kInstanceOutput:
            case DataFlow::kIndirectDrawOutput: {
                auto bufferInfo = this->allocateDrawBuffer(step, r, index, params);
                if (bufferInfo) {
                    maybeResource = bufferInfo;
                }
                break;
            }
            case DataFlow::kPrivate:
                maybeResource = this->allocateResource(step, r, ssboIndex, index, params);
                break;
            case DataFlow::kShared: {
                // TODO: Support allocating a scratch texture
                SkASSERT(r.fSlot >= 0);
                // Allocate a new buffer only if the shared slot is empty.
                DispatchResourceOptional* slot = &fOutputTable.fSharedSlots[r.fSlot];
                if (std::holds_alternative<std::monostate>(*slot)) {
                    maybeResource = this->allocateResource(step, r, ssboIndex, index, params);
                    *slot = maybeResource;
                } else {
                    SkDEBUGCODE(using Type = ComputeStep::ResourceType;)
                    SkASSERT((r.fType == Type::kStorageBuffer &&
                              std::holds_alternative<BindBufferInfo>(*slot)) ||
                             ((r.fType == Type::kTexture || r.fType == Type::kStorageTexture) &&
                              std::holds_alternative<TextureIndex>(*slot)));
                    maybeResource = *slot;
                }
                break;
            }
        }

        int bindingIndex = 0;
        DispatchResource dispatchResource;
        if (const BindBufferInfo* buffer = std::get_if<BindBufferInfo>(&maybeResource)) {
            dispatchResource = *buffer;
            bindingIndex = bufferIndex++;
        } else if (const TextureIndex* texIdx = std::get_if<TextureIndex>(&maybeResource)) {
            dispatchResource = *texIdx;
            bindingIndex = texIndex++;
        } else {
            SKGPU_LOG_W("Failed to allocate resource for compute dispatch");
            return false;
        }
        dispatch.fBindings.push_back({static_cast<BindingIndex>(bindingIndex), dispatchResource});
    }

    auto wgBufferDescs = step->workgroupBuffers();
    if (!wgBufferDescs.empty()) {
        dispatch.fWorkgroupBuffers.push_back_n(wgBufferDescs.size(), wgBufferDescs.data());
    }

    // We need to switch pipelines if this step uses a different pipeline from the previous step.
    if (fObj->fPipelineDescs.empty() ||
        fObj->fPipelineDescs.back().uniqueID() != step->uniqueID()) {
        fObj->fPipelineDescs.push_back(ComputePipelineDesc(step));
    }

    dispatch.fPipelineIndex = fObj->fPipelineDescs.size() - 1;
    dispatch.fParams.fGlobalDispatchSize =
            globalSize ? *globalSize : step->calculateGlobalDispatchSize(params);
    dispatch.fParams.fLocalDispatchSize = step->localDispatchSize();

    fObj->fDispatchList.push_back(std::move(dispatch));

    return true;
}

void Builder::assignSharedBuffer(BindBufferInfo buffer, unsigned int slot) {
    SkASSERT(fObj);
    SkASSERT(buffer);

    fOutputTable.fSharedSlots[slot] = buffer;
}

void Builder::assignSharedTexture(sk_sp<TextureProxy> texture, unsigned int slot) {
    SkASSERT(fObj);
    SkASSERT(texture);

    fObj->fTextures.push_back(std::move(texture));
    fOutputTable.fSharedSlots[slot] = TextureIndex(fObj->fTextures.size() - 1);
}

std::unique_ptr<DispatchGroup> Builder::finalize() {
    auto obj = std::move(fObj);
    fOutputTable.reset();
    return obj;
}

BindBufferInfo Builder::getSharedBufferResource(unsigned int slot) const {
    SkASSERT(fObj);

    BindBufferInfo info;
    if (const BindBufferInfo* slotValue =
                std::get_if<BindBufferInfo>(&fOutputTable.fSharedSlots[slot])) {
        info = *slotValue;
    }
    return info;
}

sk_sp<TextureProxy> Builder::getSharedTextureResource(unsigned int slot) const {
    SkASSERT(fObj);

    const TextureIndex* idx = std::get_if<TextureIndex>(&fOutputTable.fSharedSlots[slot]);
    if (!idx) {
        return nullptr;
    }

    SkASSERT(*idx < SkToSizeT(fObj->fTextures.size()));
    return fObj->fTextures[*idx];
}

BindBufferInfo Builder::allocateDrawBuffer(const ComputeStep* step,
                                           const ComputeStep::ResourceDesc& resource,
                                           int resourceIdx,
                                           const DrawParams& params) {
    SkASSERT(step);
    SkASSERT(resource.fType == ComputeStep::ResourceType::kStorageBuffer);

    size_t bufferSize = step->calculateBufferSize(params, resourceIdx, resource);
    SkASSERT(bufferSize);

    DrawBufferManager* bufferMgr = fRecorder->priv().drawBufferManager();
    BindBufferInfo* slot = nullptr;
    BindBufferInfo info;
    using DataFlow = ComputeStep::DataFlow;
    switch (resource.fFlow) {
        case DataFlow::kVertexOutput:
            slot = &fOutputTable.fVertexBuffer;
            info = bufferMgr->getVertexStorage(bufferSize);
            break;
        case DataFlow::kIndexOutput:
            slot = &fOutputTable.fIndexBuffer;
            info = bufferMgr->getIndexStorage(bufferSize);
            break;
        case DataFlow::kInstanceOutput:
            slot = &fOutputTable.fInstanceBuffer;
            info = bufferMgr->getVertexStorage(bufferSize);
            break;
        case DataFlow::kIndirectDrawOutput:
            slot = &fOutputTable.fIndirectDrawBuffer;
            info = bufferMgr->getIndirectStorage(bufferSize);
            break;
        default:
            SkASSERT(false);
            break;
    }

    // Multiple ComputeSteps in a sequence are currently not allowed to output the same type of
    // geometry (this is enforced during ComputeStep construction).
    SkASSERT(*slot);
    if (info) {
        *slot = info;
    }
    return info;
}

DispatchResourceOptional Builder::allocateResource(const ComputeStep* step,
                                                   const ComputeStep::ResourceDesc& resource,
                                                   int ssboIdx,
                                                   int resourceIdx,
                                                   const DrawParams& params) {
    SkASSERT(step);
    using Type = ComputeStep::ResourceType;
    using ResourcePolicy = ComputeStep::ResourcePolicy;

    DrawBufferManager* bufferMgr = fRecorder->priv().drawBufferManager();
    DispatchResourceOptional result;
    switch (resource.fType) {
        case Type::kStorageBuffer: {
            size_t bufferSize = step->calculateBufferSize(params, resourceIdx, resource);
            SkASSERT(bufferSize);
            if (resource.fPolicy == ResourcePolicy::kMapped) {
                auto [ptr, bufInfo] = bufferMgr->getStoragePointer(bufferSize);
                if (ptr) {
                    step->prepareStorageBuffer(
                            params, ssboIdx, resourceIdx, resource, ptr, bufferSize);
                    result = bufInfo;
                }
            } else {
                auto bufInfo = bufferMgr->getStorage(bufferSize,
                                                     resource.fPolicy == ResourcePolicy::kClear
                                                             ? ClearBuffer::kYes
                                                             : ClearBuffer::kNo);
                if (bufInfo) {
                    result = bufInfo;
                }
            }
            break;
        }
        case Type::kUniformBuffer: {
            SkASSERT(resource.fPolicy == ResourcePolicy::kMapped);

            const auto& resourceReqs = fRecorder->priv().caps()->resourceBindingRequirements();
            UniformManager uboMgr(resourceReqs.fUniformBufferLayout);
            step->prepareUniformBuffer(params, resourceIdx, resource, &uboMgr);

            auto dataBlock = uboMgr.finishUniformDataBlock();
            SkASSERT(dataBlock.size());

            auto [writer, bufInfo] = bufferMgr->getUniformWriter(dataBlock.size());
            if (bufInfo) {
                writer.write(dataBlock.data(), dataBlock.size());
                result = bufInfo;
            }
            break;
        }
        case Type::kStorageTexture: {
            auto [size, colorType] =
                    step->calculateTextureParameters(params, resourceIdx, resource);
            SkASSERT(!size.isEmpty());
            SkASSERT(colorType != kUnknown_SkColorType);

            sk_sp<TextureProxy> texture = TextureProxy::MakeStorage(
                    fRecorder->priv().caps(), size, colorType, skgpu::Budgeted::kYes);
            if (texture) {
                fObj->fTextures.push_back(std::move(texture));
                result = TextureIndex(fObj->fTextures.size() - 1);
            }
            break;
        }
        case Type::kTexture:
            // This resource type is meant to be populated externally (e.g. by an upload or a render
            // pass) and only sampled by a ComputeStep. It's not meaningful to allocate an internal
            // texture for a DispatchGroup if none of the ComputeSteps will write to it.
            //
            // Instead of using internal allocation, this texture must be assigned explicitly to a
            // slot by calling the Builder::assignSharedTexture() method.
            SK_ABORT("a sampled texture must be externally assigned to a ComputeStep");
            break;
    }
    return result;
}

}  // namespace skgpu::graphite
