We've been seeing a number of bugs caused by incorrect use of foo_from_raw APIs, which construct a higher-level resource from a lower-level resource. I'm referring to APIs like these:
There are similar functions for other sorts of resources like buffers and textures. The names vary, but I'm going to collectively call all of these _from_raw functions.
These _from_raw functions have legitimate uses, and sometimes there may not be any practical alternative. For example, if one wishes to use wgpu to manage resources created by some other part of the system, the _from_raw pattern seems like your only option.
However, in many cases, people are forced to use _from_raw functions for resources they've just created themselves, simply because they need to pass the creation operation some information specific to the particular backend they're using. But in doing so, they bypass the validation that would normally be carried out by wgpu-core. In this way, the present API design creates pressure on users to skip the validation that is one of wgpu's selling points. (Ideally, there would be a cross-platform wgpu-core feature for their case, but designing and implementing such a thing may not always be feasible.)
One solution is to let the users invoke the validation explicitly themselves, as is done in #9979.
Another solution we might consider is inspired by Vulkan's extending structures, but uses standard Rust features to do this in a type-safe way. Here, users would continue to call wgpu_core methods for resource creation as usual. However, these methods would accept a Vec<Box<dyn Any>> (empty in the normal case) which they would pass through unexamined to wgpu_hal. The wgpu_hal backend would then downcast the vector's elements to specific types it recognizes, and use them to inform resource creation. If an element had an unrecognized type, the backend would panic.
This effectively allows wgpu_core functions, which are backend-independent, to accept backend-specific types. Users would exercise exactly the same wgpu-core code paths as normal resource creation. I've verified that it's even possible to pass extending types by value, so that the user can transfer ownership of resources through wgpu-core to wgpu-hal. No unsafe code is required.
We've been seeing a number of bugs caused by incorrect use of
foo_from_rawAPIs, which construct a higher-level resource from a lower-level resource. I'm referring to APIs like these:wgpu_hal::vulkan::Adapter::device_from_rawbuilds awgpu_hal::vulkan::Devicefrom anashVulkan device.wgpu_core::instance::Global::create_device_from_halbuilds awgpu_core::device::Devicefromwgpu_hal::DynOpenDevice.There are similar functions for other sorts of resources like buffers and textures. The names vary, but I'm going to collectively call all of these
_from_rawfunctions.These
_from_rawfunctions have legitimate uses, and sometimes there may not be any practical alternative. For example, if one wishes to use wgpu to manage resources created by some other part of the system, the_from_rawpattern seems like your only option.However, in many cases, people are forced to use
_from_rawfunctions for resources they've just created themselves, simply because they need to pass the creation operation some information specific to the particular backend they're using. But in doing so, they bypass the validation that would normally be carried out by wgpu-core. In this way, the present API design creates pressure on users to skip the validation that is one of wgpu's selling points. (Ideally, there would be a cross-platform wgpu-core feature for their case, but designing and implementing such a thing may not always be feasible.)One solution is to let the users invoke the validation explicitly themselves, as is done in #9979.
Another solution we might consider is inspired by Vulkan's extending structures, but uses standard Rust features to do this in a type-safe way. Here, users would continue to call
wgpu_coremethods for resource creation as usual. However, these methods would accept aVec<Box<dyn Any>>(empty in the normal case) which they would pass through unexamined towgpu_hal. Thewgpu_halbackend would then downcast the vector's elements to specific types it recognizes, and use them to inform resource creation. If an element had an unrecognized type, the backend would panic.This effectively allows
wgpu_corefunctions, which are backend-independent, to accept backend-specific types. Users would exercise exactly the same wgpu-core code paths as normal resource creation. I've verified that it's even possible to pass extending types by value, so that the user can transfer ownership of resources through wgpu-core to wgpu-hal. No unsafe code is required.