1 /*
2 * Copyright 2022 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/graphite/dawn/DawnQueueManager.h"
9
10 #include "src/gpu/graphite/dawn/DawnAsyncWait.h"
11 #include "src/gpu/graphite/dawn/DawnCommandBuffer.h"
12 #include "src/gpu/graphite/dawn/DawnResourceProvider.h"
13 #include "src/gpu/graphite/dawn/DawnSharedContext.h"
14 #include "src/gpu/graphite/dawn/DawnUtilsPriv.h"
15
16 namespace skgpu::graphite {
17 namespace {
18 #if defined(__EMSCRIPTEN__)
19 // GpuWorkSubmission with AsyncWait. This is useful for wasm where wgpu::Future
20 // is not available yet.
21 class DawnWorkSubmissionWithAsyncWait final : public GpuWorkSubmission {
22 public:
23 DawnWorkSubmissionWithAsyncWait(std::unique_ptr<CommandBuffer> cmdBuffer,
24 DawnQueueManager* queueManager,
25 const DawnSharedContext* sharedContext);
26
27 private:
28 bool onIsFinished(const SharedContext* sharedContext) override;
29 void onWaitUntilFinished(const SharedContext* sharedContext) override;
30
31 DawnAsyncWait fAsyncWait;
32 };
33
DawnWorkSubmissionWithAsyncWait(std::unique_ptr<CommandBuffer> cmdBuffer,DawnQueueManager * queueManager,const DawnSharedContext * sharedContext)34 DawnWorkSubmissionWithAsyncWait::DawnWorkSubmissionWithAsyncWait(
35 std::unique_ptr<CommandBuffer> cmdBuffer,
36 DawnQueueManager* queueManager,
37 const DawnSharedContext* sharedContext)
38 : GpuWorkSubmission(std::move(cmdBuffer), queueManager), fAsyncWait(sharedContext) {
39 queueManager->dawnQueue().OnSubmittedWorkDone(
40 // This is parameter is being removed:
41 // https://github.com/webgpu-native/webgpu-headers/issues/130
42 /*signalValue=*/0,
43 [](WGPUQueueWorkDoneStatus, void* userData) {
44 auto asyncWaitPtr = static_cast<DawnAsyncWait*>(userData);
45 asyncWaitPtr->signal();
46 },
47 &fAsyncWait);
48 }
49
onIsFinished(const SharedContext *)50 bool DawnWorkSubmissionWithAsyncWait::onIsFinished(const SharedContext*) {
51 return fAsyncWait.yieldAndCheck();
52 }
53
onWaitUntilFinished(const SharedContext *)54 void DawnWorkSubmissionWithAsyncWait::onWaitUntilFinished(const SharedContext*) {
55 fAsyncWait.busyWait();
56 }
57
58 #else
59
60 // The version with wgpu::Future. This is not available in wasm yet so we have
61 // to guard behind #if
62 class DawnWorkSubmissionWithFuture final : public GpuWorkSubmission {
63 public:
64 DawnWorkSubmissionWithFuture(std::unique_ptr<CommandBuffer> cmdBuffer,
65 DawnQueueManager* queueManager);
66
67 private:
68 bool onIsFinished(const SharedContext* sharedContext) override;
69 void onWaitUntilFinished(const SharedContext* sharedContext) override;
70
71 wgpu::Future fSubmittedWorkDoneFuture;
72 };
73
74 DawnWorkSubmissionWithFuture::DawnWorkSubmissionWithFuture(std::unique_ptr<CommandBuffer> cmdBuffer,
75 DawnQueueManager* queueManager)
76 : GpuWorkSubmission(std::move(cmdBuffer), queueManager) {
77 fSubmittedWorkDoneFuture = queueManager->dawnQueue().OnSubmittedWorkDone(
78 wgpu::CallbackMode::WaitAnyOnly, [](wgpu::QueueWorkDoneStatus) {});
79 }
80
81 bool DawnWorkSubmissionWithFuture::onIsFinished(const SharedContext* sharedContext) {
82 wgpu::FutureWaitInfo waitInfo{};
83 waitInfo.future = fSubmittedWorkDoneFuture;
84 const auto& instance = static_cast<const DawnSharedContext*>(sharedContext)
85 ->device()
86 .GetAdapter()
87 .GetInstance();
88 if (instance.WaitAny(1, &waitInfo, /*timeoutNS=*/0) != wgpu::WaitStatus::Success) {
89 return false;
90 }
91
92 return waitInfo.completed;
93 }
94
95 void DawnWorkSubmissionWithFuture::onWaitUntilFinished(const SharedContext* sharedContext) {
96 wgpu::FutureWaitInfo waitInfo{};
97 waitInfo.future = fSubmittedWorkDoneFuture;
98 const auto& instance = static_cast<const DawnSharedContext*>(sharedContext)
99 ->device()
100 .GetAdapter()
101 .GetInstance();
102 [[maybe_unused]] auto status =
103 instance.WaitAny(1, &waitInfo, /*timeoutNS=*/std::numeric_limits<uint64_t>::max());
104 SkASSERT(status == wgpu::WaitStatus::Success);
105 SkASSERT(waitInfo.completed);
106 }
107 #endif // defined(__EMSCRIPTEN__)
108 } // namespace
109
DawnQueueManager(wgpu::Queue queue,const SharedContext * sharedContext)110 DawnQueueManager::DawnQueueManager(wgpu::Queue queue, const SharedContext* sharedContext)
111 : QueueManager(sharedContext), fQueue(std::move(queue)) {}
112
tick() const113 void DawnQueueManager::tick() const { this->dawnSharedContext()->tick(); }
114
dawnSharedContext() const115 const DawnSharedContext* DawnQueueManager::dawnSharedContext() const {
116 return static_cast<const DawnSharedContext*>(fSharedContext);
117 }
118
getNewCommandBuffer(ResourceProvider * resourceProvider,Protected)119 std::unique_ptr<CommandBuffer> DawnQueueManager::getNewCommandBuffer(
120 ResourceProvider* resourceProvider, Protected) {
121 return DawnCommandBuffer::Make(dawnSharedContext(),
122 static_cast<DawnResourceProvider*>(resourceProvider));
123 }
124
onSubmitToGpu()125 QueueManager::OutstandingSubmission DawnQueueManager::onSubmitToGpu() {
126 SkASSERT(fCurrentCommandBuffer);
127 DawnCommandBuffer* dawnCmdBuffer = static_cast<DawnCommandBuffer*>(fCurrentCommandBuffer.get());
128 auto wgpuCmdBuffer = dawnCmdBuffer->finishEncoding();
129 if (!wgpuCmdBuffer) {
130 fCurrentCommandBuffer->callFinishedProcs(/*success=*/false);
131 return nullptr;
132 }
133
134 fQueue.Submit(/*commandCount=*/1, &wgpuCmdBuffer);
135
136 #if defined(__EMSCRIPTEN__)
137 return std::make_unique<DawnWorkSubmissionWithAsyncWait>(
138 std::move(fCurrentCommandBuffer), this, dawnSharedContext());
139 #else
140 return std::make_unique<DawnWorkSubmissionWithFuture>(std::move(fCurrentCommandBuffer), this);
141 #endif
142 }
143
144 #if defined(GPU_TEST_UTILS)
startCapture()145 void DawnQueueManager::startCapture() {
146 // TODO: Dawn doesn't have capturing feature yet.
147 }
148
stopCapture()149 void DawnQueueManager::stopCapture() {
150 // TODO: Dawn doesn't have capturing feature yet.
151 }
152 #endif
153
154 } // namespace skgpu::graphite
155