blob: ec5ef6cb63400b8fdaa538fd497200fd96a4f5ee [file] [log] [blame]
/*
* Copyright 2022 Google LLC
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "src/gpu/graphite/dawn/DawnQueueManager.h"
#include "src/gpu/graphite/dawn/DawnAsyncWait.h"
#include "src/gpu/graphite/dawn/DawnCommandBuffer.h"
#include "src/gpu/graphite/dawn/DawnResourceProvider.h"
#include "src/gpu/graphite/dawn/DawnSharedContext.h"
#include "src/gpu/graphite/dawn/DawnUtilsPriv.h"
namespace skgpu::graphite {
namespace {
// GpuWorkSubmission with AsyncWait. This is useful for wasm where wgpu::Future
// is not available yet.
class [[maybe_unused]] DawnWorkSubmissionWithAsyncWait final : public GpuWorkSubmission {
public:
DawnWorkSubmissionWithAsyncWait(std::unique_ptr<CommandBuffer> cmdBuffer,
DawnQueueManager* queueManager,
const DawnSharedContext* sharedContext);
private:
bool onIsFinished(const SharedContext* sharedContext) override;
void onWaitUntilFinished(const SharedContext* sharedContext) override;
DawnAsyncWait fAsyncWait;
};
DawnWorkSubmissionWithAsyncWait::DawnWorkSubmissionWithAsyncWait(
std::unique_ptr<CommandBuffer> cmdBuffer,
DawnQueueManager* queueManager,
const DawnSharedContext* sharedContext)
: GpuWorkSubmission(std::move(cmdBuffer), queueManager), fAsyncWait(sharedContext) {
queueManager->dawnQueue().OnSubmittedWorkDone(
#if defined(__EMSCRIPTEN__)
// This is parameter is being removed:
// https://github.com/webgpu-native/webgpu-headers/issues/130
/*signalValue=*/0,
#endif
[](WGPUQueueWorkDoneStatus, void* userData) {
auto asyncWaitPtr = static_cast<DawnAsyncWait*>(userData);
asyncWaitPtr->signal();
},
&fAsyncWait);
}
bool DawnWorkSubmissionWithAsyncWait::onIsFinished(const SharedContext*) {
return fAsyncWait.yieldAndCheck();
}
void DawnWorkSubmissionWithAsyncWait::onWaitUntilFinished(const SharedContext*) {
fAsyncWait.busyWait();
}
#if !defined(__EMSCRIPTEN__)
// The version with wgpu::Future. This is not available in wasm yet so we have
// to guard behind #if
class DawnWorkSubmissionWithFuture final : public GpuWorkSubmission {
public:
DawnWorkSubmissionWithFuture(std::unique_ptr<CommandBuffer> cmdBuffer,
DawnQueueManager* queueManager);
private:
bool onIsFinished(const SharedContext* sharedContext) override;
void onWaitUntilFinished(const SharedContext* sharedContext) override;
wgpu::Future fSubmittedWorkDoneFuture;
};
DawnWorkSubmissionWithFuture::DawnWorkSubmissionWithFuture(std::unique_ptr<CommandBuffer> cmdBuffer,
DawnQueueManager* queueManager)
: GpuWorkSubmission(std::move(cmdBuffer), queueManager) {
fSubmittedWorkDoneFuture = queueManager->dawnQueue().OnSubmittedWorkDone(
wgpu::CallbackMode::WaitAnyOnly, [](wgpu::QueueWorkDoneStatus) {});
}
bool DawnWorkSubmissionWithFuture::onIsFinished(const SharedContext* sharedContext) {
wgpu::FutureWaitInfo waitInfo{};
waitInfo.future = fSubmittedWorkDoneFuture;
const auto& instance = static_cast<const DawnSharedContext*>(sharedContext)
->device()
.GetAdapter()
.GetInstance();
if (instance.WaitAny(1, &waitInfo, /*timeoutNS=*/0) != wgpu::WaitStatus::Success) {
return false;
}
return waitInfo.completed;
}
void DawnWorkSubmissionWithFuture::onWaitUntilFinished(const SharedContext* sharedContext) {
wgpu::FutureWaitInfo waitInfo{};
waitInfo.future = fSubmittedWorkDoneFuture;
const auto& instance = static_cast<const DawnSharedContext*>(sharedContext)
->device()
.GetAdapter()
.GetInstance();
[[maybe_unused]] auto status =
instance.WaitAny(1, &waitInfo, /*timeoutNS=*/std::numeric_limits<uint64_t>::max());
SkASSERT(status == wgpu::WaitStatus::Success);
SkASSERT(waitInfo.completed);
}
#endif // !defined(__EMSCRIPTEN__)
} // namespace
DawnQueueManager::DawnQueueManager(wgpu::Queue queue, const SharedContext* sharedContext)
: QueueManager(sharedContext), fQueue(std::move(queue)) {}
void DawnQueueManager::tick() const { this->dawnSharedContext()->tick(); }
const DawnSharedContext* DawnQueueManager::dawnSharedContext() const {
return static_cast<const DawnSharedContext*>(fSharedContext);
}
std::unique_ptr<CommandBuffer> DawnQueueManager::getNewCommandBuffer(
ResourceProvider* resourceProvider) {
return DawnCommandBuffer::Make(dawnSharedContext(),
static_cast<DawnResourceProvider*>(resourceProvider));
}
QueueManager::OutstandingSubmission DawnQueueManager::onSubmitToGpu() {
SkASSERT(fCurrentCommandBuffer);
DawnCommandBuffer* dawnCmdBuffer = static_cast<DawnCommandBuffer*>(fCurrentCommandBuffer.get());
auto wgpuCmdBuffer = dawnCmdBuffer->finishEncoding();
if (!wgpuCmdBuffer) {
fCurrentCommandBuffer->callFinishedProcs(/*success=*/false);
return nullptr;
}
fQueue.Submit(/*commandCount=*/1, &wgpuCmdBuffer);
#if defined(__EMSCRIPTEN__)
return std::make_unique<DawnWorkSubmissionWithAsyncWait>(
std::move(fCurrentCommandBuffer), this, dawnSharedContext());
#else
return std::make_unique<DawnWorkSubmissionWithFuture>(std::move(fCurrentCommandBuffer), this);
#endif
}
#if defined(GRAPHITE_TEST_UTILS)
void DawnQueueManager::startCapture() {
// TODO: Dawn doesn't have capturing feature yet.
}
void DawnQueueManager::stopCapture() {
// TODO: Dawn doesn't have capturing feature yet.
}
#endif
} // namespace skgpu::graphite