@@ -394,22 +394,36 @@ class DXFence : public offloadtest::Fence {
394394
395395class DXQueue : public offloadtest ::Queue {
396396public:
397+ using Queue::submit;
398+
397399 ComPtr<ID3D12CommandQueue> Queue;
400+ std::unique_ptr<DXFence> SubmitFence;
401+ uint64_t FenceCounter = 0 ;
398402
399- DXQueue (ComPtr<ID3D12CommandQueue> Queue) : Queue(Queue) {}
400- virtual ~DXQueue () {}
403+ DXQueue (ComPtr<ID3D12CommandQueue> Queue,
404+ std::unique_ptr<DXFence> SubmitFence)
405+ : Queue(Queue), SubmitFence(std::move(SubmitFence)) {}
406+ DXQueue (DXQueue &&) = default ;
407+ ~DXQueue () override {}
401408
402409 static llvm::Expected<DXQueue>
403410 createGraphicsQueue (ComPtr<ID3D12Device> Device) {
404411 const D3D12_COMMAND_QUEUE_DESC Desc = {D3D12_COMMAND_LIST_TYPE_DIRECT, 0 ,
405412 D3D12_COMMAND_QUEUE_FLAG_NONE, 0 };
406- ComPtr<ID3D12CommandQueue> Queue ;
407- if (auto Err =
408- HR::toError ( Device->CreateCommandQueue (&Desc, IID_PPV_ARGS (&Queue )),
409- " Failed to create command queue." ))
413+ ComPtr<ID3D12CommandQueue> CmdQueue ;
414+ if (auto Err = HR::toError (
415+ Device->CreateCommandQueue (&Desc, IID_PPV_ARGS (&CmdQueue )),
416+ " Failed to create command queue." ))
410417 return Err;
411- return DXQueue (Queue);
418+ auto FenceOrErr = DXFence::create (Device.Get (), " QueueSubmitFence" );
419+ if (!FenceOrErr)
420+ return FenceOrErr.takeError ();
421+ return DXQueue (CmdQueue, std::move (*FenceOrErr));
412422 }
423+
424+ llvm::Error
425+ submit (llvm::SmallVector<std::unique_ptr<offloadtest::CommandBuffer>> CBs)
426+ override ;
413427};
414428
415429class DXCommandBuffer : public offloadtest ::CommandBuffer {
@@ -444,6 +458,42 @@ class DXCommandBuffer : public offloadtest::CommandBuffer {
444458 DXCommandBuffer () : CommandBuffer(GPUAPI::DirectX) {}
445459};
446460
461+ llvm::Error DXQueue::submit (
462+ llvm::SmallVector<std::unique_ptr<offloadtest::CommandBuffer>> CBs) {
463+ llvm::SmallVector<ID3D12CommandList *> CmdLists;
464+ CmdLists.reserve (CBs.size ());
465+
466+ // Wait on the previous submit's fence value before executing this batch,
467+ // so that back-to-back submits don't overlap on the GPU. Skip on first
468+ // submit since Wait(fence, 0) triggers a D3D12 validation warning.
469+ if (FenceCounter > 0 )
470+ if (auto Err =
471+ HR::toError (Queue->Wait (SubmitFence->Fence .Get (), FenceCounter),
472+ " Failed to wait on previous submit." ))
473+ return Err;
474+
475+ for (auto &CB : CBs) {
476+ auto &DCB = *llvm::cast<DXCommandBuffer>(CB.get ());
477+ if (auto Err =
478+ HR::toError (DCB.CmdList ->Close (), " Failed to close command list." ))
479+ return Err;
480+ CmdLists.push_back (DCB.CmdList .Get ());
481+ }
482+
483+ Queue->ExecuteCommandLists (CmdLists.size (), CmdLists.data ());
484+
485+ const uint64_t CurrentCounter = ++FenceCounter;
486+ if (auto Err =
487+ HR::toError (Queue->Signal (SubmitFence->Fence .Get (), CurrentCounter),
488+ " Failed to add signal." ))
489+ return Err;
490+
491+ // TODO: Return a Fence+value with keepalive lists instead of blocking here.
492+ if (auto Err = SubmitFence->waitForCompletion (CurrentCounter))
493+ return Err;
494+
495+ return llvm::Error::success ();
496+ }
447497class DXDevice : public offloadtest ::Device {
448498private:
449499 ComPtr<IDXCoreAdapter> Adapter;
@@ -491,10 +541,10 @@ class DXDevice : public offloadtest::Device {
491541public:
492542 DXDevice (ComPtr<IDXCoreAdapter> A, ComPtr<ID3D12Device> D, DXQueue Q,
493543 std::string Desc)
494- : Adapter(A), Device(D), GraphicsQueue(Q ) {
544+ : Adapter(A), Device(D), GraphicsQueue(std::move(Q) ) {
495545 Description = Desc;
496546 }
497- DXDevice (const DXDevice &) = default ;
547+ DXDevice (const DXDevice &) = delete ;
498548
499549 ~DXDevice () override = default ;
500550
@@ -646,9 +696,8 @@ class DXDevice : public offloadtest::Device {
646696 auto GraphicsQueueOrErr = DXQueue::createGraphicsQueue (Device);
647697 if (!GraphicsQueueOrErr)
648698 return GraphicsQueueOrErr.takeError ();
649- const DXQueue GraphicsQueue = *GraphicsQueueOrErr;
650-
651- return std::make_unique<DXDevice>(Adapter, Device, std::move (GraphicsQueue),
699+ return std::make_unique<DXDevice>(Adapter, Device,
700+ std::move (*GraphicsQueueOrErr),
652701 std::string (DescVec.data ()));
653702 }
654703
@@ -897,7 +946,20 @@ class DXDevice : public offloadtest::Device {
897946 Buffer.Get (), 1 , &StartCoord, &RegionSize, Heap.Get (), 1 , &RangeFlag,
898947 &HeapRangeStartOffset, &RangeTileCount, D3D12_TILE_MAPPING_FLAG_NONE);
899948
900- return waitForSignal (IS);
949+ // Synchronize after UpdateTileMappings, which is a queue operation (not
950+ // recorded into a command list). This is a hack but it works since this
951+ // is all single threaded code.
952+ // TODO: Replace with a proper fence abstraction.
953+ static uint64_t TileMappingFenceCounter = 0 ;
954+ const uint64_t CurrentCounter = ++TileMappingFenceCounter;
955+ auto *F = static_cast <DXFence *>(IS.Fence .get ());
956+
957+ if (auto Err =
958+ HR::toError (CommandQueue->Signal (F->Fence .Get (), CurrentCounter),
959+ " Failed to add signal." ))
960+ return Err;
961+
962+ return IS.Fence ->waitForCompletion (CurrentCounter);
901963 }
902964
903965 llvm::Expected<ResourceBundle> createSRV (Resource &R, InvocationState &IS) {
@@ -1336,33 +1398,8 @@ class DXDevice : public offloadtest::Device {
13361398 IS.CB ->CmdList ->ResourceBarrier (1 , &Barrier);
13371399 }
13381400
1339- llvm::Error waitForSignal (InvocationState &IS) {
1340- // This is a hack but it works since this is all single threaded code.
1341- static uint64_t FenceCounter = 0 ;
1342- const uint64_t CurrentCounter = FenceCounter + 1 ;
1343- auto *F = static_cast <DXFence *>(IS.Fence .get ());
1344-
1345- if (auto Err = HR::toError (
1346- GraphicsQueue.Queue ->Signal (F->Fence .Get (), CurrentCounter),
1347- " Failed to add signal." ))
1348- return Err;
1349-
1350- if (auto Err = IS.Fence ->waitForCompletion (CurrentCounter))
1351- return Err;
1352-
1353- FenceCounter = CurrentCounter;
1354- return llvm::Error::success ();
1355- }
1356-
13571401 llvm::Error executeCommandList (InvocationState &IS) {
1358- if (auto Err = HR::toError (IS.CB ->CmdList ->Close (),
1359- " Failed to close command list." ))
1360- return Err;
1361-
1362- ID3D12CommandList *const CmdLists[] = {IS.CB ->CmdList .Get ()};
1363- GraphicsQueue.Queue ->ExecuteCommandLists (1 , CmdLists);
1364-
1365- return waitForSignal (IS);
1402+ return GraphicsQueue.submit (std::move (IS.CB ));
13661403 }
13671404
13681405 llvm::Error createComputeCommands (Pipeline &P, InvocationState &IS) {
0 commit comments