-
Notifications
You must be signed in to change notification settings - Fork 31
Implement an abstract Fence type to expose waiting for command buffer completion. #1007
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e1b7c03
42a8718
8453367
ad3b565
5605694
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -293,6 +293,50 @@ class DXBuffer : public offloadtest::Buffer { | |
| : Buffer(Buffer), Name(Name), Desc(Desc), SizeInBytes(SizeInBytes) {} | ||
| }; | ||
|
|
||
| class DXFence : public offloadtest::Fence { | ||
| public: | ||
| std::string Name; | ||
manon-traverse marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ComPtr<ID3D12Fence> Fence; | ||
| HANDLE Event; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs a
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This new code seems to rely on casting to facilitate the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @bogner on a related note, is the CI build-testing the WSL path (Linux with D3D12 headers available)? |
||
|
|
||
| uint64_t getFenceValue() override { return Fence->GetCompletedValue(); } | ||
|
|
||
| llvm::Error waitForCompletion(uint64_t SignalValue) override { | ||
|
|
||
| if (Fence->GetCompletedValue() >= SignalValue) { | ||
| return llvm::Error::success(); | ||
| } | ||
|
|
||
| if (auto Err = HR::toError(Fence->SetEventOnCompletion(SignalValue, Event), | ||
| "Failed to register end event.")) | ||
| return Err; | ||
|
|
||
| #ifdef _WIN32 | ||
| WaitForSingleObject(Event, INFINITE); | ||
| #else // WSL | ||
| pollfd PollEvent; | ||
| PollEvent.fd = (int)Event; | ||
| PollEvent.events = POLLIN; | ||
| PollEvent.revents = 0; | ||
| if (poll(&PollEvent, 1, -1) == -1) | ||
| return llvm::createStringError( | ||
| std::error_code(errno, std::system_category()), strerror(errno)); | ||
| #endif | ||
| return llvm::Error::success(); | ||
| } | ||
|
|
||
| DXFence(ComPtr<ID3D12Fence> Fence, HANDLE Event, llvm::StringRef Name) | ||
| : Fence(Fence), Event(Event), Name(Name) {} | ||
|
|
||
| ~DXFence() { | ||
| #ifdef _WIN32 | ||
| CloseHandle(Event); | ||
| #else // WSL | ||
| close((int)Event); | ||
| #endif | ||
| } | ||
| }; | ||
|
|
||
| class DXQueue : public offloadtest::Queue { | ||
| public: | ||
| ComPtr<ID3D12CommandQueue> Queue; | ||
|
|
@@ -346,12 +390,7 @@ class DXDevice : public offloadtest::Device { | |
| ComPtr<ID3D12PipelineState> PSO; | ||
| ComPtr<ID3D12CommandAllocator> Allocator; | ||
| ComPtr<ID3D12GraphicsCommandList> CmdList; | ||
| ComPtr<ID3D12Fence> Fence; | ||
| #ifdef _WIN32 | ||
| HANDLE Event; | ||
| #else // WSL | ||
| int Event; | ||
| #endif | ||
| std::shared_ptr<offloadtest::Fence> Fence; | ||
manon-traverse marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| // Resources for graphics pipelines. | ||
| ComPtr<ID3D12Resource> RT; | ||
|
|
@@ -378,6 +417,27 @@ class DXDevice : public offloadtest::Device { | |
|
|
||
| Queue &getGraphicsQueue() override { return GraphicsQueue; } | ||
|
|
||
| llvm::Expected<std::unique_ptr<offloadtest::Fence>> | ||
| createFence(llvm::StringRef Name) override { | ||
| ComPtr<ID3D12Fence> Fence; | ||
| if (auto Err = HR::toError( | ||
| Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&Fence)), | ||
| "Failed to create Fence.")) | ||
| return Err; | ||
|
|
||
| #ifdef _WIN32 | ||
| HANDLE Event = CreateEventA(nullptr, false, false, nullptr); | ||
| if (!Event) | ||
| #else // WSL | ||
| int Event = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); | ||
| if (Event == -1) | ||
| #endif | ||
| return llvm::createStringError(std::errc::device_or_resource_busy, | ||
| "Failed to create event."); | ||
|
|
||
| return std::make_unique<DXFence>(Fence, Event, Name); | ||
| } | ||
|
|
||
| llvm::Expected<std::shared_ptr<offloadtest::Buffer>> | ||
| createBuffer(std::string Name, BufferCreateDesc &Desc, | ||
| size_t SizeInBytes) override { | ||
|
|
@@ -1136,56 +1196,20 @@ class DXDevice : public offloadtest::Device { | |
| IS.CmdList->ResourceBarrier(1, &Barrier); | ||
| } | ||
|
|
||
| llvm::Error createEvent(InvocationState &IS) { | ||
| if (auto Err = HR::toError(Device->CreateFence(0, D3D12_FENCE_FLAG_NONE, | ||
| IID_PPV_ARGS(&IS.Fence)), | ||
| "Failed to create fence.")) | ||
| return Err; | ||
| #ifdef _WIN32 | ||
| IS.Event = CreateEventA(nullptr, false, false, nullptr); | ||
| if (!IS.Event) | ||
| #else // WSL | ||
| IS.Event = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK); | ||
| if (IS.Event == -1) | ||
| #endif | ||
| return llvm::createStringError(std::errc::device_or_resource_busy, | ||
| "Failed to create event."); | ||
| return llvm::Error::success(); | ||
| } | ||
|
|
||
| llvm::Error waitForSignal(InvocationState &IS) { | ||
| // This is a hack but it works since this is all single threaded code. | ||
| static uint64_t FenceCounter = 0; | ||
| const uint64_t CurrentCounter = FenceCounter + 1; | ||
| auto *F = static_cast<DXFence *>(IS.Fence.get()); | ||
|
|
||
| if (auto Err = HR::toError( | ||
| GraphicsQueue.Queue->Signal(IS.Fence.Get(), CurrentCounter), | ||
| GraphicsQueue.Queue->Signal(F->Fence.Get(), CurrentCounter), | ||
| "Failed to add signal.")) | ||
| return Err; | ||
|
|
||
| if (IS.Fence->GetCompletedValue() < CurrentCounter) { | ||
| #ifdef _WIN32 | ||
| HANDLE Event = IS.Event; | ||
| #else // WSL | ||
| HANDLE Event = reinterpret_cast<HANDLE>(IS.Event); | ||
| #endif | ||
| if (auto Err = | ||
| HR::toError(IS.Fence->SetEventOnCompletion(CurrentCounter, Event), | ||
| "Failed to register end event.")) | ||
| return Err; | ||
| if (auto Err = IS.Fence->waitForCompletion(CurrentCounter)) | ||
| return Err; | ||
|
|
||
| #ifdef _WIN32 | ||
| WaitForSingleObject(IS.Event, INFINITE); | ||
| #else // WSL | ||
| pollfd PollEvent; | ||
| PollEvent.fd = IS.Event; | ||
| PollEvent.events = POLLIN; | ||
| PollEvent.revents = 0; | ||
| if (poll(&PollEvent, 1, -1) == -1) | ||
| return llvm::createStringError( | ||
| std::error_code(errno, std::system_category()), strerror(errno)); | ||
| #endif | ||
| } | ||
| FenceCounter = CurrentCounter; | ||
| return llvm::Error::success(); | ||
| } | ||
|
|
@@ -1690,9 +1714,10 @@ class DXDevice : public offloadtest::Device { | |
| return Err; | ||
| llvm::outs() << "Command structures created.\n"; | ||
|
|
||
| if (auto Err = createEvent(State)) | ||
| return Err; | ||
| llvm::outs() << "Event prepared.\n"; | ||
| auto FenceOrErr = this->createFence("Fence"); | ||
| if (!FenceOrErr) | ||
| return FenceOrErr.takeError(); | ||
| State.Fence = std::move(*FenceOrErr); | ||
|
|
||
| if (auto Err = createBuffers(P, State)) | ||
| return Err; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.