dawn.node: Make GPUDevice.lost [SameObject]
Previously a new promise was created and new promises were never resolved on creation, only on loss/destruction of the device. This made the following code wait forever: device.destroy(); await device.lost(); Bug: dawn:1123 Change-Id: I1e31cf9ccd466672eed4cad464c38cb9f8b3d724 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/85362 Reviewed-by: Ben Clayton <bclayton@google.com> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
ecc3fe6f0f
commit
63fe6e11cd
|
@ -77,7 +77,10 @@ namespace wgpu::binding {
|
|||
// wgpu::bindings::GPUDevice
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
GPUDevice::GPUDevice(Napi::Env env, wgpu::Device device)
|
||||
: env_(env), device_(device), async_(std::make_shared<AsyncRunner>(env, device)) {
|
||||
: env_(env),
|
||||
device_(device),
|
||||
async_(std::make_shared<AsyncRunner>(env, device)),
|
||||
lost_promise_(env, PROMISE_INFO) {
|
||||
device_.SetLoggingCallback(
|
||||
[](WGPULoggingType type, char const* message, void* userdata) {
|
||||
std::cout << type << ": " << message << std::endl;
|
||||
|
@ -102,8 +105,8 @@ namespace wgpu::binding {
|
|||
break;
|
||||
}
|
||||
auto* self = static_cast<GPUDevice*>(userdata);
|
||||
for (auto promise : self->lost_promises_) {
|
||||
promise.Resolve(
|
||||
if (self->lost_promise_.GetState() == interop::PromiseState::Pending) {
|
||||
self->lost_promise_.Resolve(
|
||||
interop::GPUDeviceLostInfo::Create<DeviceLostInfo>(self->env_, r, message));
|
||||
}
|
||||
},
|
||||
|
@ -139,12 +142,11 @@ namespace wgpu::binding {
|
|||
}
|
||||
|
||||
void GPUDevice::destroy(Napi::Env env) {
|
||||
for (auto promise : lost_promises_) {
|
||||
promise.Resolve(interop::GPUDeviceLostInfo::Create<DeviceLostInfo>(
|
||||
if (lost_promise_.GetState() == interop::PromiseState::Pending) {
|
||||
lost_promise_.Resolve(interop::GPUDeviceLostInfo::Create<DeviceLostInfo>(
|
||||
env_, interop::GPUDeviceLostReason::kDestroyed, "device was destroyed"));
|
||||
}
|
||||
lost_promises_.clear();
|
||||
device_.Release();
|
||||
device_.Destroy();
|
||||
}
|
||||
|
||||
interop::Interface<interop::GPUBuffer> GPUDevice::createBuffer(
|
||||
|
@ -422,10 +424,7 @@ namespace wgpu::binding {
|
|||
|
||||
interop::Promise<interop::Interface<interop::GPUDeviceLostInfo>> GPUDevice::getLost(
|
||||
Napi::Env env) {
|
||||
auto promise =
|
||||
interop::Promise<interop::Interface<interop::GPUDeviceLostInfo>>(env, PROMISE_INFO);
|
||||
lost_promises_.emplace_back(promise);
|
||||
return promise;
|
||||
return lost_promise_;
|
||||
}
|
||||
|
||||
void GPUDevice::pushErrorScope(Napi::Env env, interop::GPUErrorFilter filter) {
|
||||
|
|
|
@ -104,8 +104,10 @@ namespace wgpu::binding {
|
|||
Napi::Env env_;
|
||||
wgpu::Device device_;
|
||||
std::shared_ptr<AsyncRunner> async_;
|
||||
std::vector<interop::Promise<interop::Interface<interop::GPUDeviceLostInfo>>>
|
||||
lost_promises_;
|
||||
|
||||
// This promise's JS object lives as long as the device because it is stored in .lost
|
||||
// of the wrapper JS object.
|
||||
interop::Promise<interop::Interface<interop::GPUDeviceLostInfo>> lost_promise_;
|
||||
};
|
||||
|
||||
} // namespace wgpu::binding
|
||||
|
|
|
@ -168,66 +168,70 @@ namespace wgpu::interop {
|
|||
int line = 0;
|
||||
};
|
||||
|
||||
enum class PromiseState {
|
||||
Pending,
|
||||
Resolved,
|
||||
Rejected,
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
// Base class for Promise<T> specializations.
|
||||
class PromiseBase {
|
||||
public:
|
||||
// Implicit conversion operators to Napi promises.
|
||||
inline operator napi_value() const {
|
||||
return state->deferred.Promise();
|
||||
return state_->deferred.Promise();
|
||||
}
|
||||
inline operator Napi::Value() const {
|
||||
return state->deferred.Promise();
|
||||
return state_->deferred.Promise();
|
||||
}
|
||||
inline operator Napi::Promise() const {
|
||||
return state->deferred.Promise();
|
||||
return state_->deferred.Promise();
|
||||
}
|
||||
|
||||
// Reject() rejects the promise with the given failure value.
|
||||
void Reject(Napi::Value value) const {
|
||||
state->deferred.Reject(value);
|
||||
state->resolved_or_rejected = true;
|
||||
state_->deferred.Reject(value);
|
||||
state_->state = PromiseState::Rejected;
|
||||
}
|
||||
void Reject(Napi::Error err) const {
|
||||
Reject(err.Value());
|
||||
}
|
||||
void Reject(std::string err) const {
|
||||
Reject(Napi::Error::New(state->deferred.Env(), err));
|
||||
Reject(Napi::Error::New(state_->deferred.Env(), err));
|
||||
}
|
||||
|
||||
PromiseState GetState() const {
|
||||
return state_->state;
|
||||
}
|
||||
|
||||
protected:
|
||||
void Resolve(Napi::Value value) const {
|
||||
state->deferred.Resolve(value);
|
||||
state->resolved_or_rejected = true;
|
||||
state_->deferred.Resolve(value);
|
||||
state_->state = PromiseState::Resolved;
|
||||
}
|
||||
|
||||
struct State {
|
||||
Napi::Promise::Deferred deferred;
|
||||
PromiseInfo info;
|
||||
bool resolved_or_rejected = false;
|
||||
PromiseState state = PromiseState::Pending;
|
||||
};
|
||||
|
||||
PromiseBase(Napi::Env env, const PromiseInfo& info)
|
||||
: state(new State{Napi::Promise::Deferred::New(env), info}) {
|
||||
state->deferred.Promise().AddFinalizer(
|
||||
: state_(new State{Napi::Promise::Deferred::New(env), info}) {
|
||||
state_->deferred.Promise().AddFinalizer(
|
||||
[](Napi::Env, State* state) {
|
||||
// TODO(https://github.com/gpuweb/cts/issues/784):
|
||||
// Devices are never destroyed, so we always end up
|
||||
// leaking the Device.lost promise. Enable this once
|
||||
// fixed.
|
||||
if ((false)) {
|
||||
if (!state->resolved_or_rejected) {
|
||||
::wgpu::utils::Fatal("Promise not resolved or rejected",
|
||||
state->info.file, state->info.line,
|
||||
state->info.function);
|
||||
}
|
||||
if (state->state == PromiseState::Pending) {
|
||||
::wgpu::utils::Fatal("Promise not resolved or rejected",
|
||||
state->info.file, state->info.line,
|
||||
state->info.function);
|
||||
}
|
||||
delete state;
|
||||
},
|
||||
state);
|
||||
state_);
|
||||
}
|
||||
|
||||
State* const state;
|
||||
State* const state_;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
|
@ -242,7 +246,7 @@ namespace wgpu::interop {
|
|||
|
||||
// Resolve() fulfills the promise with the given value.
|
||||
void Resolve(T&& value) const {
|
||||
PromiseBase::Resolve(ToJS(state->deferred.Env(), std::forward<T>(value)));
|
||||
PromiseBase::Resolve(ToJS(state_->deferred.Env(), std::forward<T>(value)));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -256,7 +260,7 @@ namespace wgpu::interop {
|
|||
|
||||
// Resolve() fulfills the promise.
|
||||
void Resolve() const {
|
||||
PromiseBase::Resolve(state->deferred.Env().Undefined());
|
||||
PromiseBase::Resolve(state_->deferred.Env().Undefined());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -142,6 +142,9 @@ func run() error {
|
|||
|
||||
// simplify the definitions in the WebIDL before passing this to the template
|
||||
idl, declarations := simplify(idl)
|
||||
|
||||
// Patch the IDL for the differences we need compared to the upstream IDL.
|
||||
patch(idl, declarations)
|
||||
g.declarations = declarations
|
||||
|
||||
// Write the file header
|
||||
|
@ -369,6 +372,17 @@ func (s *simplifier) visitType(t ast.Type) {
|
|||
}
|
||||
}
|
||||
|
||||
func patch(idl *ast.File, decl declarations) {
|
||||
// Add [SameObject] to GPUDevice.lost
|
||||
for _, member := range decl["GPUDevice"].(*ast.Interface).Members {
|
||||
if m := member.(*ast.Member); m != nil && m.Name == "lost" {
|
||||
annotation := &ast.Annotation{}
|
||||
annotation.Name = "SameObject"
|
||||
m.Annotations = append(m.Annotations, annotation)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// generator holds the template generator state
|
||||
type generator struct {
|
||||
// the root template
|
||||
|
|
Loading…
Reference in New Issue