Bug 1752188: Move GPUBufferDescriptor validation to server. r=jgilbert

Depends on [`wgpu#2673`].

WebGPU requires `GPUBufferDescriptor` validation failure to:

1) generate an error on the Device timeline, and

2) mark the new buffer as invalid.

Satisfy 1) by moving most validation to the compositor process.

Requirement 2) is harder. `wgpu_core::Global::device_create_buffer`
already takes care of some validation for us, and marks the provided
buffer id invalid when there's a problem. However, there are certain
errors the spec requires us to detect which `device_create_buffer`
cannot even see, because they are caught by standard Rust validation
steps in the process of creating the `wgpu_types::BufferDescriptor`
that one would *pass to* that function. For example, if there are
bogus bits set in the `usage` property, we can't even construct a Rust
`BufferUsages` value from that to include in the `BufferDescriptor`
that we must pass to `device_create_buffer`.

This means that we need to do some validation ourselves, in the
process of constructing that `BufferDescriptor`, and use the
`Global::create_buffer_error` method added in [`wgpu#2673`] to mark
the new buffer as invalid.

[`wgpu#2673`]: https://github.com/gfx-rs/wgpu/pull/2673

Differential Revision: https://phabricator.services.mozilla.com/D146768
This commit is contained in:
Jim Blandy 2022-06-06 06:33:13 +00:00
parent b3f36731c3
commit cee3303a59
9 changed files with 52 additions and 50 deletions

View File

@ -10,6 +10,7 @@ using layers::CompositableHandle from "mozilla/layers/LayersTypes.h";
using RawId from "mozilla/webgpu/WebGPUTypes.h"; using RawId from "mozilla/webgpu/WebGPUTypes.h";
using dom::GPURequestAdapterOptions from "mozilla/dom/WebGPUBinding.h"; using dom::GPURequestAdapterOptions from "mozilla/dom/WebGPUBinding.h";
using dom::GPUCommandBufferDescriptor from "mozilla/dom/WebGPUBinding.h"; using dom::GPUCommandBufferDescriptor from "mozilla/dom/WebGPUBinding.h";
using dom::GPUBufferDescriptor from "mozilla/dom/WebGPUBinding.h";
using webgpu::ffi::WGPUHostMap from "mozilla/webgpu/ffi/wgpu.h"; using webgpu::ffi::WGPUHostMap from "mozilla/webgpu/ffi/wgpu.h";
using MaybeScopedError from "mozilla/webgpu/WebGPUTypes.h"; using MaybeScopedError from "mozilla/webgpu/WebGPUTypes.h";
@ -38,6 +39,8 @@ parent:
async CommandEncoderAction(RawId selfId, RawId aDeviceId, ByteBuf buf); async CommandEncoderAction(RawId selfId, RawId aDeviceId, ByteBuf buf);
async BumpImplicitBindGroupLayout(RawId pipelineId, bool isCompute, uint32_t index, RawId assignId); async BumpImplicitBindGroupLayout(RawId pipelineId, bool isCompute, uint32_t index, RawId assignId);
async CreateBuffer(RawId deviceId, RawId bufferId, GPUBufferDescriptor desc);
async InstanceRequestAdapter(GPURequestAdapterOptions options, RawId[] ids) returns (ByteBuf byteBuf); async InstanceRequestAdapter(GPURequestAdapterOptions options, RawId[] ids) returns (ByteBuf byteBuf);
async AdapterRequestDevice(RawId selfId, ByteBuf buf, RawId newId) returns (bool success); async AdapterRequestDevice(RawId selfId, ByteBuf buf, RawId newId) returns (bool success);
async AdapterDestroy(RawId selfId); async AdapterDestroy(RawId selfId);

View File

