// Copyright 2018 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/ProgrammablePassEncoder.h"

#include "dawn_native/BindGroup.h"
#include "dawn_native/CommandBuffer.h"
#include "dawn_native/Commands.h"
#include "dawn_native/Device.h"
#include "dawn_native/ValidationUtils_autogen.h"

#include <string.h>

namespace dawn_native {

    ProgrammablePassEncoder::ProgrammablePassEncoder(DeviceBase* device,
                                                     CommandEncoderBase* topLevelEncoder,
                                                     CommandAllocator* allocator)
        : ObjectBase(device), mTopLevelEncoder(topLevelEncoder), mAllocator(allocator) {
        DAWN_ASSERT(allocator != nullptr);
    }

    ProgrammablePassEncoder::ProgrammablePassEncoder(DeviceBase* device,
                                                     CommandEncoderBase* topLevelEncoder,
                                                     ErrorTag errorTag)
        : ObjectBase(device, errorTag), mTopLevelEncoder(topLevelEncoder), mAllocator(nullptr) {
    }

    void ProgrammablePassEncoder::EndPass() {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
            return;
        }

        mTopLevelEncoder->PassEnded();
        mAllocator = nullptr;
    }

    void ProgrammablePassEncoder::InsertDebugMarker(const char* groupLabel) {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
            return;
        }

        InsertDebugMarkerCmd* cmd =
            mAllocator->Allocate<InsertDebugMarkerCmd>(Command::InsertDebugMarker);
        cmd->length = strlen(groupLabel);

        char* label = mAllocator->AllocateData<char>(cmd->length + 1);
        memcpy(label, groupLabel, cmd->length + 1);
    }

    void ProgrammablePassEncoder::PopDebugGroup() {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
            return;
        }

        mAllocator->Allocate<PopDebugGroupCmd>(Command::PopDebugGroup);
    }

    void ProgrammablePassEncoder::PushDebugGroup(const char* groupLabel) {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
            return;
        }

        PushDebugGroupCmd* cmd = mAllocator->Allocate<PushDebugGroupCmd>(Command::PushDebugGroup);
        cmd->length = strlen(groupLabel);

        char* label = mAllocator->AllocateData<char>(cmd->length + 1);
        memcpy(label, groupLabel, cmd->length + 1);
    }

    void ProgrammablePassEncoder::SetBindGroup(uint32_t groupIndex,
                                               BindGroupBase* group,
                                               uint32_t dynamicOffsetCount,
                                               const uint64_t* dynamicOffsets) {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands()) ||
            mTopLevelEncoder->ConsumedError(GetDevice()->ValidateObject(group))) {
            return;
        }

        if (groupIndex >= kMaxBindGroups) {
            mTopLevelEncoder->HandleError("Setting bind group over the max");
            return;
        }

        // TODO(shaobo.yan@intel.com): Implement dynamic buffer offset.
        if (dynamicOffsetCount != 0) {
            mTopLevelEncoder->HandleError("Dynamic Buffer Offset not supported yet");
            return;
        }

        SetBindGroupCmd* cmd = mAllocator->Allocate<SetBindGroupCmd>(Command::SetBindGroup);
        cmd->index = groupIndex;
        cmd->group = group;
    }

    void ProgrammablePassEncoder::SetPushConstants(dawn::ShaderStageBit stages,
                                                   uint32_t offset,
                                                   uint32_t count,
                                                   const void* data) {
        if (mTopLevelEncoder->ConsumedError(ValidateCanRecordCommands())) {
            return;
        }

        if (mTopLevelEncoder->ConsumedError(ValidateShaderStageBit(stages))) {
            return;
        }

        // TODO(cwallez@chromium.org): check for overflows
        if (offset + count > kMaxPushConstants) {
            mTopLevelEncoder->HandleError("Setting too many push constants");
            return;
        }

        SetPushConstantsCmd* cmd =
            mAllocator->Allocate<SetPushConstantsCmd>(Command::SetPushConstants);
        cmd->stages = stages;
        cmd->offset = offset;
        cmd->count = count;

        uint32_t* values = mAllocator->AllocateData<uint32_t>(count);
        memcpy(values, data, count * sizeof(uint32_t));
    }

    MaybeError ProgrammablePassEncoder::ValidateCanRecordCommands() const {
        if (mAllocator == nullptr) {
            return DAWN_VALIDATION_ERROR("Recording in an error or already ended pass encoder");
        }

        return nullptr;
    }

}  // namespace dawn_native
