// 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:
    explicit 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
