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

#include "src/gpu/graphite/Buffer.h"
#include "src/gpu/graphite/DrawCommands.h"

namespace skgpu::graphite {

DrawWriter::DrawWriter(DrawPassCommands::List* commandList, DrawBufferManager* bufferManager)
        : fCommandList(commandList)
        , fManager(bufferManager)
        , fRenderState(RenderStateFlags::kNone)
        , fPrimitiveType(PrimitiveType::kTriangles)
        , fStaticStride(0)
        , fAppendStride(0)
        , fAppend({})
        , fStatic({})
        , fIndices({})
        , fBoundAppend({})
        , fBoundStatic({})
        , fBoundIndices({})
        , fTemplateCount(0)
        , fPendingCount(0) {
    SkASSERT(commandList && bufferManager);
}

void DrawWriter::setTemplate(BindBufferInfo staticData, BindBufferInfo indices,
                             BindBufferInfo appendData, uint32_t templateCount) {
    if (fPendingCount == 0) {
        // A pendingCount of zero indicates that a either a newPipelineState() or dynamicState()
        // triggered a flush, so we want to update the incoming member buffers.
        fAppend = appendData;
        fStatic = staticData;
        fIndices = indices;
        fTemplateCount = templateCount;
    } else {
        // IF non-zero pending count, then we must not have flushed, so we cannot have called a new
        // pipeline yet. So we know the buffers MUST be the same.
        // IF a new buffer is acquired in reserve(), it calls a flush on the previous binding. The
        // flush sets the pendingCount to zero, skipping this code path.
        SkASSERT(fAppend == appendData && fStatic == staticData && fIndices == indices);
        SkASSERT((templateCount == 0 &&
                 (fRenderState & RenderStateFlags::kAppendDynamicInstances)) ||
                 fTemplateCount == templateCount);
    }
}

void DrawWriter::flushInternal() {
    // Skip flush if no items appended, or dynamic instances resolved to zero count.
    if (fPendingCount == 0 ||
        ((fRenderState & RenderStateFlags::kAppendDynamicInstances) && fTemplateCount == 0)) {
        return;
    }

    // Calculate base offsets from buffer info for the draw commands.
    // - If a valid bufferFoo exists and  matches the current stride, use pendingBaseFoo as a
    //   pseudo-alias for offset and reset the offset and size before assigning to boundBufferFoo.
    // - If a valid bufferFoo does not exist, or is not stride aligned, then draw from the start of
    //   the offset with pendingBaseFoo = 0 and assign the current buffer.
    auto bind = [](const BindBufferInfo& buffer, uint32_t stride, BindBufferInfo& boundBuffer,
                   uint32_t& pendingBase) -> bool {
        bool shouldBind = false;
        if (buffer.fBuffer) {
            BindBufferInfo newBinding = buffer;
            if (buffer.fOffset % stride == 0) {
                pendingBase = buffer.fOffset / stride;
                newBinding = {buffer.fBuffer, 0, SkTo<uint32_t>(buffer.fBuffer->size())};
            }
            shouldBind = boundBuffer != newBinding;
            boundBuffer = newBinding;
        }
        return shouldBind;
    };

    uint32_t pendingBaseAppend = 0;
    uint32_t pendingBaseStatic = 0;
    uint32_t pendingBaseIndices = 0;
    if (bind(fAppend, fAppendStride, fBoundAppend, pendingBaseAppend)) {
        fCommandList->bindAppendDataBuffer(fBoundAppend);
    }
    if (bind(fStatic, fStaticStride, fBoundStatic, pendingBaseStatic)) {
        fCommandList->bindStaticDataBuffer(fBoundStatic);
    }
    if (bind(fIndices, sizeof(uint16_t), fBoundIndices, pendingBaseIndices)) {
        fCommandList->bindIndexBuffer(fBoundIndices);
    }

    // Before any draw commands are added, check if the DrawWriter has an assigned barrier type
    // to issue prior to draw calls.
    if (fBarrierToIssueBeforeDraws.has_value()) {
        fCommandList->addBarrier(fBarrierToIssueBeforeDraws.value());
    }

    // Issue the appropriate draw call (instanced vs. non-instanced) based on the current
    // fTemplateCount. Because of the initial AppendDynamicInstances && fTemplateCount check, any
    // DynamicInstance render step must have valid (non-zero) templateCount data at this point.
    if (fTemplateCount) {
        SkASSERT((pendingBaseAppend + fPendingCount)*fAppendStride <= fBoundAppend.fSize);
        if (fIndices) {
            // It's not possible to validate that the indices stored in fIndices access only valid
            // data within fVertices. Simply validate that fIndices holds enough data for the
            // vertex count that's drawn.
            SkASSERT(fTemplateCount*sizeof(uint16_t) <= fIndices.fSize);
            fCommandList->drawIndexedInstanced(fPrimitiveType,
                                               pendingBaseIndices,
                                               fTemplateCount,
                                               pendingBaseStatic,
                                               pendingBaseAppend,
                                               fPendingCount);

        } else {
            SkASSERT(fTemplateCount*fStaticStride <= fStatic.fSize);
            fCommandList->drawInstanced(fPrimitiveType, pendingBaseStatic, fTemplateCount,
                                        pendingBaseAppend, fPendingCount);
        }

        // Clear instancing template state after the draw is recorded for non-Fixed RenderState
        if (fRenderState &
            (RenderStateFlags::kAppendInstances | RenderStateFlags::kAppendDynamicInstances)) {
            fAppend = {};
            if (fRenderState & RenderStateFlags::kAppendDynamicInstances) {
                fTemplateCount = 0;
            }
        }
    } else {
        // Issue non-instanced draw call (indexed or non-indexed).
        if (fIndices) {
            // As before, just validate there is sufficient index data
            SkASSERT(fPendingCount*sizeof(uint16_t) <= fIndices.fSize);
            fCommandList->drawIndexed(fPrimitiveType,
                                      pendingBaseIndices,
                                      fPendingCount,
                                      pendingBaseAppend);
        } else {
            SkASSERT((pendingBaseAppend + fPendingCount)*fStaticStride <= fBoundAppend.fSize);
            fCommandList->draw(fPrimitiveType, pendingBaseAppend, fPendingCount);
        }

        // Clear vertex template state after the draw is recorded for non-Fixed RenderState
        if (fRenderState & RenderStateFlags::kAppendVertices) {
            fAppend = {};
        }
    }

    // Mark all appended items as drawn.
    fPendingCount = 0;
}

} // namespace skgpu::graphite
