// 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/CommandRecordingContext.h"
#include "dawn_native/d3d12/CommandAllocatorManager.h"
#include "dawn_native/d3d12/D3D12Error.h"
#include "dawn_native/d3d12/DeviceD3D12.h"
#include "dawn_native/d3d12/HeapD3D12.h"
#include "dawn_native/d3d12/ResidencyManagerD3D12.h"

namespace dawn::native::d3d12 {

    void CommandRecordingContext::AddToSharedTextureList(Texture* texture) {
        ASSERT(IsOpen());
        mSharedTextures.insert(texture);
    }

    MaybeError CommandRecordingContext::Open(ID3D12Device* d3d12Device,
                                             CommandAllocatorManager* commandAllocationManager) {
        ASSERT(!IsOpen());
        ID3D12CommandAllocator* commandAllocator;
        DAWN_TRY_ASSIGN(commandAllocator, commandAllocationManager->ReserveCommandAllocator());
        if (mD3d12CommandList != nullptr) {
            MaybeError error = CheckHRESULT(mD3d12CommandList->Reset(commandAllocator, nullptr),
                                            "D3D12 resetting command list");
            if (error.IsError()) {
                mD3d12CommandList.Reset();
                DAWN_TRY(std::move(error));
            }
        } else {
            ComPtr<ID3D12GraphicsCommandList> d3d12GraphicsCommandList;
            DAWN_TRY(CheckHRESULT(
                d3d12Device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAllocator,
                                               nullptr, IID_PPV_ARGS(&d3d12GraphicsCommandList)),
                "D3D12 creating direct command list"));
            mD3d12CommandList = std::move(d3d12GraphicsCommandList);
            // Store a cast to ID3D12GraphicsCommandList4. This is required to use the D3D12 render
            // pass APIs introduced in Windows build 1809.
            mD3d12CommandList.As(&mD3d12CommandList4);
        }

        mIsOpen = true;

        return {};
    }

    MaybeError CommandRecordingContext::ExecuteCommandList(Device* device) {
        if (IsOpen()) {
            // Shared textures must be transitioned to common state after the last usage in order
            // for them to be used by other APIs like D3D11. We ensure this by transitioning to the
            // common state right before command list submission. TransitionUsageNow itself ensures
            // no unnecessary transitions happen if the resources is already in the common state.
            for (Texture* texture : mSharedTextures) {
                DAWN_TRY(texture->AcquireKeyedMutex());
                texture->TrackAllUsageAndTransitionNow(this, D3D12_RESOURCE_STATE_COMMON);
            }

            MaybeError error =
                CheckHRESULT(mD3d12CommandList->Close(), "D3D12 closing pending command list");
            if (error.IsError()) {
                Release();
                DAWN_TRY(std::move(error));
            }
            DAWN_TRY(device->GetResidencyManager()->EnsureHeapsAreResident(
                mHeapsPendingUsage.data(), mHeapsPendingUsage.size()));

            ID3D12CommandList* d3d12CommandList = GetCommandList();
            device->GetCommandQueue()->ExecuteCommandLists(1, &d3d12CommandList);

            for (Texture* texture : mSharedTextures) {
                texture->ReleaseKeyedMutex();
            }

            mIsOpen = false;
            mSharedTextures.clear();
            mHeapsPendingUsage.clear();
        }
        return {};
    }

    void CommandRecordingContext::TrackHeapUsage(Heap* heap, ExecutionSerial serial) {
        // Before tracking the heap, check the last serial it was recorded on to ensure we aren't
        // tracking it more than once.
        if (heap->GetLastUsage() < serial) {
            heap->SetLastUsage(serial);
            mHeapsPendingUsage.push_back(heap);
        }
    }

    ID3D12GraphicsCommandList* CommandRecordingContext::GetCommandList() const {
        ASSERT(mD3d12CommandList != nullptr);
        ASSERT(IsOpen());
        return mD3d12CommandList.Get();
    }

    // This function will fail on Windows versions prior to 1809. Support must be queried through
    // the device before calling.
    ID3D12GraphicsCommandList4* CommandRecordingContext::GetCommandList4() const {
        ASSERT(IsOpen());
        ASSERT(mD3d12CommandList != nullptr);
        return mD3d12CommandList4.Get();
    }

    void CommandRecordingContext::Release() {
        mD3d12CommandList.Reset();
        mD3d12CommandList4.Reset();
        mIsOpen = false;
        mSharedTextures.clear();
        mHeapsPendingUsage.clear();
        mTempBuffers.clear();
    }

    bool CommandRecordingContext::IsOpen() const {
        return mIsOpen;
    }

    void CommandRecordingContext::AddToTempBuffers(Ref<Buffer> tempBuffer) {
        mTempBuffers.emplace_back(tempBuffer);
    }

}  // namespace dawn::native::d3d12
