/*
 * 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/task/TaskList.h"

#include "src/core/SkTraceEvent.h"
#include "src/gpu/graphite/ScratchResourceManager.h"

#include <cstdint>

namespace skgpu::graphite {

using Status = Task::Status;

template <typename Fn>
Status TaskList::visitTasks(Fn fn) {
    int discardCount = 0;
    for (sk_sp<Task>& task: fTasks) {
        if (!task) {
            discardCount++;
            continue; // Skip over discarded tasks
        }

        Status status = fn(task.get());
        if (status == Status::kFail) {
            return Status::kFail;
        } else if (status == Status::kDiscard) {
            task.reset();
            discardCount++;
        }
    }

    return discardCount == fTasks.size() ? Status::kDiscard : Status::kSuccess;
}

Status TaskList::prepareResources(ResourceProvider* resourceProvider,
                                  ScratchResourceManager* scratchManager,
                                  sk_sp<const RuntimeEffectDictionary> runtimeDict) {
    TRACE_EVENT1("skia.gpu", TRACE_FUNC, "# tasks", fTasks.size());
    scratchManager->pushScope();
    Status status = this->visitTasks([&](Task* task) {
        return task->prepareResources(resourceProvider, scratchManager, runtimeDict);
    });
    scratchManager->popScope();
    return status;
}

Status TaskList::addCommands(Context* context,
                             CommandBuffer* commandBuffer,
                             Task::ReplayTargetData replayData) {
    TRACE_EVENT1("skia.gpu", TRACE_FUNC, "# tasks", fTasks.size());
    return this->visitTasks([&](Task* task) {
        return task->addCommands(context, commandBuffer, replayData);
    });
}

bool TaskList::visitPipelines(const std::function<bool(const GraphicsPipeline*)>& visitor) {
    Status status = this->visitTasks([&](Task* task) {
        return task->visitPipelines(visitor) ? Status::kSuccess : Status::kFail;
    });
    // Map back to simple bool (treat kDiscard as true too, no pipelines to visit means all
    // pipelines were visited).
    return status != Status::kFail;
}

bool TaskList::visitProxies(const std::function<bool(const TextureProxy*)>& visitor) {
    Status status = this->visitTasks([&](Task* task) {
        return task->visitProxies(visitor) ? Status::kSuccess : Status::kFail;
    });
    // Map back to simple bool (treat kDiscard as true too, no pipelines to visit means all
    // pipelines were visited).
    return status != Status::kFail;
}

#if defined(SK_DUMP_TASKS)
void TaskList::visit(const std::function<void(const Task* task, bool isLast)>& visitor) const {
    // Find the last non-null task so we know when to draw the corner branch.
    const Task* lastNonNullTask = nullptr;
    for (int i = fTasks.size() - 1; i >= 0; --i) {
        if (fTasks[i]) {
            lastNonNullTask = fTasks[i].get();
            break;
        }
    }

    for (const sk_sp<Task>& task : fTasks) {
        if (task) {
            visitor(task.get(), task.get() == lastNonNullTask);
        }
    }
}
#endif

} // namespace skgpu::graphite
