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

#include "dawn/common/Constants.h"
#include "dawn/native/Adapter.h"
#include "dawn/native/Device.h"
#include "dawn/native/ObjectType_autogen.h"
#include "dawn/native/Surface.h"
#include "dawn/native/Texture.h"
#include "dawn/native/ValidationUtils_autogen.h"

namespace dawn::native {

    namespace {

        class ErrorSwapChain final : public SwapChainBase {
          public:
            ErrorSwapChain(DeviceBase* device) : SwapChainBase(device, ObjectBase::kError) {
            }

          private:
            void APIConfigure(wgpu::TextureFormat format,
                              wgpu::TextureUsage allowedUsage,
                              uint32_t width,
                              uint32_t height) override {
                GetDevice()->ConsumedError(
                    DAWN_FORMAT_VALIDATION_ERROR("%s is an error swapchain.", this));
            }

            TextureViewBase* APIGetCurrentTextureView() override {
                GetDevice()->ConsumedError(
                    DAWN_FORMAT_VALIDATION_ERROR("%s is an error swapchain.", this));
                return TextureViewBase::MakeError(GetDevice());
            }

            void APIPresent() override {
                GetDevice()->ConsumedError(
                    DAWN_FORMAT_VALIDATION_ERROR("%s is an error swapchain.", this));
            }
        };

    }  // anonymous namespace

    MaybeError ValidateSwapChainDescriptor(const DeviceBase* device,
                                           const Surface* surface,
                                           const SwapChainDescriptor* descriptor) {
        if (descriptor->implementation != 0) {
            DAWN_INVALID_IF(surface != nullptr,
                            "Exactly one of surface or implementation must be set");

            DawnSwapChainImplementation* impl =
                reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation);

            DAWN_INVALID_IF(!impl->Init || !impl->Destroy || !impl->Configure ||
                                !impl->GetNextTexture || !impl->Present,
                            "Implementation is incomplete");

        } else {
            DAWN_INVALID_IF(surface == nullptr,
                            "At least one of surface or implementation must be set");

            DAWN_TRY(ValidatePresentMode(descriptor->presentMode));

// TODO(crbug.com/dawn/160): Lift this restriction once wgpu::Instance::GetPreferredSurfaceFormat is
// implemented.
// TODO(dawn:286):
#if defined(DAWN_PLATFORM_ANDROID)
            constexpr wgpu::TextureFormat kRequireSwapChainFormat = wgpu::TextureFormat::RGBA8Unorm;
#else
            constexpr wgpu::TextureFormat kRequireSwapChainFormat = wgpu::TextureFormat::BGRA8Unorm;
#endif  // !defined(DAWN_PLATFORM_ANDROID)
            DAWN_INVALID_IF(descriptor->format != kRequireSwapChainFormat,
                            "Format (%s) is not %s, which is (currently) the only accepted format.",
                            descriptor->format, kRequireSwapChainFormat);

            DAWN_INVALID_IF(descriptor->usage != wgpu::TextureUsage::RenderAttachment,
                            "Usage (%s) is not %s, which is (currently) the only accepted usage.",
                            descriptor->usage, wgpu::TextureUsage::RenderAttachment);

            DAWN_INVALID_IF(descriptor->width == 0 || descriptor->height == 0,
                            "Swap Chain size (width: %u, height: %u) is empty.", descriptor->width,
                            descriptor->height);

            DAWN_INVALID_IF(
                descriptor->width > device->GetLimits().v1.maxTextureDimension2D ||
                    descriptor->height > device->GetLimits().v1.maxTextureDimension2D,
                "Swap Chain size (width: %u, height: %u) is greater than the maximum 2D texture "
                "size (width: %u, height: %u).",
                descriptor->width, descriptor->height, device->GetLimits().v1.maxTextureDimension2D,
                device->GetLimits().v1.maxTextureDimension2D);
        }

