// Copyright 2017 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/opengl/BufferGL.h"

#include "dawn_native/CommandBuffer.h"
#include "dawn_native/opengl/DeviceGL.h"

namespace dawn_native { namespace opengl {

    // Buffer

    // static
    ResultOrError<Ref<Buffer>> Buffer::CreateInternalBuffer(Device* device,
                                                            const BufferDescriptor* descriptor,
                                                            bool shouldLazyClear) {
        Ref<Buffer> buffer = AcquireRef(new Buffer(device, descriptor, shouldLazyClear));
        if (descriptor->mappedAtCreation) {
            DAWN_TRY(buffer->MapAtCreationInternal());
        }

        return std::move(buffer);
    }

    Buffer::Buffer(Device* device, const BufferDescriptor* descriptor)
        : BufferBase(device, descriptor) {
        // Allocate at least 4 bytes so clamped accesses are always in bounds.
        mAllocatedSize = std::max(GetSize(), uint64_t(4u));

        device->gl.GenBuffers(1, &mBuffer);
        device->gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);

        // The buffers with mappedAtCreation == true will be initialized in
        // BufferBase::MapAtCreation().
        if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting) &&
            !descriptor->mappedAtCreation) {
            std::vector<uint8_t> clearValues(mAllocatedSize, 1u);
            device->gl.BufferData(GL_ARRAY_BUFFER, mAllocatedSize, clearValues.data(),
                                  GL_STATIC_DRAW);
        } else {
            // Buffers start zeroed if you pass nullptr to glBufferData.
            device->gl.BufferData(GL_ARRAY_BUFFER, mAllocatedSize, nullptr, GL_STATIC_DRAW);
        }
    }

    Buffer::Buffer(Device* device, const BufferDescriptor* descriptor, bool shouldLazyClear)
        : Buffer(device, descriptor) {
        if (!shouldLazyClear) {
            SetIsDataInitialized();
        }
    }

    Buffer::~Buffer() = default;

    GLuint Buffer::GetHandle() const {
        return mBuffer;
    }

    bool Buffer::EnsureDataInitialized() {
        if (!NeedsInitialization()) {
            return false;
        }

        InitializeToZero();
        return true;
    }

    bool Buffer::EnsureDataInitializedAsDestination(uint64_t offset, uint64_t size) {
        if (!NeedsInitialization()) {
            return false;
        }

        if (IsFullBufferRange(offset, size)) {
            SetIsDataInitialized();
            return false;
        }

        InitializeToZero();
        return true;
    }

    bool Buffer::EnsureDataInitializedAsDestination(const CopyTextureToBufferCmd* copy) {
        if (!NeedsInitialization()) {
            return false;
        }

        if (IsFullBufferOverwrittenInTextureToBufferCopy(copy)) {
            SetIsDataInitialized();
            return false;
        }

        InitializeToZero();
        return true;
    }

    void Buffer::InitializeToZero() {
        ASSERT(NeedsInitialization());

        const uint64_t size = GetAllocatedSize();
        Device* device = ToBackend(GetDevice());

        const std::vector<uint8_t> clearValues(size, 0u);
        device->gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
        device->gl.BufferSubData(GL_ARRAY_BUFFER, 0, size, clearValues.data());
        device->IncrementLazyClearCountForTesting();

        SetIsDataInitialized();
    }

    bool Buffer::IsCPUWritableAtCreation() const {
        // TODO(enga): All buffers in GL can be mapped. Investigate if mapping them will cause the
        // driver to migrate it to shared memory.
        return true;
    }

    MaybeError Buffer::MapAtCreationImpl() {
        const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;
        gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
        mMappedData = gl.MapBufferRange(GL_ARRAY_BUFFER, 0, GetSize(), GL_MAP_WRITE_BIT);
        return {};
    }

    MaybeError Buffer::MapAsyncImpl(wgpu::MapMode mode, size_t offset, size_t size) {
        const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;

        // It is an error to map an empty range in OpenGL. We always have at least a 4-byte buffer
        // so we extend the range to be 4 bytes.
        if (size == 0) {
            if (offset != 0) {
                offset -= 4;
            }
            size = 4;
        }

        EnsureDataInitialized();

        // This does GPU->CPU synchronization, we could require a high
        // version of OpenGL that would let us map the buffer unsynchronized.
        gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
        void* mappedData = nullptr;
        if (mode & wgpu::MapMode::Read) {
            mappedData = gl.MapBufferRange(GL_ARRAY_BUFFER, offset, size, GL_MAP_READ_BIT);
        } else {
            ASSERT(mode & wgpu::MapMode::Write);
            mappedData = gl.MapBufferRange(GL_ARRAY_BUFFER, offset, size, GL_MAP_WRITE_BIT);
        }

        // The frontend asks that the pointer returned by GetMappedPointerImpl is from the start of
        // the resource but OpenGL gives us the pointer at offset. Remove the offset.
        mMappedData = static_cast<uint8_t*>(mappedData) - offset;
        return {};
    }

    void* Buffer::GetMappedPointerImpl() {
        // The mapping offset has already been removed.
        return mMappedData;
    }

    void Buffer::UnmapImpl() {
        const OpenGLFunctions& gl = ToBackend(GetDevice())->gl;

        gl.BindBuffer(GL_ARRAY_BUFFER, mBuffer);
        gl.UnmapBuffer(GL_ARRAY_BUFFER);
        mMappedData = nullptr;
    }

    void Buffer::DestroyImpl() {
        BufferBase::DestroyImpl();
        ToBackend(GetDevice())->gl.DeleteBuffers(1, &mBuffer);
        mBuffer = 0;
    }

}}  // namespace dawn_native::opengl
