123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
- // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
- // SPDX-License-Identifier: MIT
- #pragma once
- #include <Renderer/FatalErrorIfFailed.h>
- /// Holds a number of DirectX operations with logic to wait for completion
- class CommandQueue
- {
- public:
- /// Destructor
- ~CommandQueue()
- {
- WaitUntilFinished();
- if (mFenceEvent != INVALID_HANDLE_VALUE)
- CloseHandle(mFenceEvent);
- }
- /// Initialize the queue
- void Initialize(ID3D12Device *inDevice)
- {
- D3D12_COMMAND_QUEUE_DESC queue_desc = {};
- queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
- queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
- FatalErrorIfFailed(inDevice->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&mCommandQueue)));
- FatalErrorIfFailed(inDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&mCommandAllocator)));
- // Create the command list
- FatalErrorIfFailed(inDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, mCommandAllocator.Get(), nullptr, IID_PPV_ARGS(&mCommandList)));
- // Command lists are created in the recording state, but there is nothing to record yet. The main loop expects it to be closed, so close it now
- FatalErrorIfFailed(mCommandList->Close());
- // Create synchronization object
- FatalErrorIfFailed(inDevice->CreateFence(mFenceValue, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&mFence)));
- // Increment fence value so we don't skip waiting the first time a command list is executed
- mFenceValue++;
- // Create an event handle to use for frame synchronization
- mFenceEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
- if (mFenceEvent == nullptr)
- FatalErrorIfFailed(HRESULT_FROM_WIN32(GetLastError()));
- }
- /// Start the command list (requires waiting until the previous one is finished)
- ID3D12GraphicsCommandList * Start()
- {
- // Reset the allocator
- FatalErrorIfFailed(mCommandAllocator->Reset());
- // Reset the command list
- FatalErrorIfFailed(mCommandList->Reset(mCommandAllocator.Get(), nullptr));
- return mCommandList.Get();
- }
- /// Execute accumulated command list
- void Execute()
- {
- JPH_ASSERT(!mIsExecuting);
- // Close the command list
- FatalErrorIfFailed(mCommandList->Close());
- // Execute the command list
- ID3D12CommandList* ppCommandLists[] = { mCommandList.Get() };
- mCommandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists);
- // Schedule a Signal command in the queue
- FatalErrorIfFailed(mCommandQueue->Signal(mFence.Get(), mFenceValue));
- // Mark that we're executing
- mIsExecuting = true;
- }
- /// After executing, this waits until execution is done
- void WaitUntilFinished()
- {
- // Check if we've been started
- if (mIsExecuting)
- {
- if (mFence->GetCompletedValue() < mFenceValue)
- {
- // Wait until the fence has been processed
- FatalErrorIfFailed(mFence->SetEventOnCompletion(mFenceValue, mFenceEvent));
- WaitForSingleObjectEx(mFenceEvent, INFINITE, FALSE);
- }
- // Increment the fence value
- mFenceValue++;
- // Done executing
- mIsExecuting = false;
- }
- }
- /// Execute and wait for the command list to finish
- void ExecuteAndWait()
- {
- Execute();
- WaitUntilFinished();
- }
- private:
- ComPtr<ID3D12CommandQueue> mCommandQueue; ///< The command queue that will hold command lists
- ComPtr<ID3D12CommandAllocator> mCommandAllocator; ///< Allocator that holds the memory for the commands
- ComPtr<ID3D12GraphicsCommandList> mCommandList; ///< The command list that will hold the render commands / state changes
- HANDLE mFenceEvent = INVALID_HANDLE_VALUE; ///< Fence event, used to wait for rendering to complete
- ComPtr<ID3D12Fence> mFence; ///< Fence object, used to signal the fence event
- UINT64 mFenceValue = 0; ///< Current fence value, each time we need to wait we will signal the fence with this value, wait for it and then increase the value
- bool mIsExecuting = false; ///< If a commandlist is currently executing on the queue
- };
|