dawn_node: Add binding/GPUBuffer.cpp

Bug: dawn:1123
Change-Id: I4ba8d69bcd91a1fa0ed43a5ca063c7ff14d7d031
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/64918
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Ben Clayton <bclayton@google.com>
This commit is contained in:
Ben Clayton 2021-09-28 21:51:28 +00:00 committed by Dawn LUCI CQ
parent ea5d768f94
commit 126dc7d20f
2 changed files with 168 additions and 0 deletions

View File

@ -27,6 +27,7 @@ add_library(dawn_node_binding STATIC
"GPUBindGroup.h" "GPUBindGroup.h"
"GPUBindGroupLayout.cpp" "GPUBindGroupLayout.cpp"
"GPUBindGroupLayout.h" "GPUBindGroupLayout.h"
"GPUBuffer.cpp"
"GPUBuffer.h" "GPUBuffer.h"
"GPUCommandBuffer.cpp" "GPUCommandBuffer.cpp"
"GPUCommandBuffer.h" "GPUCommandBuffer.h"

View File

@ -0,0 +1,167 @@
// Copyright 2021 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/dawn_node/binding/GPUBuffer.h"
#include <memory>
#include "src/dawn_node/binding/Converter.h"
#include "src/dawn_node/binding/Errors.h"
#include "src/dawn_node/utils/Debug.h"
namespace wgpu { namespace binding {
////////////////////////////////////////////////////////////////////////////////
// wgpu::bindings::GPUBuffer
// TODO(crbug.com/dawn/1134): We may be doing more validation here than necessary. Once CTS is
// robustly passing, pull out validation and see what / if breaks.
////////////////////////////////////////////////////////////////////////////////
GPUBuffer::GPUBuffer(wgpu::Buffer buffer,
wgpu::BufferDescriptor desc,
wgpu::Device device,
std::shared_ptr<AsyncRunner> async)
: buffer_(std::move(buffer)),
desc_(desc),
device_(std::move(device)),
async_(std::move(async)) {
if (desc.mappedAtCreation) {
state_ = State::MappedAtCreation;
}
}
interop::Promise<void> GPUBuffer::mapAsync(Napi::Env env,
interop::GPUMapModeFlags mode,
std::optional<interop::GPUSize64> offset,
std::optional<interop::GPUSize64> size) {
wgpu::MapMode md{};
Converter conv(env);
if (!conv(md, mode)) {
return {env};
}
if (state_ != State::Unmapped) {
interop::Promise<void> promise(env);
promise.Reject(Errors::OperationError(env));
device_.InjectError(wgpu::ErrorType::Validation,
"mapAsync called on buffer that is not in the unmapped state");
return promise;
}
struct Context {
Napi::Env env;
interop::Promise<void> promise;
AsyncTask task;
State& state;
};
auto ctx = new Context{env, interop::Promise<void>(env), async_, state_};
auto promise = ctx->promise;
uint64_t o = offset.has_value() ? offset.value() : 0;
uint64_t s = size.has_value() ? size.value() : (desc_.size - o);
state_ = State::MappingPending;
buffer_.MapAsync(
md, o, s,
[](WGPUBufferMapAsyncStatus status, void* userdata) {
auto c = std::unique_ptr<Context>(static_cast<Context*>(userdata));
c->state = State::Unmapped;
switch (status) {
case WGPUBufferMapAsyncStatus::WGPUBufferMapAsyncStatus_Success:
c->promise.Resolve();
c->state = State::Mapped;
break;
case WGPUBufferMapAsyncStatus::WGPUBufferMapAsyncStatus_Error:
c->promise.Reject(Errors::OperationError(c->env));
break;
case WGPUBufferMapAsyncStatus::WGPUBufferMapAsyncStatus_UnmappedBeforeCallback:
c->promise.Reject(Errors::AbortError(c->env));
break;
case WGPUBufferMapAsyncStatus::WGPUBufferMapAsyncStatus_Unknown:
case WGPUBufferMapAsyncStatus::WGPUBufferMapAsyncStatus_DeviceLost:
case WGPUBufferMapAsyncStatus::WGPUBufferMapAsyncStatus_DestroyedBeforeCallback:
// TODO: The spec is a bit vague around what the promise should do
// here.
c->promise.Reject(Errors::UnknownError(c->env));
break;
}
},
ctx);
return promise;
}
interop::ArrayBuffer GPUBuffer::getMappedRange(Napi::Env env,
std::optional<interop::GPUSize64> offset,
std::optional<interop::GPUSize64> size) {
if (state_ != State::Mapped && state_ != State::MappedAtCreation) {
Errors::OperationError(env).ThrowAsJavaScriptException();
return {};
}
uint64_t o = offset.has_value() ? offset.value() : 0;
uint64_t s = size.has_value() ? size.value() : (desc_.size - o);
uint64_t start = o;
uint64_t end = o + s;
for (auto& mapping : mapped_) {
if (mapping.Intersects(start, end)) {
Errors::OperationError(env).ThrowAsJavaScriptException();
return {};
}
}
auto* ptr = (desc_.usage & wgpu::BufferUsage::MapWrite)
? buffer_.GetMappedRange(o, s)
: const_cast<void*>(buffer_.GetConstMappedRange(o, s));
if (!ptr) {
Errors::OperationError(env).ThrowAsJavaScriptException();
return {};
}
auto array_buffer = Napi::ArrayBuffer::New(env, ptr, s);
// TODO(crbug.com/dawn/1135): Ownership here is the wrong way around.
mapped_.emplace_back(Mapping{start, end, Napi::Persistent(array_buffer)});
return array_buffer;
}
void GPUBuffer::unmap(Napi::Env env) {
if (state_ == State::Destroyed) {
device_.InjectError(wgpu::ErrorType::Validation,
"unmap() called on a destroyed buffer");
return;
}
for (auto& mapping : mapped_) {
mapping.buffer.Value().Detach();
}
mapped_.clear();
buffer_.Unmap();
state_ = State::Unmapped;
}
void GPUBuffer::destroy(Napi::Env) {
buffer_.Destroy();
state_ = State::Destroyed;
}
std::optional<std::string> GPUBuffer::getLabel(Napi::Env) {
UNIMPLEMENTED();
}
void GPUBuffer::setLabel(Napi::Env, std::optional<std::string> value) {
UNIMPLEMENTED();
}
}} // namespace wgpu::binding