// 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 { namespace 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
