dawn.node: Implement writeBuffer up to spec.

Bug: dawn:1132
Change-Id: I5b088283c85305f8c8b662478a5a46169a0217fa
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/85503
Reviewed-by: Ben Clayton <bclayton@google.com>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
Corentin Wallez 2022-04-04 09:09:51 +00:00 committed by Dawn LUCI CQ
parent 7b6609f19b
commit e6359d6058
3 changed files with 41 additions and 9 deletions

View File

@ -149,6 +149,7 @@ namespace wgpu::binding {
auto arr = v.ArrayBuffer(); auto arr = v.ArrayBuffer();
out.data = arr.Data(); out.data = arr.Data();
out.size = arr.ByteLength(); out.size = arr.ByteLength();
out.bytesPerElement = v.ElementSize();
}, },
*view); *view);
return true; return true;
@ -156,6 +157,7 @@ namespace wgpu::binding {
if (auto* arr = std::get_if<interop::ArrayBuffer>(&in)) { if (auto* arr = std::get_if<interop::ArrayBuffer>(&in)) {
out.data = arr->Data(); out.data = arr->Data();
out.size = arr->ByteLength(); out.size = arr->ByteLength();
out.bytesPerElement = 1;
return true; return true;
} }
Napi::Error::New(env, "invalid value for BufferSource").ThrowAsJavaScriptException(); Napi::Error::New(env, "invalid value for BufferSource").ThrowAsJavaScriptException();

View File

@ -95,7 +95,8 @@ namespace wgpu::binding {
// BufferSource is the converted type of interop::BufferSource. // BufferSource is the converted type of interop::BufferSource.
struct BufferSource { struct BufferSource {
void* data; void* data;
size_t size; size_t size; // in bytes
size_t bytesPerElement; // 1 for ArrayBuffers
}; };
private: private:

View File

@ -14,6 +14,8 @@
#include "src/dawn/node/binding/GPUQueue.h" #include "src/dawn/node/binding/GPUQueue.h"
#include <cassert>
#include <limits>
#include <memory> #include <memory>
#include "src/dawn/node/binding/Converter.h" #include "src/dawn/node/binding/Converter.h"
@ -73,8 +75,8 @@ namespace wgpu::binding {
interop::Interface<interop::GPUBuffer> buffer, interop::Interface<interop::GPUBuffer> buffer,
interop::GPUSize64 bufferOffset, interop::GPUSize64 bufferOffset,
interop::BufferSource data, interop::BufferSource data,
interop::GPUSize64 dataOffset, interop::GPUSize64 dataOffsetElements,
std::optional<interop::GPUSize64> size) { std::optional<interop::GPUSize64> sizeElements) {
wgpu::Buffer buf = *buffer.As<GPUBuffer>(); wgpu::Buffer buf = *buffer.As<GPUBuffer>();
Converter::BufferSource src{}; Converter::BufferSource src{};
Converter conv(env); Converter conv(env);
@ -82,16 +84,43 @@ namespace wgpu::binding {
return; return;
} }
// TODO(crbug.com/dawn/1132): Bounds check // Note that in the JS semantics of WebGPU, writeBuffer works in number of elements of the
if (src.data) { // typed arrays.
src.data = reinterpret_cast<uint8_t*>(src.data) + dataOffset; if (dataOffsetElements > uint64_t(src.size / src.bytesPerElement)) {
binding::Errors::OperationError(env, "dataOffset is larger than data's size.")
.ThrowAsJavaScriptException();
return;
} }
uint64_t dataOffset = dataOffsetElements * src.bytesPerElement;
src.data = reinterpret_cast<uint8_t*>(src.data) + dataOffset;
src.size -= dataOffset; src.size -= dataOffset;
if (size.has_value()) {
src.size = size.value(); // Size defaults to dataSize - dataOffset. Instead of computing in elements, we directly
// use it in bytes, and convert the provided value, if any, in bytes.
uint64_t size64 = uint64_t(src.size);
if (sizeElements.has_value()) {
if (sizeElements.value() > std::numeric_limits<uint64_t>::max() / src.bytesPerElement) {
binding::Errors::OperationError(env, "size overflows.")
.ThrowAsJavaScriptException();
return;
}
size64 = sizeElements.value() * src.bytesPerElement;
} }
queue_.WriteBuffer(buf, bufferOffset, src.data, src.size); if (size64 > uint64_t(src.size)) {
binding::Errors::OperationError(env, "size + dataOffset is larger than data's size.")
.ThrowAsJavaScriptException();
return;
}
if (size64 % 4 != 0) {
binding::Errors::OperationError(env, "size is not a multiple of 4 bytes.")
.ThrowAsJavaScriptException();
return;
}
assert(size64 <= std::numeric_limits<size_t>::max());
queue_.WriteBuffer(buf, bufferOffset, src.data, static_cast<size_t>(size64));
} }
void GPUQueue::writeTexture(Napi::Env env, void GPUQueue::writeTexture(Napi::Env env,