// Copyright 2019 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "dawn_native/RenderEncoderBase.h"

#include "common/Constants.h"
#include "dawn_native/Buffer.h"
#include "dawn_native/CommandEncoder.h"
#include "dawn_native/Commands.h"
#include "dawn_native/Device.h"
#include "dawn_native/RenderPipeline.h"

#include <math.h>
#include <string.h>

namespace dawn_native {

    RenderEncoderBase::RenderEncoderBase(DeviceBase* device,
                                         CommandEncoderBase* topLevelEncoder,
                                         CommandAllocator* allocator)
        : ProgrammablePassEncoder(device, topLevelEncoder, allocator) {
    }

    RenderEncoderBase::RenderEncoderBase(DeviceBase* device,
                                         CommandEncoderBase* topLevelEncoder,
                                         ErrorTag errorTag)
        : ProgrammablePassEncoder(device, topLevelEncoder, errorTag) {
    }

    void RenderEncoderBase::Draw(uint32_t vertexCount,
                                 uint32_t instanceCount,
                                 uint32_t firstVertex,
                                 uint32_t firstInstance) {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
            return;
        }

        DrawCmd* draw = mAllocator->Allocate<DrawCmd>(Command::Draw);
        draw->vertexCount = vertexCount;
        draw->instanceCount = instanceCount;
        draw->firstVertex = firstVertex;
        draw->firstInstance = firstInstance;
    }

    void RenderEncoderBase::DrawIndexed(uint32_t indexCount,
                                        uint32_t instanceCount,
                                        uint32_t firstIndex,
                                        int32_t baseVertex,
                                        uint32_t firstInstance) {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
            return;
        }

        DrawIndexedCmd* draw = mAllocator->Allocate<DrawIndexedCmd>(Command::DrawIndexed);
        draw->indexCount = indexCount;
        draw->instanceCount = instanceCount;
        draw->firstIndex = firstIndex;
        draw->baseVertex = baseVertex;
        draw->firstInstance = firstInstance;
    }

    void RenderEncoderBase::DrawIndirect(BufferBase* indirectBuffer, uint64_t indirectOffset) {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
            mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(indirectBuffer))) {
            return;
        }

        if (indirectOffset >= indirectBuffer->GetSize() ||
            indirectOffset + kDrawIndirectSize > indirectBuffer->GetSize()) {
            mTopLevelEncoder->HandleError("Indirect offset out of bounds");
            return;
        }

        DrawIndirectCmd* cmd = mAllocator->Allocate<DrawIndirectCmd>(Command::DrawIndirect);
        cmd->indirectBuffer = indirectBuffer;
        cmd->indirectOffset = indirectOffset;
    }

    void RenderEncoderBase::DrawIndexedIndirect(BufferBase* indirectBuffer,
                                                uint64_t indirectOffset) {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
            mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(indirectBuffer))) {
            return;
        }

        if (indirectOffset >= indirectBuffer->GetSize() ||
            indirectOffset + kDrawIndexedIndirectSize > indirectBuffer->GetSize()) {
            mTopLevelEncoder->HandleError("Indirect offset out of bounds");
            return;
        }

        DrawIndexedIndirectCmd* cmd =
            mAllocator->Allocate<DrawIndexedIndirectCmd>(Command::DrawIndexedIndirect);
        cmd->indirectBuffer = indirectBuffer;
        cmd->indirectOffset = indirectOffset;
    }

    void RenderEncoderBase::SetPipeline(RenderPipelineBase* pipeline) {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
            mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(pipeline))) {
            return;
        }

        SetRenderPipelineCmd* cmd =
            mAllocator->Allocate<SetRenderPipelineCmd>(Command::SetRenderPipeline);
        cmd->pipeline = pipeline;
    }

    void RenderEncoderBase::SetIndexBuffer(BufferBase* buffer, uint64_t offset) {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
            mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(buffer))) {
            return;
        }

        SetIndexBufferCmd* cmd = mAllocator->Allocate<SetIndexBufferCmd>(Command::SetIndexBuffer);
        cmd->buffer = buffer;
        cmd->offset = offset;
    }

    void RenderEncoderBase::SetVertexBuffers(uint32_t startSlot,
                                             uint32_t count,
                                             BufferBase* const* buffers,
                                             uint64_t const* offsets) {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
            return;
        }

        for (size_t i = 0; i < count; ++i) {
            if (mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(buffers[i]))) {
                return;
            }
        }

        SetVertexBuffersCmd* cmd =
            mAllocator->Allocate<SetVertexBuffersCmd>(Command::SetVertexBuffers);
        cmd->startSlot = startSlot;
        cmd->count = count;

        Ref<BufferBase>* cmdBuffers = mAllocator->AllocateData<Ref<BufferBase>>(count);
        for (size_t i = 0; i < count; ++i) {
            cmdBuffers[i] = buffers[i];
        }

        uint64_t* cmdOffsets = mAllocator->AllocateData<uint64_t>(count);
        memcpy(cmdOffsets, offsets, count * sizeof(uint64_t));
    }

}  // namespace dawn_native
