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

#include "dawn_native/D3D12Backend.h"
#include "dawn_native/Instance.h"
#include "dawn_native/d3d12/AdapterD3D12.h"
#include "dawn_native/d3d12/D3D12Error.h"
#include "dawn_native/d3d12/PlatformFunctions.h"

namespace dawn::native::d3d12 {

    namespace {

        ResultOrError<ComPtr<IDXGIFactory4>> CreateFactory(const PlatformFunctions* functions,
                                                           BackendValidationLevel validationLevel,
                                                           bool beginCaptureOnStartup) {
            ComPtr<IDXGIFactory4> factory;

            uint32_t dxgiFactoryFlags = 0;

            // Enable the debug layer (requires the Graphics Tools "optional feature").
            {
                if (validationLevel != BackendValidationLevel::Disabled) {
                    ComPtr<ID3D12Debug3> debugController;
                    if (SUCCEEDED(
                            functions->d3d12GetDebugInterface(IID_PPV_ARGS(&debugController)))) {
                        ASSERT(debugController != nullptr);
                        debugController->EnableDebugLayer();
                        if (validationLevel == BackendValidationLevel::Full) {
                            debugController->SetEnableGPUBasedValidation(true);
                        }

                        // Enable additional debug layers.
                        dxgiFactoryFlags |= DXGI_CREATE_FACTORY_DEBUG;
                    }
                }

                if (beginCaptureOnStartup) {
                    ComPtr<IDXGraphicsAnalysis> graphicsAnalysis;
                    if (functions->dxgiGetDebugInterface1 != nullptr &&
                        SUCCEEDED(functions->dxgiGetDebugInterface1(
                            0, IID_PPV_ARGS(&graphicsAnalysis)))) {
                        graphicsAnalysis->BeginCapture();
                    }
                }
            }

            if (FAILED(functions->createDxgiFactory2(dxgiFactoryFlags, IID_PPV_ARGS(&factory)))) {
                return DAWN_INTERNAL_ERROR("Failed to create a DXGI factory");
            }

            ASSERT(factory != nullptr);
            return std::move(factory);
        }

        ResultOrError<std::unique_ptr<AdapterBase>> CreateAdapterFromIDXGIAdapter(
            Backend* backend,
            ComPtr<IDXGIAdapter> dxgiAdapter) {
            ComPtr<IDXGIAdapter3> dxgiAdapter3;
            DAWN_TRY(CheckHRESULT(dxgiAdapter.As(&dxgiAdapter3), "DXGIAdapter retrieval"));
            std::unique_ptr<Adapter> adapter =
                std::make_unique<Adapter>(backend, std::move(dxgiAdapter3));
            DAWN_TRY(adapter->Initialize());

            return {std::move(adapter)};
        }

    }  // anonymous namespace

    Backend::Backend(InstanceBase* instance)
        : BackendConnection(instance, wgpu::BackendType::D3D12) {
    }

    MaybeError Backend::Initialize() {
        mFunctions = std::make_unique<PlatformFunctions>();
        DAWN_TRY(mFunctions->LoadFunctions());

        const auto instance = GetInstance();

        DAWN_TRY_ASSIGN(mFactory,
                        CreateFactory(mFunctions.get(), instance->GetBackendValidationLevel(),
                                      instance->IsBeginCaptureOnStartupEnabled()));

        return {};
    }

    ComPtr<IDXGIFactory4> Backend::GetFactory() const {
        return mFactory;
    }

    MaybeError Backend::EnsureDxcLibrary() {
        if (mDxcLibrary == nullptr) {
            DAWN_TRY(CheckHRESULT(
                mFunctions->dxcCreateInstance(CLSID_DxcLibrary, IID_PPV_ARGS(&mDxcLibrary)),
                "DXC create library"));
            ASSERT(mDxcLibrary != nullptr);
        }
        return {};
    }

    MaybeError Backend::EnsureDxcCompiler() {
        if (mDxcCompiler == nullptr) {
            DAWN_TRY(CheckHRESULT(
                mFunctions->dxcCreateInstance(CLSID_DxcCompiler, IID_PPV_ARGS(&mDxcCompiler)),
                "DXC create compiler"));
            ASSERT(mDxcCompiler != nullptr);
        }
        return {};
    }

    MaybeError Backend::EnsureDxcValidator() {
        if (mDxcValidator == nullptr) {
            DAWN_TRY(CheckHRESULT(
                mFunctions->dxcCreateInstance(CLSID_DxcValidator, IID_PPV_ARGS(&mDxcValidator)),
                "DXC create validator"));
            ASSERT(mDxcValidator != nullptr);
        }
        return {};
    }

    ComPtr<IDxcLibrary> Backend::GetDxcLibrary() const {
        ASSERT(mDxcLibrary != nullptr);
        return mDxcLibrary;
    }

    ComPtr<IDxcCompiler> Backend::GetDxcCompiler() const {
        ASSERT(mDxcCompiler != nullptr);
        return mDxcCompiler;
    }

    ComPtr<IDxcValidator> Backend::GetDxcValidator() const {
        ASSERT(mDxcValidator != nullptr);
        return mDxcValidator;
    }

    const PlatformFunctions* Backend::GetFunctions() const {
        return mFunctions.get();
    }

    std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() {
        AdapterDiscoveryOptions options;
        auto result = DiscoverAdapters(&options);
        if (result.IsError()) {
            GetInstance()->ConsumedError(result.AcquireError());
            return {};
        }
        return result.AcquireSuccess();
    }

    ResultOrError<std::vector<std::unique_ptr<AdapterBase>>> Backend::DiscoverAdapters(
        const AdapterDiscoveryOptionsBase* optionsBase) {
        ASSERT(optionsBase->backendType == WGPUBackendType_D3D12);
        const AdapterDiscoveryOptions* options =
            static_cast<const AdapterDiscoveryOptions*>(optionsBase);

        std::vector<std::unique_ptr<AdapterBase>> adapters;
        if (options->dxgiAdapter != nullptr) {
            // |dxgiAdapter| was provided. Discover just that adapter.
            std::unique_ptr<AdapterBase> adapter;
            DAWN_TRY_ASSIGN(adapter, CreateAdapterFromIDXGIAdapter(this, options->dxgiAdapter));
            adapters.push_back(std::move(adapter));
            return std::move(adapters);
        }

        // Enumerate and discover all available adapters.
        for (uint32_t adapterIndex = 0;; ++adapterIndex) {
            ComPtr<IDXGIAdapter1> dxgiAdapter = nullptr;
            if (mFactory->EnumAdapters1(adapterIndex, &dxgiAdapter) == DXGI_ERROR_NOT_FOUND) {
                break;  // No more adapters to enumerate.
            }

            ASSERT(dxgiAdapter != nullptr);
            ResultOrError<std::unique_ptr<AdapterBase>> adapter =
                CreateAdapterFromIDXGIAdapter(this, dxgiAdapter);
            if (adapter.IsError()) {
                GetInstance()->ConsumedError(adapter.AcquireError());
                continue;
            }

            adapters.push_back(std::move(adapter.AcquireSuccess()));
        }

        return adapters;
    }

    BackendConnection* Connect(InstanceBase* instance) {
        Backend* backend = new Backend(instance);

        if (instance->ConsumedError(backend->Initialize())) {
            delete backend;
            return nullptr;
        }

        return backend;
    }

}  // namespace dawn::native::d3d12