@ -352,23 +352,11 @@ Maybe<DeviceRequest> WebGPUChild::AdapterRequestDevice(
RawId WebGPUChild::DeviceCreateBuffer(RawId aSelfId, RawId WebGPUChild::DeviceCreateBuffer(RawId aSelfId,
const dom::GPUBufferDescriptor& aDesc) { const dom::GPUBufferDescriptor& aDesc) {
ffi::WGPUBufferDescriptor desc = {}; RawId bufferId = ffi::wgpu_client_make_buffer_id(mClient.get(), aSelfId);
nsCString label; if (!SendCreateBuffer(aSelfId, bufferId, aDesc)) {
if (aDesc.mLabel.WasPassed()) {
LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
desc.label = label.get();
}
desc.size = aDesc.mSize;
desc.usage = aDesc.mUsage;
desc.mapped_at_creation = aDesc.mMappedAtCreation;
ByteBuf bb;
RawId id =
ffi::wgpu_client_create_buffer(mClient.get(), aSelfId, &desc, ToFFI(&bb));
if (!SendDeviceAction(aSelfId, std::move(bb))) {
MOZ_CRASH("IPC failure"); MOZ_CRASH("IPC failure");
} }
return id; return bufferId;
} }
RawId WebGPUChild::DeviceCreateTexture(RawId aSelfId, RawId WebGPUChild::DeviceCreateTexture(RawId aSelfId,

View File

@ -334,6 +334,22 @@ ipc::IPCResult WebGPUParent::RecvDeviceDestroy(RawId aSelfId) {
return IPC_OK(); return IPC_OK();
} }
ipc::IPCResult WebGPUParent::RecvCreateBuffer(
RawId aSelfId, RawId aBufferId, dom::GPUBufferDescriptor&& aDesc) {
nsCString label;
const char* labelOrNull = nullptr;
if (aDesc.mLabel.WasPassed()) {
LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
labelOrNull = label.get();
}
ErrorBuffer error;
ffi::wgpu_server_device_create_buffer(mContext.get(), aSelfId, aBufferId,
labelOrNull, aDesc.mSize, aDesc.mUsage,
aDesc.mMappedAtCreation, error.ToFFI());
ForwardError(aSelfId, error);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvBufferReturnShmem(RawId aSelfId, ipc::IPCResult WebGPUParent::RecvBufferReturnShmem(RawId aSelfId,
Shmem&& aShmem) { Shmem&& aShmem) {
MOZ_LOG(sLogger, LogLevel::Info, MOZ_LOG(sLogger, LogLevel::Info,
@ -744,13 +760,11 @@ ipc::IPCResult WebGPUParent::RecvSwapChainPresent(
ffi::WGPUBufferUsages usage = ffi::WGPUBufferUsages usage =
WGPUBufferUsages_COPY_DST | WGPUBufferUsages_MAP_READ; WGPUBufferUsages_COPY_DST | WGPUBufferUsages_MAP_READ;
ffi::WGPUBufferDescriptor desc = {};
desc.size = bufferSize;
desc.usage = usage;
ErrorBuffer error; ErrorBuffer error;
ffi::wgpu_server_device_create_buffer(mContext.get(), data->mDeviceId, ffi::wgpu_server_device_create_buffer(mContext.get(), data->mDeviceId,
&desc, bufferId, error.ToFFI()); bufferId, nullptr, bufferSize,
usage, false, error.ToFFI());
if (ForwardError(data->mDeviceId, error)) { if (ForwardError(data->mDeviceId, error)) {
return IPC_OK(); return IPC_OK();
} }

View File

@ -34,6 +34,8 @@ class WebGPUParent final : public PWebGPUParent {
AdapterRequestDeviceResolver&& resolver); AdapterRequestDeviceResolver&& resolver);
ipc::IPCResult RecvAdapterDestroy(RawId aSelfId); ipc::IPCResult RecvAdapterDestroy(RawId aSelfId);
ipc::IPCResult RecvDeviceDestroy(RawId aSelfId); ipc::IPCResult RecvDeviceDestroy(RawId aSelfId);
ipc::IPCResult RecvCreateBuffer(RawId aSelfId, RawId aBufferId,
dom::GPUBufferDescriptor&& aDesc);
ipc::IPCResult RecvBufferReturnShmem(RawId aSelfId, Shmem&& aShmem); ipc::IPCResult RecvBufferReturnShmem(RawId aSelfId, Shmem&& aShmem);
ipc::IPCResult RecvBufferMap(RawId aSelfId, ffi::WGPUHostMap aHostMap, ipc::IPCResult RecvBufferMap(RawId aSelfId, ffi::WGPUHostMap aHostMap,
uint64_t aOffset, uint64_t size, uint64_t aOffset, uint64_t size,

View File

@ -33,6 +33,9 @@ DEFINE_IPC_SERIALIZER_WITHOUT_FIELDS(mozilla::dom::GPUCommandBufferDescriptor);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::GPURequestAdapterOptions, DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::GPURequestAdapterOptions,
mPowerPreference, mForceFallbackAdapter); mPowerPreference, mForceFallbackAdapter);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::GPUBufferDescriptor, mSize,
mUsage, mMappedAtCreation);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::webgpu::ScopedError, operationError, DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::webgpu::ScopedError, operationError,
validationMessage); validationMessage);

View File

@ -43,6 +43,7 @@ exclude = [
"Option_BufferSize", "Option_NonZeroU32", "Option_NonZeroU8", "Option_BufferSize", "Option_NonZeroU32", "Option_NonZeroU8",
"ANativeWindow_setBuffersGeometry", "ANativeWindow_setBuffersGeometry",
] ]
include = ["BufferUsages"]
[export.rename] [export.rename]
"BufferDescriptor_RawString" = "BufferDescriptor" "BufferDescriptor_RawString" = "BufferDescriptor"

View File

@ -475,26 +475,6 @@ pub extern "C" fn wgpu_client_make_buffer_id(
.alloc(backend) .alloc(backend)
} }
#[no_mangle]
pub extern "C" fn wgpu_client_create_buffer(
client: &Client,
device_id: id::DeviceId,
desc: &wgt::BufferDescriptor<RawString>,
bb: &mut ByteBuf,
) -> id::BufferId {
let backend = device_id.backend();
let id = client
.identities
.lock()
.select(backend)
.buffers
.alloc(backend);
let action = DeviceAction::CreateBuffer(id, desc.map_label(cow_label));
*bb = make_byte_buf(&action);
id
}
#[no_mangle] #[no_mangle]
pub extern "C" fn wgpu_client_create_texture( pub extern "C" fn wgpu_client_create_texture(
client: &Client, client: &Client,

View File

@ -75,7 +75,6 @@ struct ImplicitLayout<'a> {
#[derive(serde::Serialize, serde::Deserialize)] #[derive(serde::Serialize, serde::Deserialize)]
enum DeviceAction<'a> { enum DeviceAction<'a> {
CreateBuffer(id::BufferId, wgc::resource::BufferDescriptor<'a>),
CreateTexture(id::TextureId, wgc::resource::TextureDescriptor<'a>), CreateTexture(id::TextureId, wgc::resource::TextureDescriptor<'a>),
CreateSampler(id::SamplerId, wgc::resource::SamplerDescriptor<'a>), CreateSampler(id::SamplerId, wgc::resource::SamplerDescriptor<'a>),
CreateBindGroupLayout( CreateBindGroupLayout(

View File

@ -211,12 +211,30 @@ pub extern "C" fn wgpu_server_device_drop(global: &Global, self_id: id::DeviceId
pub extern "C" fn wgpu_server_device_create_buffer( pub extern "C" fn wgpu_server_device_create_buffer(
global: &Global, global: &Global,
self_id: id::DeviceId, self_id: id::DeviceId,
desc: &wgt::BufferDescriptor<RawString>, buffer_id: id::BufferId,
new_id: id::BufferId, label_or_null: RawString,
size: wgt::BufferAddress,
usage: u32,
mapped_at_creation: bool,
mut error_buf: ErrorBuffer, mut error_buf: ErrorBuffer,
) { ) {
let desc = desc.map_label(cow_label); let label = cow_label(&label_or_null);
let (_, error) = gfx_select!(self_id => global.device_create_buffer(self_id, &desc, new_id)); let usage = match wgt::BufferUsages::from_bits(usage) {
Some(usage) => usage,
None => {
error_buf.init_str("GPUBufferDescriptor's 'usage' includes invalid unimplemented bits \
or unimplemented usages");
gfx_select!(self_id => global.create_buffer_error(buffer_id, label));
return;
}
};
let desc = wgc::resource::BufferDescriptor {
label,
size,
usage,
mapped_at_creation,
};
let (_, error) = gfx_select!(self_id => global.device_create_buffer(self_id, &desc, buffer_id));
if let Some(err) = error { if let Some(err) = error {
error_buf.init(err); error_buf.init(err);
} }
@ -285,12 +303,6 @@ impl Global {
mut error_buf: ErrorBuffer, mut error_buf: ErrorBuffer,
) { ) {
match action { match action {
DeviceAction::CreateBuffer(id, desc) => {
let (_, error) = self.device_create_buffer::<A>(self_id, &desc, id);
if let Some(err) = error {
error_buf.init(err);
}
}
DeviceAction::CreateTexture(id, desc) => { DeviceAction::CreateTexture(id, desc) => {
let (_, error) = self.device_create_texture::<A>(self_id, &desc, id); let (_, error) = self.device_create_texture::<A>(self_id, &desc, id);
if let Some(err) = error { if let Some(err) = error {