        return {};
    }

    TextureDescriptor GetSwapChainBaseTextureDescriptor(NewSwapChainBase* swapChain) {
        TextureDescriptor desc;
        desc.usage = swapChain->GetUsage();
        desc.dimension = wgpu::TextureDimension::e2D;
        desc.size = {swapChain->GetWidth(), swapChain->GetHeight(), 1};
        desc.format = swapChain->GetFormat();
        desc.mipLevelCount = 1;
        desc.sampleCount = 1;

        return desc;
    }

    // SwapChainBase

    SwapChainBase::SwapChainBase(DeviceBase* device) : ApiObjectBase(device, kLabelNotImplemented) {
        TrackInDevice();
    }

    SwapChainBase::SwapChainBase(DeviceBase* device, ObjectBase::ErrorTag tag)
        : ApiObjectBase(device, tag) {
    }

    SwapChainBase::~SwapChainBase() {
    }

    void SwapChainBase::DestroyImpl() {
    }

    // static
    SwapChainBase* SwapChainBase::MakeError(DeviceBase* device) {
        return new ErrorSwapChain(device);
    }

    ObjectType SwapChainBase::GetType() const {
        return ObjectType::SwapChain;
    }

    // OldSwapChainBase

    OldSwapChainBase::OldSwapChainBase(DeviceBase* device, const SwapChainDescriptor* descriptor)
        : SwapChainBase(device),
          mImplementation(
              *reinterpret_cast<DawnSwapChainImplementation*>(descriptor->implementation)) {
    }

    OldSwapChainBase::~OldSwapChainBase() {
        if (!IsError()) {
            const auto& im = GetImplementation();
            im.Destroy(im.userData);
        }
    }

    void OldSwapChainBase::APIConfigure(wgpu::TextureFormat format,
                                        wgpu::TextureUsage allowedUsage,
                                        uint32_t width,
                                        uint32_t height) {
        if (GetDevice()->ConsumedError(ValidateConfigure(format, allowedUsage, width, height))) {
            return;
        }
        ASSERT(!IsError());

        allowedUsage |= wgpu::TextureUsage::Present;

        mFormat = format;
        mAllowedUsage = allowedUsage;
        mWidth = width;
        mHeight = height;
        mImplementation.Configure(mImplementation.userData, static_cast<WGPUTextureFormat>(format),
                                  static_cast<WGPUTextureUsage>(allowedUsage), width, height);
    }

    TextureViewBase* OldSwapChainBase::APIGetCurrentTextureView() {
        if (GetDevice()->ConsumedError(ValidateGetCurrentTextureView())) {
            return TextureViewBase::MakeError(GetDevice());
        }
        ASSERT(!IsError());

        // Return the same current texture view until Present is called.
        if (mCurrentTextureView != nullptr) {
            // Calling GetCurrentTextureView always returns a new reference so add it even when
            // reuse the existing texture view.
            mCurrentTextureView->Reference();
            return mCurrentTextureView.Get();
        }

        // Create the backing texture and the view.
        TextureDescriptor descriptor;
        descriptor.dimension = wgpu::TextureDimension::e2D;
        descriptor.size.width = mWidth;
        descriptor.size.height = mHeight;
        descriptor.size.depthOrArrayLayers = 1;
        descriptor.sampleCount = 1;
        descriptor.format = mFormat;
        descriptor.mipLevelCount = 1;
        descriptor.usage = mAllowedUsage;

        // Get the texture but remove the external refcount because it is never passed outside
        // of dawn_native
        mCurrentTexture = AcquireRef(GetNextTextureImpl(&descriptor));

        mCurrentTextureView = mCurrentTexture->APICreateView();
        return mCurrentTextureView.Get();
    }

    void OldSwapChainBase::APIPresent() {
        if (GetDevice()->ConsumedError(ValidatePresent())) {
            return;
        }
        ASSERT(!IsError());

        if (GetDevice()->ConsumedError(OnBeforePresent(mCurrentTextureView.Get()))) {
            return;
        }

        mImplementation.Present(mImplementation.userData);

        mCurrentTexture = nullptr;
        mCurrentTextureView = nullptr;
    }

    const DawnSwapChainImplementation& OldSwapChainBase::GetImplementation() {
        ASSERT(!IsError());
        return mImplementation;
    }

    MaybeError OldSwapChainBase::ValidateConfigure(wgpu::TextureFormat format,
                                                   wgpu::TextureUsage allowedUsage,
                                                   uint32_t width,
                                                   uint32_t height) const {
        DAWN_TRY(GetDevice()->ValidateIsAlive());
        DAWN_TRY(GetDevice()->ValidateObject(this));

        DAWN_TRY(ValidateTextureUsage(allowedUsage));
        DAWN_TRY(ValidateTextureFormat(format));

        DAWN_INVALID_IF(width == 0 || height == 0,
                        "Configuration size (width: %u, height: %u) for %s is empty.", width,
                        height, this);

        return {};
    }

    MaybeError OldSwapChainBase::ValidateGetCurrentTextureView() const {
        DAWN_TRY(GetDevice()->ValidateIsAlive());
        DAWN_TRY(GetDevice()->ValidateObject(this));

        // If width is 0, it implies swap chain has never been configured
        DAWN_INVALID_IF(mWidth == 0, "%s was not configured prior to calling GetNextTexture.",
                        this);

        return {};
    }

    MaybeError OldSwapChainBase::ValidatePresent() const {
        DAWN_TRY(GetDevice()->ValidateIsAlive());
        DAWN_TRY(GetDevice()->ValidateObject(this));

        DAWN_INVALID_IF(
            mCurrentTextureView == nullptr,
            "GetCurrentTextureView was not called on %s this frame prior to calling Present.",
            this);

        return {};
    }

    // Implementation of NewSwapChainBase

    NewSwapChainBase::NewSwapChainBase(DeviceBase* device,
                                       Surface* surface,
                                       const SwapChainDescriptor* descriptor)
        : SwapChainBase(device),
          mAttached(false),
          mWidth(descriptor->width),
          mHeight(descriptor->height),
          mFormat(descriptor->format),
          mUsage(descriptor->usage),
          mPresentMode(descriptor->presentMode),
          mSurface(surface) {
    }

    NewSwapChainBase::~NewSwapChainBase() {
        if (mCurrentTextureView != nullptr) {
            ASSERT(mCurrentTextureView->GetTexture()->GetTextureState() ==
                   TextureBase::TextureState::Destroyed);
        }

        ASSERT(!mAttached);
    }

    void NewSwapChainBase::DetachFromSurface() {
        if (mAttached) {
            DetachFromSurfaceImpl();
            mSurface = nullptr;
            mAttached = false;
        }
    }

    void NewSwapChainBase::SetIsAttached() {
        mAttached = true;
    }

    void NewSwapChainBase::APIConfigure(wgpu::TextureFormat format,
                                        wgpu::TextureUsage allowedUsage,
                                        uint32_t width,
                                        uint32_t height) {
        GetDevice()->ConsumedError(
            DAWN_FORMAT_VALIDATION_ERROR("Configure is invalid for surface-based swapchains."));
    }

    TextureViewBase* NewSwapChainBase::APIGetCurrentTextureView() {
        Ref<TextureViewBase> result;
        if (GetDevice()->ConsumedError(GetCurrentTextureView(), &result,
                                       "calling %s.GetCurrentTextureView()", this)) {
            return TextureViewBase::MakeError(GetDevice());
        }
        return result.Detach();
    }

    ResultOrError<Ref<TextureViewBase>> NewSwapChainBase::GetCurrentTextureView() {
        DAWN_TRY(ValidateGetCurrentTextureView());

        if (mCurrentTextureView != nullptr) {
            // Calling GetCurrentTextureView always returns a new reference.
            return mCurrentTextureView;
        }

        DAWN_TRY_ASSIGN(mCurrentTextureView, GetCurrentTextureViewImpl());

        // Check that the return texture view matches exactly what was given for this descriptor.
        ASSERT(mCurrentTextureView->GetTexture()->GetFormat().format == mFormat);
        ASSERT(IsSubset(mUsage, mCurrentTextureView->GetTexture()->GetUsage()));
        ASSERT(mCurrentTextureView->GetLevelCount() == 1);
        ASSERT(mCurrentTextureView->GetLayerCount() == 1);
        ASSERT(mCurrentTextureView->GetDimension() == wgpu::TextureViewDimension::e2D);
        ASSERT(mCurrentTextureView->GetTexture()
                   ->GetMipLevelVirtualSize(mCurrentTextureView->GetBaseMipLevel())
                   .width == mWidth);
        ASSERT(mCurrentTextureView->GetTexture()
                   ->GetMipLevelVirtualSize(mCurrentTextureView->GetBaseMipLevel())
                   .height == mHeight);

        return mCurrentTextureView;
    }

    void NewSwapChainBase::APIPresent() {
        if (GetDevice()->ConsumedError(ValidatePresent())) {
            return;
        }

        if (GetDevice()->ConsumedError(PresentImpl())) {
            return;
        }

        ASSERT(mCurrentTextureView->GetTexture()->GetTextureState() ==
               TextureBase::TextureState::Destroyed);
        mCurrentTextureView = nullptr;
    }

    uint32_t NewSwapChainBase::GetWidth() const {
        return mWidth;
    }

    uint32_t NewSwapChainBase::GetHeight() const {
        return mHeight;
    }

    wgpu::TextureFormat NewSwapChainBase::GetFormat() const {
        return mFormat;
    }

    wgpu::TextureUsage NewSwapChainBase::GetUsage() const {
        return mUsage;
    }

    wgpu::PresentMode NewSwapChainBase::GetPresentMode() const {
        return mPresentMode;
    }

    Surface* NewSwapChainBase::GetSurface() const {
        return mSurface;
    }

    bool NewSwapChainBase::IsAttached() const {
        return mAttached;
    }

    wgpu::BackendType NewSwapChainBase::GetBackendType() const {
        return GetDevice()->GetAdapter()->GetBackendType();
    }

    MaybeError NewSwapChainBase::ValidatePresent() const {
        DAWN_TRY(GetDevice()->ValidateIsAlive());
        DAWN_TRY(GetDevice()->ValidateObject(this));

        DAWN_INVALID_IF(!mAttached, "Cannot call Present called on detached %s.", this);

        DAWN_INVALID_IF(
            mCurrentTextureView == nullptr,
            "GetCurrentTextureView was not called on %s this frame prior to calling Present.",
            this);

        return {};
    }

    MaybeError NewSwapChainBase::ValidateGetCurrentTextureView() const {
        DAWN_TRY(GetDevice()->ValidateIsAlive());
        DAWN_TRY(GetDevice()->ValidateObject(this));

        DAWN_INVALID_IF(!mAttached, "Cannot call GetCurrentTextureView on detached %s.", this);

        return {};
    }

}  // namespace dawn::native
