Backed out changeset 4fd09aad97af (bug 1876389) for causing webgpu failures on test_command_buffer_creation.html. CLOSED TREE

This commit is contained in:
Iulian Moraru
2024-02-02 22:49:04 +02:00
parent 21e66b936b
commit 92ba802eeb
77 changed files with 1627 additions and 1974 deletions

View File

@@ -25,9 +25,9 @@ git = "https://github.com/franziskuskiefer/cose-rust"
rev = "43c22248d136c8b38fe42ea709d08da6355cf04b"
replace-with = "vendored-sources"
[source."git+https://github.com/gfx-rs/wgpu?rev=87b6513df32e8a9c588962ba8509019c277438e2"]
[source."git+https://github.com/gfx-rs/wgpu?rev=f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"]
git = "https://github.com/gfx-rs/wgpu"
rev = "87b6513df32e8a9c588962ba8509019c277438e2"
rev = "f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
replace-with = "vendored-sources"
[source."git+https://github.com/glandium/mio?rev=9a2ef335c366044ffe73b1c4acabe50a1daefe05"]

10
Cargo.lock generated
View File

@@ -1157,7 +1157,7 @@ dependencies = [
[[package]]
name = "d3d12"
version = "0.19.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=87b6513df32e8a9c588962ba8509019c277438e2#87b6513df32e8a9c588962ba8509019c277438e2"
source = "git+https://github.com/gfx-rs/wgpu?rev=f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e#f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
dependencies = [
"bitflags 2.4.1",
"libloading",
@@ -3791,7 +3791,7 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664"
[[package]]
name = "naga"
version = "0.19.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=87b6513df32e8a9c588962ba8509019c277438e2#87b6513df32e8a9c588962ba8509019c277438e2"
source = "git+https://github.com/gfx-rs/wgpu?rev=f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e#f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
dependencies = [
"arrayvec",
"bit-set",
@@ -6403,7 +6403,7 @@ dependencies = [
[[package]]
name = "wgpu-core"
version = "0.19.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=87b6513df32e8a9c588962ba8509019c277438e2#87b6513df32e8a9c588962ba8509019c277438e2"
source = "git+https://github.com/gfx-rs/wgpu?rev=f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e#f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
dependencies = [
"arrayvec",
"bit-vec",
@@ -6429,7 +6429,7 @@ dependencies = [
[[package]]
name = "wgpu-hal"
version = "0.19.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=87b6513df32e8a9c588962ba8509019c277438e2#87b6513df32e8a9c588962ba8509019c277438e2"
source = "git+https://github.com/gfx-rs/wgpu?rev=f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e#f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
dependencies = [
"android_system_properties",
"arrayvec",
@@ -6467,7 +6467,7 @@ dependencies = [
[[package]]
name = "wgpu-types"
version = "0.19.0"
source = "git+https://github.com/gfx-rs/wgpu?rev=87b6513df32e8a9c588962ba8509019c277438e2#87b6513df32e8a9c588962ba8509019c277438e2"
source = "git+https://github.com/gfx-rs/wgpu?rev=f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e#f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
dependencies = [
"bitflags 2.4.1",
"js-sys",

View File

@@ -192,7 +192,133 @@ class PresentationData {
~PresentationData() { MOZ_COUNT_DTOR(PresentationData); }
};
WebGPUParent::WebGPUParent() : mContext(ffi::wgpu_server_new(this)) {
static void FreeAdapter(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_adapter_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeAdapter");
}
}
static void FreeDevice(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_device_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeDevice");
}
}
static void FreeShaderModule(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_shader_module_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeShaderModule");
}
}
static void FreePipelineLayout(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_pipeline_layout_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreePipelineLayout");
}
}
static void FreeBindGroupLayout(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_bind_group_layout_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeBindGroupLayout");
}
}
static void FreeBindGroup(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_bind_group_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeBindGroup");
}
}
static void FreeCommandBuffer(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_command_buffer_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeCommandBuffer");
}
}
static void FreeRenderBundle(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_render_bundle_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeRenderBundle");
}
}
static void FreeRenderPipeline(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_render_pipeline_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeRenderPipeline");
}
}
static void FreeComputePipeline(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_compute_pipeline_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeComputePipeline");
}
}
static void FreeBuffer(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_buffer_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeBuffer");
}
}
static void FreeTexture(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_texture_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeTexture");
}
}
static void FreeTextureView(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_texture_view_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeTextureView");
}
}
static void FreeSampler(RawId id, void* param) {
ipc::ByteBuf byteBuf;
wgpu_server_sampler_free(id, ToFFI(&byteBuf));
if (!static_cast<WebGPUParent*>(param)->SendDropAction(std::move(byteBuf))) {
NS_ERROR("Unable FreeSampler");
}
}
static void FreeSurface(RawId id, void* param) {
Unused << id;
Unused << param;
}
static ffi::WGPUIdentityRecyclerFactory MakeFactory(void* param) {
ffi::WGPUIdentityRecyclerFactory factory;
PodZero(&factory);
factory.param = param;
factory.free_adapter = FreeAdapter;
factory.free_device = FreeDevice;
factory.free_pipeline_layout = FreePipelineLayout;
factory.free_shader_module = FreeShaderModule;
factory.free_bind_group_layout = FreeBindGroupLayout;
factory.free_bind_group = FreeBindGroup;
factory.free_command_buffer = FreeCommandBuffer;
factory.free_render_bundle = FreeRenderBundle;
factory.free_render_pipeline = FreeRenderPipeline;
factory.free_compute_pipeline = FreeComputePipeline;
factory.free_buffer = FreeBuffer;
factory.free_texture = FreeTexture;
factory.free_texture_view = FreeTextureView;
factory.free_sampler = FreeSampler;
factory.free_surface = FreeSurface;
return factory;
}
WebGPUParent::WebGPUParent()
: mContext(ffi::wgpu_server_new(MakeFactory(this), this)) {
mTimer.Start(base::TimeDelta::FromMilliseconds(POLL_TIME_MS), this,
&WebGPUParent::MaintainDevices);
}

View File

@@ -17,45 +17,46 @@ default = []
[dependencies.wgc]
package = "wgpu-core"
git = "https://github.com/gfx-rs/wgpu"
rev = "87b6513df32e8a9c588962ba8509019c277438e2"
# TODO: remove the replay feature on the next update containing https://github.com/gfx-rs/wgpu/pull/5182
features = ["serde", "replay", "trace", "strict_asserts", "wgsl", "api_log_info"]
rev = "f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
#Note: "replay" shouldn't ideally be needed,
# but it allows us to serialize everything across IPC.
features = ["replay", "trace", "serial-pass", "strict_asserts", "wgsl", "api_log_info"]
# We want the wgpu-core Metal backend on macOS and iOS.
# (We should consider also enabling "vulkan" for Vulkan Portability.)
[target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc]
package = "wgpu-core"
git = "https://github.com/gfx-rs/wgpu"
rev = "87b6513df32e8a9c588962ba8509019c277438e2"
rev = "f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
features = ["metal"]
# We want the wgpu-core Direct3D backends on Windows.
[target.'cfg(windows)'.dependencies.wgc]
package = "wgpu-core"
git = "https://github.com/gfx-rs/wgpu"
rev = "87b6513df32e8a9c588962ba8509019c277438e2"
rev = "f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
features = ["dx12"]
# We want the wgpu-core Vulkan backend on Linux and Windows.
[target.'cfg(any(windows, all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies.wgc]
package = "wgpu-core"
git = "https://github.com/gfx-rs/wgpu"
rev = "87b6513df32e8a9c588962ba8509019c277438e2"
rev = "f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
features = ["vulkan"]
[dependencies.wgt]
package = "wgpu-types"
git = "https://github.com/gfx-rs/wgpu"
rev = "87b6513df32e8a9c588962ba8509019c277438e2"
rev = "f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
[dependencies.wgh]
package = "wgpu-hal"
git = "https://github.com/gfx-rs/wgpu"
rev = "87b6513df32e8a9c588962ba8509019c277438e2"
rev = "f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
[target.'cfg(windows)'.dependencies.d3d12]
git = "https://github.com/gfx-rs/wgpu"
rev = "87b6513df32e8a9c588962ba8509019c277438e2"
rev = "f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
[target.'cfg(windows)'.dependencies]
winapi = "0.3"

View File

@@ -30,26 +30,6 @@ typedef uint64_t WGPUOption_SamplerId;
typedef uint64_t WGPUOption_SurfaceId;
typedef uint64_t WGPUOption_TextureViewId;
typedef uint64_t WGPUOption_QuerySetId;
typedef uint64_t WGPUAdapterId;
typedef uint64_t WGPUBindGroupId;
typedef uint64_t WGPUBindGroupLayoutId;
typedef uint64_t WGPUBufferId;
typedef uint64_t WGPUCommandBufferId;
typedef uint64_t WGPUCommandEncoderId;
typedef uint64_t WGPUComputePipelineId;
typedef uint64_t WGPUDeviceId;
typedef uint64_t WGPUPipelineLayoutId;
typedef uint64_t WGPUQuerySetId;
typedef uint64_t WGPUQueueId;
typedef uint64_t WGPURenderBundleId;
typedef uint64_t WGPURenderPipelineId;
typedef uint64_t WGPUSamplerId;
typedef uint64_t WGPUShaderModuleId;
typedef uint64_t WGPUStagingBufferId;
typedef uint64_t WGPUSurfaceId;
typedef uint64_t WGPUTextureId;
typedef uint64_t WGPUTextureViewId;
"""
include_version = true
braces = "SameLine"

View File

@@ -20,11 +20,11 @@ origin:
# Human-readable identifier for this version/release
# Generally "version NNN", "tag SSS", "bookmark SSS"
release: commit 87b6513df32e8a9c588962ba8509019c277438e2
release: f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e (2024-01-19T21:42:19Z).
# Revision to pull in
# Must be a long or short commit SHA (long preferred)
revision: 87b6513df32e8a9c588962ba8509019c277438e2
revision: f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e
license: ['MIT', 'Apache-2.0']

View File

@@ -14,7 +14,6 @@ use wgc::{id, identity::IdentityManager};
use wgt::{Backend, TextureFormat};
pub use wgc::command::{compute_ffi::*, render_ffi::*};
use wgc::id::markers;
use parking_lot::Mutex;
@@ -265,20 +264,20 @@ pub struct RenderBundleEncoderDescriptor<'a> {
#[derive(Debug)]
struct IdentityHub {
adapters: IdentityManager<markers::Adapter>,
devices: IdentityManager<markers::Device>,
buffers: IdentityManager<markers::Buffer>,
command_buffers: IdentityManager<markers::CommandBuffer>,
render_bundles: IdentityManager<markers::RenderBundle>,
bind_group_layouts: IdentityManager<markers::BindGroupLayout>,
pipeline_layouts: IdentityManager<markers::PipelineLayout>,
bind_groups: IdentityManager<markers::BindGroup>,
shader_modules: IdentityManager<markers::ShaderModule>,
compute_pipelines: IdentityManager<markers::ComputePipeline>,
render_pipelines: IdentityManager<markers::RenderPipeline>,
textures: IdentityManager<markers::Texture>,
texture_views: IdentityManager<markers::TextureView>,
samplers: IdentityManager<markers::Sampler>,
adapters: IdentityManager<wgc::id::AdapterId>,
devices: IdentityManager<wgc::id::DeviceId>,
buffers: IdentityManager<wgc::id::BufferId>,
command_buffers: IdentityManager<wgc::id::CommandBufferId>,
render_bundles: IdentityManager<wgc::id::RenderBundleId>,
bind_group_layouts: IdentityManager<wgc::id::BindGroupLayoutId>,
pipeline_layouts: IdentityManager<wgc::id::PipelineLayoutId>,
bind_groups: IdentityManager<wgc::id::BindGroupId>,
shader_modules: IdentityManager<wgc::id::ShaderModuleId>,
compute_pipelines: IdentityManager<wgc::id::ComputePipelineId>,
render_pipelines: IdentityManager<wgc::id::RenderPipelineId>,
textures: IdentityManager<wgc::id::TextureId>,
texture_views: IdentityManager<wgc::id::TextureViewId>,
samplers: IdentityManager<wgc::id::SamplerId>,
}
impl Default for IdentityHub {
@@ -308,7 +307,7 @@ impl ImplicitLayout<'_> {
pipeline: identities.pipeline_layouts.process(backend),
bind_groups: Cow::Owned(
(0..8) // hal::MAX_BIND_GROUPS
.map(|_| Some(identities.bind_group_layouts.process(backend)))
.map(|_| identities.bind_group_layouts.process(backend))
.collect(),
),
}
@@ -634,7 +633,6 @@ pub extern "C" fn wgpu_client_make_encoder_id(
.select(backend)
.command_buffers
.process(backend)
.transmute()
}
#[no_mangle]
@@ -652,8 +650,7 @@ pub extern "C" fn wgpu_client_create_command_encoder(
.lock()
.select(backend)
.command_buffers
.process(backend)
.transmute();
.process(backend);
let action = DeviceAction::CreateCommandEncoder(id, desc.map_label(|_| label));
*bb = make_byte_buf(&action);
@@ -1151,7 +1148,7 @@ pub unsafe extern "C" fn wgpu_client_create_compute_pipeline(
let implicit = ImplicitLayout::new(identities.select(backend), backend);
ptr::write(implicit_pipeline_layout_id, Some(implicit.pipeline));
for (i, bgl_id) in implicit.bind_groups.iter().enumerate() {
*implicit_bind_group_layout_ids.add(i) = *bgl_id;
*implicit_bind_group_layout_ids.add(i) = Some(*bgl_id);
}
Some(implicit)
}
@@ -1194,7 +1191,7 @@ pub unsafe extern "C" fn wgpu_client_create_render_pipeline(
let implicit = ImplicitLayout::new(identities.select(backend), backend);
ptr::write(implicit_pipeline_layout_id, Some(implicit.pipeline));
for (i, bgl_id) in implicit.bind_groups.iter().enumerate() {
*implicit_bind_group_layout_ids.add(i) = *bgl_id;
*implicit_bind_group_layout_ids.add(i) = Some(*bgl_id);
}
Some(implicit)
}

View File

@@ -1,3 +1,42 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use wgc::id;
pub type FactoryParam = *mut std::ffi::c_void;
//TODO: remove this in favor of `DropAction` that could be sent over IPC.
#[repr(C)]
pub struct IdentityRecyclerFactory {
param: FactoryParam,
free_adapter: extern "C" fn(id::AdapterId, FactoryParam),
free_device: extern "C" fn(id::DeviceId, FactoryParam),
free_pipeline_layout: extern "C" fn(id::PipelineLayoutId, FactoryParam),
free_shader_module: extern "C" fn(id::ShaderModuleId, FactoryParam),
free_bind_group_layout: extern "C" fn(id::BindGroupLayoutId, FactoryParam),
free_bind_group: extern "C" fn(id::BindGroupId, FactoryParam),
free_command_buffer: extern "C" fn(id::CommandBufferId, FactoryParam),
free_render_bundle: extern "C" fn(id::RenderBundleId, FactoryParam),
free_render_pipeline: extern "C" fn(id::RenderPipelineId, FactoryParam),
free_compute_pipeline: extern "C" fn(id::ComputePipelineId, FactoryParam),
free_query_set: extern "C" fn(id::QuerySetId, FactoryParam),
free_buffer: extern "C" fn(id::BufferId, FactoryParam),
free_staging_buffer: extern "C" fn(id::StagingBufferId, FactoryParam),
free_texture: extern "C" fn(id::TextureId, FactoryParam),
free_texture_view: extern "C" fn(id::TextureViewId, FactoryParam),
free_sampler: extern "C" fn(id::SamplerId, FactoryParam),
free_surface: extern "C" fn(id::SurfaceId, FactoryParam),
}
impl<I: wgc::id::TypedId> wgc::identity::IdentityHandlerFactory<I> for IdentityRecyclerFactory {
type Input = I;
fn input_to_id(id_in: Self::Input) -> I {
id_in
}
fn autogenerate_ids() -> bool {
false
}
}
impl wgc::identity::GlobalIdentityHandlerFactory for IdentityRecyclerFactory {}

View File

@@ -9,6 +9,7 @@ pub use wgc::command::{compute_ffi::*, render_ffi::*};
pub mod client;
pub mod error;
pub mod identity;
pub mod server;
pub use wgc::device::trace::Command as CommandEncoderAction;
@@ -112,7 +113,7 @@ pub struct AdapterInformation<S> {
#[derive(serde::Serialize, serde::Deserialize)]
struct ImplicitLayout<'a> {
pipeline: id::PipelineLayoutId,
bind_groups: Cow<'a, [Option<id::BindGroupLayoutId>]>,
bind_groups: Cow<'a, [id::BindGroupLayoutId]>,
}
#[derive(serde::Serialize, serde::Deserialize)]

View File

@@ -4,6 +4,7 @@
use crate::{
error::{ErrMsg, ErrorBuffer, ErrorBufferType},
identity::IdentityRecyclerFactory,
wgpu_string, AdapterInformation, ByteBuf, CommandEncoderAction, DeviceAction, DropAction,
QueueWriteAction, SwapChainId, TextureAction,
};
@@ -74,20 +75,23 @@ fn restrict_limits(limits: wgt::Limits) -> wgt::Limits {
// hide wgc's global in private
pub struct Global {
global: wgc::global::Global,
global: wgc::global::Global<IdentityRecyclerFactory>,
#[allow(dead_code)]
owner: *mut c_void,
}
impl std::ops::Deref for Global {
type Target = wgc::global::Global;
type Target = wgc::global::Global<IdentityRecyclerFactory>;
fn deref(&self) -> &Self::Target {
&self.global
}
}
#[no_mangle]
pub extern "C" fn wgpu_server_new(owner: *mut c_void) -> *mut Global {
pub extern "C" fn wgpu_server_new(
factory: IdentityRecyclerFactory,
owner: *mut c_void,
) -> *mut Global {
log::info!("Initializing WGPU server");
let backends_pref = static_prefs::pref!("dom.webgpu.wgpu-backend").to_string();
let backends = if backends_pref.is_empty() {
@@ -114,6 +118,7 @@ pub extern "C" fn wgpu_server_new(owner: *mut c_void) -> *mut Global {
let global = wgc::global::Global::new(
"wgpu",
factory,
wgt::InstanceDescriptor {
backends,
flags: instance_flags,
@@ -188,8 +193,8 @@ pub unsafe extern "C" fn wgpu_server_instance_request_adapter(
&& desc.AdapterLuid.LowPart == adapter_luid.unwrap().low_part
&& desc.AdapterLuid.HighPart == adapter_luid.unwrap().high_part
{
let adapter_id = global
.create_adapter_from_hal::<wgh::api::Dx12>(adapter, Some(id.unwrap().clone()));
let adapter_id =
global.create_adapter_from_hal::<wgh::api::Dx12>(adapter, id.unwrap().clone());
return ids.iter().position(|&i| i == adapter_id).unwrap() as i8;
}
}
@@ -200,7 +205,10 @@ pub unsafe extern "C" fn wgpu_server_instance_request_adapter(
return -1;
}
match global.request_adapter(desc, wgc::instance::AdapterInputs::IdSet(ids)) {
match global.request_adapter(
desc,
wgc::instance::AdapterInputs::IdSet(ids, |i| i.backend()),
) {
Ok(id) => ids.iter().position(|&i| i == id).unwrap() as i8,
Err(e) => {
error_buf.init(e);
@@ -288,7 +296,7 @@ pub unsafe extern "C" fn wgpu_server_adapter_request_device(
// TODO: in https://github.com/gfx-rs/wgpu/pull/3626/files#diff-033343814319f5a6bd781494692ea626f06f6c3acc0753a12c867b53a646c34eR97
// which introduced the queue id parameter, the queue id is also the device id. I don't know how applicable this is to
// other situations (this one in particular).
let (_, _, error) = gfx_select!(self_id => global.adapter_request_device(self_id, &desc, trace_path, Some(new_id), Some(new_id.transmute())));
let (_, _, error) = gfx_select!(self_id => global.adapter_request_device(self_id, &desc, trace_path, new_id, new_id));
if let Some(err) = error {
error_buf.init(err);
}
@@ -310,11 +318,7 @@ pub extern "C" fn wgpu_server_device_drop(global: &Global, self_id: id::DeviceId
}
#[no_mangle]
pub unsafe extern "C" fn wgpu_server_set_device_lost_callback(
global: &Global,
self_id: id::DeviceId,
callback: wgc::device::DeviceLostClosureC,
) {
pub unsafe extern "C" fn wgpu_server_set_device_lost_callback(global: &Global, self_id: id::DeviceId, callback: wgc::device::DeviceLostClosureC) {
gfx_select!(self_id => global.device_set_device_lost_closure(self_id, wgc::device::DeviceLostClosure::from_c(callback)));
}
@@ -387,7 +391,7 @@ pub extern "C" fn wgpu_server_device_create_shader_module(
let (_, error) = gfx_select!(
self_id => global.device_create_shader_module(
self_id, &desc, source, Some(module_id)
self_id, &desc, source, module_id
)
);
@@ -422,7 +426,7 @@ pub extern "C" fn wgpu_server_device_create_buffer(
message: "Out of memory",
r#type: ErrorBufferType::OutOfMemory,
});
gfx_select!(self_id => global.create_buffer_error(Some(buffer_id), label));
gfx_select!(self_id => global.create_buffer_error(buffer_id, label));
return;
}
@@ -432,8 +436,7 @@ pub extern "C" fn wgpu_server_device_create_buffer(
usage,
mapped_at_creation,
};
let (_, error) =
gfx_select!(self_id => global.device_create_buffer(self_id, &desc, Some(buffer_id)));
let (_, error) = gfx_select!(self_id => global.device_create_buffer(self_id, &desc, buffer_id));
if let Some(err) = error {
error_buf.init(err);
}
@@ -531,10 +534,7 @@ pub extern "C" fn wgpu_server_buffer_drop(global: &Global, self_id: id::BufferId
#[allow(unused_variables)]
#[no_mangle]
pub extern "C" fn wgpu_server_get_device_fence_handle(
global: &Global,
device_id: id::DeviceId,
) -> *mut c_void {
pub extern "C" fn wgpu_server_get_device_fence_handle(global: &Global, device_id: id::DeviceId) -> *mut c_void {
assert!(device_id.backend() == wgt::Backend::Dx12);
#[cfg(target_os = "windows")]
@@ -622,7 +622,7 @@ impl Global {
|| desc.size.height > max
|| desc.size.depth_or_array_layers > max
{
gfx_select!(self_id => self.create_texture_error(Some(id), desc.label));
gfx_select!(self_id => self.create_texture_error(id, desc.label));
error_buf.init(ErrMsg {
message: "Out of memory",
r#type: ErrorBufferType::OutOfMemory,
@@ -709,7 +709,7 @@ impl Global {
hal_texture,
self_id,
&desc,
Some(id),
id,
)
};
if let Some(err) = error {
@@ -719,60 +719,52 @@ impl Global {
}
}
let (_, error) = self.device_create_texture::<A>(self_id, &desc, Some(id));
let (_, error) = self.device_create_texture::<A>(self_id, &desc, id);
if let Some(err) = error {
error_buf.init(err);
}
}
DeviceAction::CreateSampler(id, desc) => {
let (_, error) = self.device_create_sampler::<A>(self_id, &desc, Some(id));
let (_, error) = self.device_create_sampler::<A>(self_id, &desc, id);
if let Some(err) = error {
error_buf.init(err);
}
}
DeviceAction::CreateBindGroupLayout(id, desc) => {
let (_, error) =
self.device_create_bind_group_layout::<A>(self_id, &desc, Some(id));
let (_, error) = self.device_create_bind_group_layout::<A>(self_id, &desc, id);
if let Some(err) = error {
error_buf.init(err);
}
}
DeviceAction::RenderPipelineGetBindGroupLayout(pipeline_id, index, bgl_id) => {
let (_, error) = self.render_pipeline_get_bind_group_layout::<A>(
pipeline_id,
index,
Some(bgl_id),
);
let (_, error) =
self.render_pipeline_get_bind_group_layout::<A>(pipeline_id, index, bgl_id);
if let Some(err) = error {
error_buf.init(err);
}
}
DeviceAction::ComputePipelineGetBindGroupLayout(pipeline_id, index, bgl_id) => {
let (_, error) = self.compute_pipeline_get_bind_group_layout::<A>(
pipeline_id,
index,
Some(bgl_id),
);
let (_, error) =
self.compute_pipeline_get_bind_group_layout::<A>(pipeline_id, index, bgl_id);
if let Some(err) = error {
error_buf.init(err);
}
}
DeviceAction::CreatePipelineLayout(id, desc) => {
let (_, error) = self.device_create_pipeline_layout::<A>(self_id, &desc, Some(id));
let (_, error) = self.device_create_pipeline_layout::<A>(self_id, &desc, id);
if let Some(err) = error {
error_buf.init(err);
}
}
DeviceAction::CreateBindGroup(id, desc) => {
let (_, error) = self.device_create_bind_group::<A>(self_id, &desc, Some(id));
let (_, error) = self.device_create_bind_group::<A>(self_id, &desc, id);
if let Some(err) = error {
error_buf.init(err);
}
}
DeviceAction::CreateShaderModule(id, desc, code) => {
let source = wgc::pipeline::ShaderModuleSource::Wgsl(code);
let (_, error) =
self.device_create_shader_module::<A>(self_id, &desc, source, Some(id));
let (_, error) = self.device_create_shader_module::<A>(self_id, &desc, source, id);
if let Some(err) = error {
error_buf.init(err);
}
@@ -781,15 +773,11 @@ impl Global {
let implicit_ids = implicit
.as_ref()
.map(|imp| wgc::device::ImplicitPipelineIds {
root_id: Some(imp.pipeline),
root_id: imp.pipeline,
group_ids: &imp.bind_groups,
});
let (_, error) = self.device_create_compute_pipeline::<A>(
self_id,
&desc,
Some(id),
implicit_ids,
);
let (_, error) =
self.device_create_compute_pipeline::<A>(self_id, &desc, id, implicit_ids);
if let Some(err) = error {
error_buf.init(err);
}
@@ -798,26 +786,26 @@ impl Global {
let implicit_ids = implicit
.as_ref()
.map(|imp| wgc::device::ImplicitPipelineIds {
root_id: Some(imp.pipeline),
root_id: imp.pipeline,
group_ids: &imp.bind_groups,
});
let (_, error) =
self.device_create_render_pipeline::<A>(self_id, &desc, Some(id), implicit_ids);
self.device_create_render_pipeline::<A>(self_id, &desc, id, implicit_ids);
if let Some(err) = error {
error_buf.init(err);
}
}
DeviceAction::CreateRenderBundle(id, encoder, desc) => {
let (_, error) = self.render_bundle_encoder_finish::<A>(encoder, &desc, Some(id));
let (_, error) = self.render_bundle_encoder_finish::<A>(encoder, &desc, id);
if let Some(err) = error {
error_buf.init(err);
}
}
DeviceAction::CreateRenderBundleError(buffer_id, label) => {
self.create_render_bundle_error::<A>(Some(buffer_id), label);
self.create_render_bundle_error::<A>(buffer_id, label);
}
DeviceAction::CreateCommandEncoder(id, desc) => {
let (_, error) = self.device_create_command_encoder::<A>(self_id, &desc, Some(id));
let (_, error) = self.device_create_command_encoder::<A>(self_id, &desc, id);
if let Some(err) = error {
error_buf.init(err);
}
@@ -839,7 +827,7 @@ impl Global {
) {
match action {
TextureAction::CreateView(id, desc) => {
let (_, error) = self.texture_create_view::<A>(self_id, &desc, Some(id));
let (_, error) = self.texture_create_view::<A>(self_id, &desc, id);
if let Some(err) = error {
error_buf.init(err);
}
@@ -1027,7 +1015,7 @@ pub extern "C" fn wgpu_server_device_create_encoder(
let desc = desc.map_label(|_| label);
let (_, error) =
gfx_select!(self_id => global.device_create_command_encoder(self_id, &desc, Some(new_id)));
gfx_select!(self_id => global.device_create_command_encoder(self_id, &desc, new_id));
if let Some(err) = error {
error_buf.init(err);
}
@@ -1072,8 +1060,7 @@ pub unsafe extern "C" fn wgpu_server_encoder_copy_texture_to_buffer(
buffer: dst_buffer,
layout: dst_layout.into_wgt(),
};
if let Err(err) = gfx_select!(self_id => global.command_encoder_copy_texture_to_buffer(self_id, source, &destination, size))
{
if let Err(err) = gfx_select!(self_id => global.command_encoder_copy_texture_to_buffer(self_id, source, &destination, size)) {
error_buf.init(err);
}
}
@@ -1176,7 +1163,10 @@ pub extern "C" fn wgpu_server_render_pipeline_drop(global: &Global, self_id: id:
}
#[no_mangle]
pub extern "C" fn wgpu_server_texture_destroy(global: &Global, self_id: id::TextureId) {
pub extern "C" fn wgpu_server_texture_destroy(
global: &Global,
self_id: id::TextureId,
) {
let _ = gfx_select!(self_id => global.texture_destroy(self_id));
}
@@ -1203,7 +1193,7 @@ pub extern "C" fn wgpu_server_compute_pipeline_get_bind_group_layout(
assign_id: id::BindGroupLayoutId,
mut error_buf: ErrorBuffer,
) {
let (_, error) = gfx_select!(self_id => global.compute_pipeline_get_bind_group_layout(self_id, index, Some(assign_id)));
let (_, error) = gfx_select!(self_id => global.compute_pipeline_get_bind_group_layout(self_id, index, assign_id));
if let Some(err) = error {
error_buf.init(err);
}
@@ -1217,7 +1207,7 @@ pub extern "C" fn wgpu_server_render_pipeline_get_bind_group_layout(
assign_id: id::BindGroupLayoutId,
mut error_buf: ErrorBuffer,
) {
let (_, error) = gfx_select!(self_id => global.render_pipeline_get_bind_group_layout(self_id, index, Some(assign_id)));
let (_, error) = gfx_select!(self_id => global.render_pipeline_get_bind_group_layout(self_id, index, assign_id));
if let Some(err) = error {
error_buf.init(err);
}

View File

@@ -1302,10 +1302,9 @@ who = [
"Nicolas Silva <nical@fastmail.com>",
"Teodor Tanasoaia <ttanasoaia@mozilla.com>",
"Erich Gubler <erichdongubler@gmail.com>",
"Jim Blandy <jimb@red-bean.com>",
]
criteria = "safe-to-deploy"
delta = "0.7.0 -> 0.19.0@git:87b6513df32e8a9c588962ba8509019c277438e2"
delta = "0.7.0 -> 0.19.0@git:f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
importable = false
[[audits.darling]]
@@ -2598,13 +2597,13 @@ delta = "0.13.0 -> 0.14.0"
[[audits.naga]]
who = [
"Jim Blandy <jimb@red-bean.com>",
"Nicolas Silva <nical@fastmail.com>",
"Teodor Tanasoaia <ttanasoaia@mozilla.com>",
"Erich Gubler <erichdongubler@gmail.com>",
"Jim Blandy <jimb@red-bean.com>",
]
criteria = "safe-to-deploy"
delta = "0.14.0 -> 0.19.0@git:87b6513df32e8a9c588962ba8509019c277438e2"
delta = "0.14.0 -> 0.19.0@git:f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
importable = false
[[audits.net2]]
@@ -4385,13 +4384,13 @@ delta = "0.17.0 -> 0.18.0"
[[audits.wgpu-core]]
who = [
"Jim Blandy <jimb@red-bean.com>",
"Nicolas Silva <nical@fastmail.com>",
"Teodor Tanasoaia <ttanasoaia@mozilla.com>",
"Erich Gubler <erichdongubler@gmail.com>",
"Jim Blandy <jimb@red-bean.com>",
]
criteria = "safe-to-deploy"
delta = "0.18.0 -> 0.19.0@git:87b6513df32e8a9c588962ba8509019c277438e2"
delta = "0.18.0 -> 0.19.0@git:f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
importable = false
[[audits.wgpu-hal]]
@@ -4439,13 +4438,13 @@ delta = "0.17.0 -> 0.18.0"
[[audits.wgpu-hal]]
who = [
"Jim Blandy <jimb@red-bean.com>",
"Nicolas Silva <nical@fastmail.com>",
"Teodor Tanasoaia <ttanasoaia@mozilla.com>",
"Erich Gubler <erichdongubler@gmail.com>",
"Jim Blandy <jimb@red-bean.com>",
]
criteria = "safe-to-deploy"
delta = "0.18.0 -> 0.19.0@git:87b6513df32e8a9c588962ba8509019c277438e2"
delta = "0.18.0 -> 0.19.0@git:f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
importable = false
[[audits.wgpu-types]]
@@ -4493,13 +4492,13 @@ delta = "0.17.0 -> 0.18.0"
[[audits.wgpu-types]]
who = [
"Jim Blandy <jimb@red-bean.com>",
"Nicolas Silva <nical@fastmail.com>",
"Teodor Tanasoaia <ttanasoaia@mozilla.com>",
"Erich Gubler <erichdongubler@gmail.com>",
"Jim Blandy <jimb@red-bean.com>",
]
criteria = "safe-to-deploy"
delta = "0.18.0 -> 0.19.0@git:87b6513df32e8a9c588962ba8509019c277438e2"
delta = "0.18.0 -> 0.19.0@git:f9509bcf9ec2b63a64eb7fea93f7f44cd5ae4d2e"
importable = false
[[audits.whatsys]]

View File

@@ -1 +1 @@
{"files":{"CHANGELOG.md":"45fa76b0e5bc51721887147000e9e78a5934cb04d1ad628e501ef2082763d353","Cargo.toml":"1108efc3deca25c270c3f8631abca07e7e696aace92d324ef8b83503cb2edbc3","README.md":"76cee3209f773a62535de6c9724b53f158406359f35b4d48b17ac3747b6c102e","src/com.rs":"cfc8f5692162b4cbf9bf370959ad0be08a40a7e9026b5511ca0065ffe33f72ab","src/command_allocator.rs":"ef01059a661749470f3772d188fe0fab0f002e1d154facdab4b9b2932f4b2d93","src/command_list.rs":"8723f3b755b721e0dbb234bd604956c1b7922a2368231197495daa3fa6548e63","src/debug.rs":"aa33b98f7c3e71cba75fc42c6ca9af72d96b45122422c16e48525e24590c57bf","src/descriptor.rs":"fea0b820de1566b54d17d8d0c67e6f5a2126eda19526397eb710ff7d6db9db9e","src/device.rs":"c1dd479aabd22bced0d407523d60629ad1da439fb47ad89fe7b48bae1c4b23e5","src/dxgi.rs":"1516186845b91bf3df813a29b4a0e00a85ca5649fb7a2755da43fba984c41a42","src/heap.rs":"dae2380684896c97e97ed022929f79ce2cc4f5418a3ec34883086f7c88f423d0","src/lib.rs":"612e2f471b84502d219da3fb86ee13f3cbd6faf17d77407bab6c84e51ec424d0","src/pso.rs":"ff819c321536695e34a3be9a6051cf3e57765049a4a2035db6ab27add5a7978a","src/query.rs":"ff61a2b76a108afc1f082724bb9b07ac8b52afbe97356e0fcf6df0ff7e53e07d","src/queue.rs":"bd32813d0b8a3bedf3223b69ade9f9c799a138a9e27d970f86435d9ce32d1557","src/resource.rs":"8989cdb7c3ee0687c826047f39f85148459d9219754f20a970bf8aaa09b96e27","src/sync.rs":"5c287fb7498242a397eb1f08887be9cff9b48dc7cb13af5792cce5f7182b55f8"},"package":null}
{"files":{"CHANGELOG.md":"45fa76b0e5bc51721887147000e9e78a5934cb04d1ad628e501ef2082763d353","Cargo.toml":"1108efc3deca25c270c3f8631abca07e7e696aace92d324ef8b83503cb2edbc3","README.md":"76cee3209f773a62535de6c9724b53f158406359f35b4d48b17ac3747b6c102e","src/com.rs":"cfc8f5692162b4cbf9bf370959ad0be08a40a7e9026b5511ca0065ffe33f72ab","src/command_allocator.rs":"ef01059a661749470f3772d188fe0fab0f002e1d154facdab4b9b2932f4b2d93","src/command_list.rs":"8723f3b755b721e0dbb234bd604956c1b7922a2368231197495daa3fa6548e63","src/debug.rs":"67c8eb966cf349038f79c691e42b5d86cd8fc63c40d10cc279172400d56db6dc","src/descriptor.rs":"fea0b820de1566b54d17d8d0c67e6f5a2126eda19526397eb710ff7d6db9db9e","src/device.rs":"c1dd479aabd22bced0d407523d60629ad1da439fb47ad89fe7b48bae1c4b23e5","src/dxgi.rs":"1516186845b91bf3df813a29b4a0e00a85ca5649fb7a2755da43fba984c41a42","src/heap.rs":"dae2380684896c97e97ed022929f79ce2cc4f5418a3ec34883086f7c88f423d0","src/lib.rs":"612e2f471b84502d219da3fb86ee13f3cbd6faf17d77407bab6c84e51ec424d0","src/pso.rs":"ff819c321536695e34a3be9a6051cf3e57765049a4a2035db6ab27add5a7978a","src/query.rs":"ff61a2b76a108afc1f082724bb9b07ac8b52afbe97356e0fcf6df0ff7e53e07d","src/queue.rs":"bd32813d0b8a3bedf3223b69ade9f9c799a138a9e27d970f86435d9ce32d1557","src/resource.rs":"8989cdb7c3ee0687c826047f39f85148459d9219754f20a970bf8aaa09b96e27","src/sync.rs":"5c287fb7498242a397eb1f08887be9cff9b48dc7cb13af5792cce5f7182b55f8"},"package":null}

View File

@@ -1,10 +1,7 @@
use crate::com::ComPtr;
use winapi::um::d3d12sdklayers;
#[cfg(any(feature = "libloading", feature = "implicit-link"))]
use winapi::Interface as _;
use winapi::{
shared::{minwindef::TRUE, winerror::S_OK},
um::d3d12sdklayers,
};
pub type Debug = ComPtr<d3d12sdklayers::ID3D12Debug>;
@@ -43,14 +40,4 @@ impl Debug {
pub fn enable_layer(&self) {
unsafe { self.EnableDebugLayer() }
}
pub fn enable_gpu_based_validation(&self) -> bool {
let (ptr, hr) = unsafe { self.cast::<d3d12sdklayers::ID3D12Debug1>() };
if hr == S_OK {
unsafe { ptr.SetEnableGPUBasedValidation(TRUE) };
true
} else {
false
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -48,7 +48,7 @@ harness = false
[dependencies]
arrayvec = "0.7"
bit-set = "0.5"
bitflags = "2.4"
bitflags = "2.2"
log = "0.4"
num-traits = "0.2"
rustc-hash = "1.1.0"

View File

@@ -1,11 +1,7 @@
use super::token::TokenValue;
use crate::{proc::ConstantEvaluatorError, Span};
use codespan_reporting::diagnostic::{Diagnostic, Label};
use codespan_reporting::files::SimpleFile;
use codespan_reporting::term;
use pp_rs::token::PreprocessorError;
use std::borrow::Cow;
use termcolor::{NoColor, WriteColor};
use thiserror::Error;
fn join_with_comma(list: &[ExpectedToken]) -> String {
@@ -22,7 +18,7 @@ fn join_with_comma(list: &[ExpectedToken]) -> String {
}
/// One of the expected tokens returned in [`InvalidToken`](ErrorKind::InvalidToken).
#[derive(Clone, Debug, PartialEq)]
#[derive(Debug, PartialEq)]
pub enum ExpectedToken {
/// A specific token was expected.
Token(TokenValue),
@@ -59,7 +55,7 @@ impl std::fmt::Display for ExpectedToken {
}
/// Information about the cause of an error.
#[derive(Clone, Debug, Error)]
#[derive(Debug, Error)]
#[cfg_attr(test, derive(PartialEq))]
pub enum ErrorKind {
/// Whilst parsing as encountered an unexpected EOF.
@@ -127,7 +123,7 @@ impl From<ConstantEvaluatorError> for ErrorKind {
}
/// Error returned during shader parsing.
#[derive(Clone, Debug, Error)]
#[derive(Debug, Error)]
#[error("{kind}")]
#[cfg_attr(test, derive(PartialEq))]
pub struct Error {
@@ -136,56 +132,3 @@ pub struct Error {
/// Holds information about the range of the source code where the error happened.
pub meta: Span,
}
/// A collection of errors returned during shader parsing.
#[derive(Clone, Debug)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ParseError {
pub errors: Vec<Error>,
}
impl ParseError {
pub fn emit_to_writer(&self, writer: &mut impl WriteColor, source: &str) {
self.emit_to_writer_with_path(writer, source, "glsl");
}
pub fn emit_to_writer_with_path(&self, writer: &mut impl WriteColor, source: &str, path: &str) {
let path = path.to_string();
let files = SimpleFile::new(path, source);
let config = codespan_reporting::term::Config::default();
for err in &self.errors {
let mut diagnostic = Diagnostic::error().with_message(err.kind.to_string());
if let Some(range) = err.meta.to_range() {
diagnostic = diagnostic.with_labels(vec![Label::primary((), range)]);
}
term::emit(writer, &config, &files, &diagnostic).expect("cannot write error");
}
}
pub fn emit_to_string(&self, source: &str) -> String {
let mut writer = NoColor::new(Vec::new());
self.emit_to_writer(&mut writer, source);
String::from_utf8(writer.into_inner()).unwrap()
}
}
impl std::fmt::Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.errors.iter().try_for_each(|e| write!(f, "{e:?}"))
}
}
impl std::error::Error for ParseError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
None
}
}
impl From<Vec<Error>> for ParseError {
fn from(errors: Vec<Error>) -> Self {
Self { errors }
}
}

View File

@@ -13,7 +13,7 @@ To begin, take a look at the documentation for the [`Frontend`].
*/
pub use ast::{Precision, Profile};
pub use error::{Error, ErrorKind, ExpectedToken, ParseError};
pub use error::{Error, ErrorKind, ExpectedToken};
pub use token::TokenValue;
use crate::{proc::Layouter, FastHashMap, FastHashSet, Handle, Module, ShaderStage, Span, Type};
@@ -196,7 +196,7 @@ impl Frontend {
&mut self,
options: &Options,
source: &str,
) -> std::result::Result<Module, ParseError> {
) -> std::result::Result<Module, Vec<Error>> {
self.reset(options.stage);
let lexer = lex::Lexer::new(source, &options.defines);
@@ -207,12 +207,12 @@ impl Frontend {
if self.errors.is_empty() {
Ok(module)
} else {
Err(std::mem::take(&mut self.errors).into())
Err(std::mem::take(&mut self.errors))
}
}
Err(e) => {
self.errors.push(e);
Err(std::mem::take(&mut self.errors).into())
Err(std::mem::take(&mut self.errors))
}
}
}

View File

@@ -1,7 +1,7 @@
use super::{
ast::Profile,
error::ExpectedToken,
error::{Error, ErrorKind, ParseError},
error::{Error, ErrorKind},
token::TokenValue,
Frontend, Options, Span,
};
@@ -21,12 +21,10 @@ fn version() {
)
.err()
.unwrap(),
ParseError {
errors: vec![Error {
kind: ErrorKind::InvalidVersion(99000),
meta: Span::new(9, 14)
}],
},
vec![Error {
kind: ErrorKind::InvalidVersion(99000),
meta: Span::new(9, 14)
}],
);
assert_eq!(
@@ -37,12 +35,10 @@ fn version() {
)
.err()
.unwrap(),
ParseError {
errors: vec![Error {
kind: ErrorKind::InvalidVersion(449),
meta: Span::new(9, 12)
}]
},
vec![Error {
kind: ErrorKind::InvalidVersion(449),
meta: Span::new(9, 12)
}]
);
assert_eq!(
@@ -53,12 +49,10 @@ fn version() {
)
.err()
.unwrap(),
ParseError {
errors: vec![Error {
kind: ErrorKind::InvalidProfile("smart".into()),
meta: Span::new(13, 18),
}]
},
vec![Error {
kind: ErrorKind::InvalidProfile("smart".into()),
meta: Span::new(13, 18),
}]
);
assert_eq!(
@@ -69,21 +63,19 @@ fn version() {
)
.err()
.unwrap(),
ParseError {
errors: vec![
Error {
kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedHash,),
meta: Span::new(27, 28),
},
Error {
kind: ErrorKind::InvalidToken(
TokenValue::Identifier("version".into()),
vec![ExpectedToken::Eof]
),
meta: Span::new(28, 35)
}
]
},
vec![
Error {
kind: ErrorKind::PreprocessorError(PreprocessorError::UnexpectedHash,),
meta: Span::new(27, 28),
},
Error {
kind: ErrorKind::InvalidToken(
TokenValue::Identifier("version".into()),
vec![ExpectedToken::Eof]
),
meta: Span::new(28, 35)
}
]
);
// valid versions
@@ -455,12 +447,10 @@ fn functions() {
)
.err()
.unwrap(),
ParseError {
errors: vec![Error {
kind: ErrorKind::SemanticError("Function already defined".into()),
meta: Span::new(134, 152),
}]
},
vec![Error {
kind: ErrorKind::SemanticError("Function already defined".into()),
meta: Span::new(134, 152),
}]
);
println!();
@@ -636,12 +626,10 @@ fn implicit_conversions() {
)
.err()
.unwrap(),
ParseError {
errors: vec![Error {
kind: ErrorKind::SemanticError("Unknown function \'test\'".into()),
meta: Span::new(156, 165),
}]
},
vec![Error {
kind: ErrorKind::SemanticError("Unknown function \'test\'".into()),
meta: Span::new(156, 165),
}]
);
assert_eq!(
@@ -660,12 +648,10 @@ fn implicit_conversions() {
)
.err()
.unwrap(),
ParseError {
errors: vec![Error {
kind: ErrorKind::SemanticError("Ambiguous best function for \'test\'".into()),
meta: Span::new(158, 165),
}]
}
vec![Error {
kind: ErrorKind::SemanticError("Ambiguous best function for \'test\'".into()),
meta: Span::new(158, 165),
}]
);
}

View File

@@ -20,7 +20,7 @@ pub struct Token {
///
/// This type is exported since it's returned in the
/// [`InvalidToken`](super::ErrorKind::InvalidToken) error.
#[derive(Clone, Debug, PartialEq)]
#[derive(Debug, PartialEq)]
pub enum TokenValue {
Identifier(String),

View File

@@ -1,9 +1,5 @@
use super::ModuleState;
use crate::arena::Handle;
use codespan_reporting::diagnostic::Diagnostic;
use codespan_reporting::files::SimpleFile;
use codespan_reporting::term;
use termcolor::{NoColor, WriteColor};
#[derive(Debug, thiserror::Error)]
pub enum Error {
@@ -131,24 +127,3 @@ pub enum Error {
)]
NonBindingArrayOfImageOrSamplers,
}
impl Error {
pub fn emit_to_writer(&self, writer: &mut impl WriteColor, source: &str) {
self.emit_to_writer_with_path(writer, source, "glsl");
}
pub fn emit_to_writer_with_path(&self, writer: &mut impl WriteColor, source: &str, path: &str) {
let path = path.to_string();
let files = SimpleFile::new(path, source);
let config = codespan_reporting::term::Config::default();
let diagnostic = Diagnostic::error().with_message(format!("{self:?}"));
term::emit(writer, &config, &files, &diagnostic).expect("cannot write error");
}
pub fn emit_to_string(&self, source: &str) -> String {
let mut writer = NoColor::new(Vec::new());
self.emit_to_writer(&mut writer, source);
String::from_utf8(writer.into_inner()).unwrap()
}
}

View File

@@ -687,7 +687,8 @@ pub enum ImageClass {
}
/// A data type declared in the module.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "clone", derive(Clone))]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
@@ -699,7 +700,8 @@ pub struct Type {
}
/// Enum with additional information, depending on the kind of type.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
#[derive(Debug, Eq, Hash, PartialEq)]
#[cfg_attr(feature = "clone", derive(Clone))]
#[cfg_attr(feature = "serialize", derive(Serialize))]
#[cfg_attr(feature = "deserialize", derive(Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]

View File

@@ -97,7 +97,7 @@ macro_rules! gen_component_wise_extractor {
.and_then(|comps| Ok(handler(comps)?.into())),
)+
&Expression::Compose { ty, ref components } => match &eval.types[ty].inner {
&TypeInner::Vector { size, scalar } => match scalar.kind {
&TypeInner::Vector { size: _, scalar } => match scalar.kind {
$(ScalarKind::$scalar_kind)|* => {
let first_ty = ty;
let mut component_groups =
@@ -132,7 +132,7 @@ macro_rules! gen_component_wise_extractor {
let component_groups = component_groups.into_inner().unwrap();
let mut new_components =
ArrayVec::<_, { crate::VectorSize::MAX }>::new();
for idx in 0..(size as u8).into() {
for idx in 0..N {
let group = component_groups
.iter()
.map(|cs| cs[idx])
@@ -222,34 +222,6 @@ gen_component_wise_extractor! {
],
}
gen_component_wise_extractor! {
component_wise_concrete_int -> ConcreteInt,
literals: [
U32 => U32: u32,
I32 => I32: i32,
],
scalar_kinds: [
Sint,
Uint,
],
}
gen_component_wise_extractor! {
component_wise_signed -> Signed,
literals: [
AbstractFloat => AbstractFloat: f64,
AbstractInt => AbstractInt: i64,
F32 => F32: f32,
I32 => I32: i32,
],
scalar_kinds: [
Sint,
AbstractInt,
Float,
AbstractFloat,
],
}
#[derive(Debug)]
enum Behavior {
Wgsl,
@@ -837,9 +809,7 @@ impl<'a> ConstantEvaluator<'a> {
));
}
// NOTE: We try to match the declaration order of `MathFunction` here.
match fun {
// comparison
crate::MathFunction::Abs => {
component_wise_scalar(self, span, [arg], |args| match args {
Scalar::AbstractFloat([e]) => Ok(Scalar::AbstractFloat([e.abs()])),
@@ -849,14 +819,27 @@ impl<'a> ConstantEvaluator<'a> {
Scalar::U32([e]) => Ok(Scalar::U32([e])), // TODO: just re-use the expression, ezpz
})
}
crate::MathFunction::Min => {
component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| {
Ok([e1.min(e2)])
})
crate::MathFunction::Acos => {
component_wise_float!(self, span, [arg], |e| { Ok([e.acos()]) })
}
crate::MathFunction::Max => {
component_wise_scalar!(self, span, [arg, arg1.unwrap()], |e1, e2| {
Ok([e1.max(e2)])
crate::MathFunction::Acosh => {
component_wise_float!(self, span, [arg], |e| { Ok([e.acosh()]) })
}
crate::MathFunction::Asin => {
component_wise_float!(self, span, [arg], |e| { Ok([e.asin()]) })
}
crate::MathFunction::Asinh => {
component_wise_float!(self, span, [arg], |e| { Ok([e.asinh()]) })
}
crate::MathFunction::Atan => {
component_wise_float!(self, span, [arg], |e| { Ok([e.atan()]) })
}
crate::MathFunction::Atanh => {
component_wise_float!(self, span, [arg], |e| { Ok([e.atanh()]) })
}
crate::MathFunction::Pow => {
component_wise_float!(self, span, [arg, arg1.unwrap()], |e1, e2| {
Ok([e1.powf(e2)])
})
}
crate::MathFunction::Clamp => {
@@ -873,61 +856,12 @@ impl<'a> ConstantEvaluator<'a> {
}
)
}
crate::MathFunction::Saturate => {
component_wise_float!(self, span, [arg], |e| { Ok([e.clamp(0., 1.)]) })
}
// trigonometry
crate::MathFunction::Cos => {
component_wise_float!(self, span, [arg], |e| { Ok([e.cos()]) })
}
crate::MathFunction::Cosh => {
component_wise_float!(self, span, [arg], |e| { Ok([e.cosh()]) })
}
crate::MathFunction::Sin => {
component_wise_float!(self, span, [arg], |e| { Ok([e.sin()]) })
}
crate::MathFunction::Sinh => {
component_wise_float!(self, span, [arg], |e| { Ok([e.sinh()]) })
}
crate::MathFunction::Tan => {
component_wise_float!(self, span, [arg], |e| { Ok([e.tan()]) })
}
crate::MathFunction::Tanh => {
component_wise_float!(self, span, [arg], |e| { Ok([e.tanh()]) })
}
crate::MathFunction::Acos => {
component_wise_float!(self, span, [arg], |e| { Ok([e.acos()]) })
}
crate::MathFunction::Asin => {
component_wise_float!(self, span, [arg], |e| { Ok([e.asin()]) })
}
crate::MathFunction::Atan => {
component_wise_float!(self, span, [arg], |e| { Ok([e.atan()]) })
}
crate::MathFunction::Asinh => {
component_wise_float!(self, span, [arg], |e| { Ok([e.asinh()]) })
}
crate::MathFunction::Acosh => {
component_wise_float!(self, span, [arg], |e| { Ok([e.acosh()]) })
}
crate::MathFunction::Atanh => {
component_wise_float!(self, span, [arg], |e| { Ok([e.atanh()]) })
}
crate::MathFunction::Radians => {
component_wise_float!(self, span, [arg], |e1| { Ok([e1.to_radians()]) })
}
crate::MathFunction::Degrees => {
component_wise_float!(self, span, [arg], |e| { Ok([e.to_degrees()]) })
}
// decomposition
crate::MathFunction::Ceil => {
component_wise_float!(self, span, [arg], |e| { Ok([e.ceil()]) })
}
crate::MathFunction::Floor => {
component_wise_float!(self, span, [arg], |e| { Ok([e.floor()]) })
}
crate::MathFunction::Round => {
// TODO: Use `f{32,64}.round_ties_even()` when available on stable. This polyfill
// is shamelessly [~~stolen from~~ inspired by `ndarray-image`][polyfill source],
@@ -954,92 +888,29 @@ impl<'a> ConstantEvaluator<'a> {
Float::F32([e]) => Ok(Float::F32([(round_ties_even(e as f64) as f32)])),
})
}
crate::MathFunction::Fract => {
component_wise_float!(self, span, [arg], |e| {
// N.B., Rust's definition of `fract` is `e - e.trunc()`, so we can't use that
// here.
Ok([e - e.floor()])
})
crate::MathFunction::Saturate => {
component_wise_float!(self, span, [arg], |e| { Ok([e.clamp(0., 1.)]) })
}
crate::MathFunction::Trunc => {
component_wise_float!(self, span, [arg], |e| { Ok([e.trunc()]) })
crate::MathFunction::Sin => {
component_wise_float!(self, span, [arg], |e| { Ok([e.sin()]) })
}
// exponent
crate::MathFunction::Exp => {
component_wise_float!(self, span, [arg], |e| { Ok([e.exp()]) })
crate::MathFunction::Sinh => {
component_wise_float!(self, span, [arg], |e| { Ok([e.sinh()]) })
}
crate::MathFunction::Exp2 => {
component_wise_float!(self, span, [arg], |e| { Ok([e.exp2()]) })
crate::MathFunction::Tan => {
component_wise_float!(self, span, [arg], |e| { Ok([e.tan()]) })
}
crate::MathFunction::Log => {
component_wise_float!(self, span, [arg], |e| { Ok([e.ln()]) })
crate::MathFunction::Tanh => {
component_wise_float!(self, span, [arg], |e| { Ok([e.tanh()]) })
}
crate::MathFunction::Log2 => {
component_wise_float!(self, span, [arg], |e| { Ok([e.log2()]) })
}
crate::MathFunction::Pow => {
component_wise_float!(self, span, [arg, arg1.unwrap()], |e1, e2| {
Ok([e1.powf(e2)])
})
}
// computational
crate::MathFunction::Sign => {
component_wise_signed!(self, span, [arg], |e| { Ok([e.signum()]) })
}
crate::MathFunction::Fma => {
component_wise_float!(
self,
span,
[arg, arg1.unwrap(), arg2.unwrap()],
|e1, e2, e3| { Ok([e1.mul_add(e2, e3)]) }
)
crate::MathFunction::Sqrt => {
component_wise_float!(self, span, [arg], |e| { Ok([e.sqrt()]) })
}
crate::MathFunction::Step => {
component_wise_float!(self, span, [arg, arg1.unwrap()], |edge, x| {
Ok([if edge <= x { 1.0 } else { 0.0 }])
})
}
crate::MathFunction::Sqrt => {
component_wise_float!(self, span, [arg], |e| { Ok([e.sqrt()]) })
}
crate::MathFunction::InverseSqrt => {
component_wise_float!(self, span, [arg], |e| { Ok([1. / e.sqrt()]) })
}
// bits
crate::MathFunction::CountTrailingZeros => {
component_wise_concrete_int!(self, span, [arg], |e| {
#[allow(clippy::useless_conversion)]
Ok([e
.trailing_zeros()
.try_into()
.expect("bit count overflowed 32 bits, somehow!?")])
})
}
crate::MathFunction::CountLeadingZeros => {
component_wise_concrete_int!(self, span, [arg], |e| {
#[allow(clippy::useless_conversion)]
Ok([e
.leading_zeros()
.try_into()
.expect("bit count overflowed 32 bits, somehow!?")])
})
}
crate::MathFunction::CountOneBits => {
component_wise_concrete_int!(self, span, [arg], |e| {
#[allow(clippy::useless_conversion)]
Ok([e
.count_ones()
.try_into()
.expect("bit count overflowed 32 bits, somehow!?")])
})
}
crate::MathFunction::ReverseBits => {
component_wise_concrete_int!(self, span, [arg], |e| { Ok([e.reverse_bits()]) })
}
fun => Err(ConstantEvaluatorError::NotImplemented(format!(
"{fun:?} built-in function"
))),

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"92c0bcfb5bf68fb55acb6e7b826ec07c1cfdd6d53b057c16a5c698e044ea228e","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","build.rs":"a99478d7f63fb41429e3834f4d0e5cd333f94ba1834c68295f929170e16987de","src/any_surface.rs":"108de0dd618beefbe18119ccc2b1d5910d6f6e16ace1c67cfd135f33f721a145","src/binding_model.rs":"b3a57236d6a554f2ef604135ba35c09ae9c99108486a3be87471c1dfd792321d","src/command/bind.rs":"a37f042484b65d9fdea4cdab3667381623ee9a8943a6d32683d410b92736d306","src/command/bundle.rs":"91513a3be0adf46a9f3454b6a3d00ff6686729eb91fe9dd6d732cbfa1ff6d1d8","src/command/clear.rs":"b20e93c4b8cb47062b38e472f78d28d9ec00fd1169b17a87094be7f9d1c995e1","src/command/compute.rs":"84c4ea6dde64893562aeddd16869ed02187145b8438775fd4419a1e6657e2b63","src/command/draw.rs":"e8a664fc248e273e8c0e4aaeb645010b3f4ec61d29d858137f31f6f653c86542","src/command/memory_init.rs":"6ec93b9e2eb21edaa534e60770b4ba95735e9de61e74d827bc492df8e3639449","src/command/mod.rs":"d6a66a5796bd824be72af2c8d3ece59a507090c61cb50e9856eb4c70a28945e2","src/command/query.rs":"dffc843746b10ba9a50b8a2b92a59b407b56a845619a96d72a5883588fcb50f0","src/command/render.rs":"e6e5eaafccdb5ea7e4c61e324ef8670ee5c7cf424bbf257e56f6f78d5b19046b","src/command/transfer.rs":"9f3d7a0500fafc4066d62f3ecbda6f9cbb9d3254a9d8fd509ed73aeb963e198c","src/conv.rs":"7e3ffe33b47a6fd3617aabf9f11cc68f1ccbee2c7343b8dbbcd0e8f3447e1ad8","src/device/any_device.rs":"f12aae9636b8634334b6e49875a8034bfcbc1db79ef898a3a19a803648be7369","src/device/bgl.rs":"292a0f07121aec78e86e0125d08785072bd4b7e763c99975b581b342ac4fcaa3","src/device/global.rs":"9e4287265a5b3a813d9c66cb8fe3c7b92d30ff07f98dfa14e79c06dc20fadc5f","src/device/life.rs":"1c6829b6d7ca9571d46282e0b3fbc4c747bfa0ef61cf57b1072998c8b1b04e9d","src/device/mod.rs":"fff41f92e1a9f6660e18dc30452d9911ca827701bb8303af2ae06f1c1e1a795f","src/device/queue.rs":"2ffc477d1bebb35a1fc8e46f4ca2c5ef50a4eb6034968f076062461b2e678699","src/device/resource.rs":"03f198d5660755dda69e770943be4f809542f61a14f16649c0151fb8ae076618","src/device/trace.rs":"9deb1b083165e07253b4928ac2f564aba06f9089c3aca1c0a1d438d87d981542","src/error.rs":"e3b6b7a69877437f4e46af7f0e8ca1db1822beae7c8448db41c2bae0f64b2bb4","src/global.rs":"0966475959706650fd036a18d51441a8e14c3ef10107db617f597614ca47e50a","src/hal_api.rs":"56ef4891dab63f834bab7a1c2ed64f71ba34d503420e1c963e5771d45f119cf5","src/hash_utils.rs":"e8d484027c7ce81978e4679a5e20af9416ab7d2fa595f1ca95992b29d625b0ca","src/hub.rs":"a180281fba7426d681eaa937b94e8f424a5f658ebfcad309ab0f0e912b4764c2","src/id.rs":"875dc5afefc6387ed5ce37253def84f15085a700e8c8f4a7ebd1a63eeded1a49","src/identity.rs":"c6a719389d71bb11c9ceaeadb0496f8b4c6ad24e35597e12b40980ad7ad72f10","src/init_tracker/buffer.rs":"61eb9cfaa312135b7a937ff6a3117f531b5b7323fae6553a41d6de9bc106d7e0","src/init_tracker/mod.rs":"43d98d2b2ebf92b3b77c5bd049c66e29a021020b2ab2c1676de56fd305b6a115","src/init_tracker/texture.rs":"030fd594bf9948fad391390d85c5e1fec7eaf67b6e812c60f2dd59bc4fda8fd5","src/instance.rs":"eed17891b58ccbf1b983e745febe815998d30a73ea712f07449b5130d50afbe5","src/lib.rs":"b2cf7a6d4acc800e12b6162c0a876e866d0e9b76ef98e90fb985eadedf6fb66d","src/pipeline.rs":"1a47caded7956da1b4f2cf22bc8a41a29941f1608ea2a58b0ac16edecce7eed0","src/pool.rs":"8c88d86763bc465bf628157c62db9641f6789ece684cc4a20a2fdf50d37e0e16","src/present.rs":"e2d6708f174df750a94f46d81b676f3ea3ee2f2c547a19717f2678ae2822d3c2","src/registry.rs":"dbc9310a24a843cf6b94a4bab78b0bb5f325e18c1f3c19c94d4f12b4f29e8598","src/resource.rs":"68ab78d4b0fa26033b750a9da02de7cb019935f9fba9a5a184a9bb6ce0332830","src/snatch.rs":"dd514e1954137eec4a0753a3670e8180796ac9c9ff770a1ca1813863debce823","src/storage.rs":"1624457eacbe27be5116fe23d2653cf609ba4fe16977daadd1a770556dbf9134","src/track/buffer.rs":"15cb7f7e4423a829d9ccd6f1cb71811a7c0aa40c32da342ad7a84f724d891ce7","src/track/metadata.rs":"c8b420da9fd491b822530c67a7de2d69c74339542a80aabb829408fb8cef7a62","src/track/mod.rs":"80739f73903b8ebd518586e22c4b6cf3f71b8a5d4435b3d0cc276beb9aa55d32","src/track/range.rs":"2a15794e79b0470d5ba6b3267173a42f34312878e1cb288f198d2854a7888e53","src/track/stateless.rs":"f3355a91716901e578b5382220f8f5ea4e38770648514b140ed8d7f895c98dea","src/track/texture.rs":"b800c4d8c19d716a9cc0d30b67c9b9a310436cda6ae4a6ff4251b4973ebe06cb","src/validation.rs":"613c58c3601f36d6aa5986cea01f30497c6bd4ceb990824904d101b2327941a9"},"package":null}
{"files":{"Cargo.toml":"8c08a31db95798345f8d6836b3f9cbe49b002362c6e4f6ac2d5ec57a4d5e067d","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","build.rs":"a99478d7f63fb41429e3834f4d0e5cd333f94ba1834c68295f929170e16987de","src/any_surface.rs":"108de0dd618beefbe18119ccc2b1d5910d6f6e16ace1c67cfd135f33f721a145","src/binding_model.rs":"3749ac3bb0fb2604729d22614c5c6983aa65f4e32dd2400f23c27db563fca664","src/command/bind.rs":"a37f042484b65d9fdea4cdab3667381623ee9a8943a6d32683d410b92736d306","src/command/bundle.rs":"095fa5c9ec22c708bd9193fcb3c87e4731cc219013e1168caad20caadb579b52","src/command/clear.rs":"437c5c9916e123d3f3905f5ac40499d9cd755b8e2fd89c4497718335faeb40ad","src/command/compute.rs":"9fd61336ca2946694d1f611d2b7b92f215a9176d88275cfab64a2ae80d264ac9","src/command/draw.rs":"25600c64b31a5fe52d8705a2102ca66b86073a99221d69c734f50be5717225a1","src/command/memory_init.rs":"6ec93b9e2eb21edaa534e60770b4ba95735e9de61e74d827bc492df8e3639449","src/command/mod.rs":"a4170bae20979fce9fbce71a82ebe22ec48ce39fc70dfbba848247e169bbde72","src/command/query.rs":"51313e41595f808b53c24a2257863a68f930bd10b0d50d306e7ea5d44115e78c","src/command/render.rs":"e59b269f5760e93b466c332340080a92cea349c9e7203d28cafe9e9d448c6aab","src/command/transfer.rs":"4798cb1cdc9829fb972b17c5bd37f5e54a0b053a96477dc79a7371e49d1facb6","src/conv.rs":"7e3ffe33b47a6fd3617aabf9f11cc68f1ccbee2c7343b8dbbcd0e8f3447e1ad8","src/device/any_device.rs":"f12aae9636b8634334b6e49875a8034bfcbc1db79ef898a3a19a803648be7369","src/device/bgl.rs":"292a0f07121aec78e86e0125d08785072bd4b7e763c99975b581b342ac4fcaa3","src/device/global.rs":"f1e1b8296a9f5254b62546062f9e37eb58616a40a367a63749fe80ba4a33ffd6","src/device/life.rs":"c409083438fd2e4bb432cc559720b8ceafeb91ef31437e308993eeff239fc94d","src/device/mod.rs":"eca2e5796eac077ce00ef1e853e881450a463404061e68475b532c01ccc0b850","src/device/queue.rs":"cef9043ca951dba20b144f37e52c23945004bf393d1e3e6f85dd35a19bacea38","src/device/resource.rs":"19c8b50fd16663b994003653f426e11894e3269cd5e486975bccbdd0d65e6df0","src/device/trace.rs":"9a8ec674567a8866a6bd1ed2ad06e474bd2504ed91f228d3040cb6db18fe5f2b","src/error.rs":"64add26c7b8f3695ac4b76dd497266b7e14b307509d4edece602c496833a6890","src/global.rs":"26e8cb27b5d8db4b4d503c3bd7d09c90a8786e8304eb6ab4f72b3546664267e5","src/hal_api.rs":"b348147701efc7daf5126e25027a2562f5866ae8289eba907f7c7d250f0fd7f0","src/hash_utils.rs":"e8d484027c7ce81978e4679a5e20af9416ab7d2fa595f1ca95992b29d625b0ca","src/hub.rs":"c2b2e575bbe0683640f3ead5ca828dee1c13fdc12a7b3e4c7fc9e716cef6dac4","src/id.rs":"2c73422b2b5f0ce4a5bc3fce79bb3d3a370cda7aa6680c2239829ffc5a85d869","src/identity.rs":"0701f6f41e754dde2bebc567a87c25b353dfab40b79a322990dbfa477739ab8c","src/init_tracker/buffer.rs":"61eb9cfaa312135b7a937ff6a3117f531b5b7323fae6553a41d6de9bc106d7e0","src/init_tracker/mod.rs":"43d98d2b2ebf92b3b77c5bd049c66e29a021020b2ab2c1676de56fd305b6a115","src/init_tracker/texture.rs":"030fd594bf9948fad391390d85c5e1fec7eaf67b6e812c60f2dd59bc4fda8fd5","src/instance.rs":"ad28cdba959eef0b72faaa2ba78c69db17e74b23a1ad2c5a359ef160786e34c8","src/lib.rs":"b90f903bc555fbdf563e6ef55672ff4292f5c6d434844e9d592fe5827c5879e1","src/pipeline.rs":"78c6d88667a1e2105356d7634cfb554998b3f3c9912d4e3abeca0eb2dd5e939b","src/pool.rs":"8c88d86763bc465bf628157c62db9641f6789ece684cc4a20a2fdf50d37e0e16","src/present.rs":"4bb768555f853d6cfb63f914520da31bc95c0000ab41ab04ff7a85e14a21454e","src/registry.rs":"c96b815b08ed7e6e3097b4de71878f4c838f07d619a60d2ba282f4ec9face934","src/resource.rs":"b6e16f95d6d131ab81451667399533429135bdb25da25433e1ce40791597372e","src/snatch.rs":"dd514e1954137eec4a0753a3670e8180796ac9c9ff770a1ca1813863debce823","src/storage.rs":"39eecf5aa0745e559985ce6b42c2eb5775ae277786f74311814eab426aa173af","src/track/buffer.rs":"c5ae73d1d84bcfb5a17c31f43de661cd0bf931e15e9fd92ad18fd31a88b05330","src/track/metadata.rs":"f8994ad91db7f3bb1b7f8b8b0f6884753d733ce28238b36f31da2230706f848e","src/track/mod.rs":"02bac3cf2e53af45f79646817e85da8e4072d576438036a44b41ce1744e02d64","src/track/range.rs":"2a15794e79b0470d5ba6b3267173a42f34312878e1cb288f198d2854a7888e53","src/track/stateless.rs":"b0a73ce9bc37afc8c3524e109749df0104229e9cfd1a040408ea59aab598113d","src/track/texture.rs":"769d87975b2fa0f6ca5794b7eaa203b2d6a00dea452783e6105ca7daf141490f","src/validation.rs":"613c58c3601f36d6aa5986cea01f30497c6bd4ceb990824904d101b2327941a9"},"package":null}

View File

@@ -49,10 +49,6 @@ rustc-hash = "1.1"
smallvec = "1"
thiserror = "1"
[dependencies.bytemuck]
version = "1.14"
optional = true
[dependencies.hal]
version = "0.19.0"
path = "../wgpu-hal"
@@ -98,28 +94,27 @@ fragile-send-sync-non-atomic-wasm = [
"wgt/fragile-send-sync-non-atomic-wasm",
]
gles = ["hal/gles"]
glsl = ["naga/glsl-in"]
link = ["hal/link"]
metal = ["hal/metal"]
renderdoc = ["hal/renderdoc"]
replay = [
"serde",
"wgt/replay",
"arrayvec/serde",
"naga/deserialize",
]
resource_log_info = []
serde = [
"dep:serde",
serial-pass = [
"serde",
"wgt/serde",
"arrayvec/serde",
]
spirv = [
"naga/spv-in",
"dep:bytemuck",
]
strict_asserts = ["wgt/strict_asserts"]
trace = [
"ron",
"serde",
"wgt/trace",
"arrayvec/serde",
"naga/serialize",
]
vulkan = ["hal/vulkan"]

View File

@@ -6,11 +6,14 @@ use crate::{
},
error::{ErrorFormatter, PrettyError},
hal_api::HalApi,
id::{BindGroupLayoutId, BufferId, SamplerId, TextureId, TextureViewId},
id::{
BindGroupId, BindGroupLayoutId, BufferId, PipelineLayoutId, SamplerId, TextureId,
TextureViewId,
},
init_tracker::{BufferInitTrackerAction, TextureInitTrackerAction},
resource::{Resource, ResourceInfo, ResourceType},
resource_log,
snatch::{SnatchGuard, Snatchable},
snatch::SnatchGuard,
track::{BindGroupStates, UsageConflict},
validation::{MissingBufferUsageError, MissingTextureUsageError},
Label,
@@ -18,9 +21,9 @@ use crate::{
use arrayvec::ArrayVec;
#[cfg(feature = "serde")]
#[cfg(feature = "replay")]
use serde::Deserialize;
#[cfg(feature = "serde")]
#[cfg(feature = "trace")]
use serde::Serialize;
use std::{borrow::Cow, ops::Range, sync::Arc};
@@ -403,7 +406,8 @@ impl BindingTypeMaxCountValidator {
/// Bindable resource and the slot to bind it to.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BindGroupEntry<'a> {
/// Slot for which binding provides resource. Corresponds to an entry of the same
/// binding index in the [`BindGroupLayoutDescriptor`].
@@ -414,7 +418,8 @@ pub struct BindGroupEntry<'a> {
/// Describes a group of bindings and the resources to be bound.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BindGroupDescriptor<'a> {
/// Debug label of the bind group.
///
@@ -428,7 +433,8 @@ pub struct BindGroupDescriptor<'a> {
/// Describes a [`BindGroupLayout`].
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct BindGroupLayoutDescriptor<'a> {
/// Debug label of the bind group layout.
///
@@ -438,7 +444,7 @@ pub struct BindGroupLayoutDescriptor<'a> {
pub entries: Cow<'a, [wgt::BindGroupLayoutEntry]>,
}
pub type BindGroupLayouts<A> = crate::storage::Storage<BindGroupLayout<A>>;
pub type BindGroupLayouts<A> = crate::storage::Storage<BindGroupLayout<A>, BindGroupLayoutId>;
/// Bind group layout.
#[derive(Debug)]
@@ -455,7 +461,7 @@ pub struct BindGroupLayout<A: HalApi> {
pub(crate) origin: bgl::Origin,
#[allow(unused)]
pub(crate) binding_count_validator: BindingTypeMaxCountValidator,
pub(crate) info: ResourceInfo<BindGroupLayout<A>>,
pub(crate) info: ResourceInfo<BindGroupLayoutId>,
pub(crate) label: String,
}
@@ -479,16 +485,14 @@ impl<A: HalApi> Drop for BindGroupLayout<A> {
}
}
impl<A: HalApi> Resource for BindGroupLayout<A> {
impl<A: HalApi> Resource<BindGroupLayoutId> for BindGroupLayout<A> {
const TYPE: ResourceType = "BindGroupLayout";
type Marker = crate::id::markers::BindGroupLayout;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<BindGroupLayoutId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<BindGroupLayoutId> {
&mut self.info
}
@@ -578,7 +582,8 @@ pub enum PushConstantUploadError {
///
/// A `PipelineLayoutDescriptor` can be used to create a pipeline layout.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PipelineLayoutDescriptor<'a> {
/// Debug label of the pipeine layout.
///
@@ -601,7 +606,7 @@ pub struct PipelineLayoutDescriptor<'a> {
pub struct PipelineLayout<A: HalApi> {
pub(crate) raw: Option<A::PipelineLayout>,
pub(crate) device: Arc<Device<A>>,
pub(crate) info: ResourceInfo<PipelineLayout<A>>,
pub(crate) info: ResourceInfo<PipelineLayoutId>,
pub(crate) bind_group_layouts: ArrayVec<Arc<BindGroupLayout<A>>, { hal::MAX_BIND_GROUPS }>,
pub(crate) push_constant_ranges: ArrayVec<wgt::PushConstantRange, { SHADER_STAGE_COUNT }>,
}
@@ -715,23 +720,22 @@ impl<A: HalApi> PipelineLayout<A> {
}
}
impl<A: HalApi> Resource for PipelineLayout<A> {
impl<A: HalApi> Resource<PipelineLayoutId> for PipelineLayout<A> {
const TYPE: ResourceType = "PipelineLayout";
type Marker = crate::id::markers::PipelineLayout;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<PipelineLayoutId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<PipelineLayoutId> {
&mut self.info
}
}
#[repr(C)]
#[derive(Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BufferBinding {
pub buffer_id: BufferId,
pub offset: wgt::BufferAddress,
@@ -741,7 +745,8 @@ pub struct BufferBinding {
// Note: Duplicated in `wgpu-rs` as `BindingResource`
// They're different enough that it doesn't make sense to share a common type
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub enum BindingResource<'a> {
Buffer(BufferBinding),
BufferArray(Cow<'a, [BufferBinding]>),
@@ -828,10 +833,10 @@ pub(crate) fn buffer_binding_type_alignment(
#[derive(Debug)]
pub struct BindGroup<A: HalApi> {
pub(crate) raw: Snatchable<A::BindGroup>,
pub(crate) raw: Option<A::BindGroup>,
pub(crate) device: Arc<Device<A>>,
pub(crate) layout: Arc<BindGroupLayout<A>>,
pub(crate) info: ResourceInfo<BindGroup<A>>,
pub(crate) info: ResourceInfo<BindGroupId>,
pub(crate) used: BindGroupStates<A>,
pub(crate) used_buffer_ranges: Vec<BufferInitTrackerAction<A>>,
pub(crate) used_texture_ranges: Vec<TextureInitTrackerAction<A>>,
@@ -869,7 +874,7 @@ impl<A: HalApi> BindGroup<A> {
for texture in &self.used_texture_ranges {
let _ = texture.texture.raw(guard)?;
}
self.raw.get(guard)
self.raw.as_ref()
}
pub(crate) fn validate_dynamic_bindings(
&self,
@@ -920,16 +925,14 @@ impl<A: HalApi> BindGroup<A> {
}
}
impl<A: HalApi> Resource for BindGroup<A> {
impl<A: HalApi> Resource<BindGroupId> for BindGroup<A> {
const TYPE: ResourceType = "BindGroup";
type Marker = crate::id::markers::BindGroup;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<BindGroupId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<BindGroupId> {
&mut self.info
}
}

View File

@@ -94,9 +94,9 @@ use crate::{
error::{ErrorFormatter, PrettyError},
hal_api::HalApi,
hub::Hub,
id,
id::{self, RenderBundleId},
init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction},
pipeline::{PipelineFlags, RenderPipeline, VertexStep},
pipeline::{self, PipelineFlags, RenderPipeline},
resource::{Resource, ResourceInfo, ResourceType},
resource_log,
track::RenderBundleScope,
@@ -110,94 +110,10 @@ use thiserror::Error;
use hal::CommandEncoder as _;
/// https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-draw
fn validate_draw(
vertex: &[Option<VertexState>],
step: &[VertexStep],
first_vertex: u32,
vertex_count: u32,
first_instance: u32,
instance_count: u32,
) -> Result<(), DrawError> {
let vertices_end = first_vertex as u64 + vertex_count as u64;
let instances_end = first_instance as u64 + instance_count as u64;
for (idx, (vbs, step)) in vertex.iter().zip(step).enumerate() {
let Some(vbs) = vbs else {
continue;
};
let stride_count = match step.mode {
wgt::VertexStepMode::Vertex => vertices_end,
wgt::VertexStepMode::Instance => instances_end,
};
if stride_count == 0 {
continue;
}
let offset = (stride_count - 1) * step.stride + step.last_stride;
let limit = vbs.range.end - vbs.range.start;
if offset > limit {
return Err(DrawError::VertexOutOfBounds {
step_mode: step.mode,
offset,
limit,
slot: idx as u32,
});
}
}
Ok(())
}
// See https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-drawindexed
fn validate_indexed_draw(
vertex: &[Option<VertexState>],
step: &[VertexStep],
index_state: &IndexState,
first_index: u32,
index_count: u32,
first_instance: u32,
instance_count: u32,
) -> Result<(), DrawError> {
let last_index = first_index as u64 + index_count as u64;
let index_limit = index_state.limit();
if last_index <= index_limit {
return Err(DrawError::IndexBeyondLimit {
last_index,
index_limit,
});
}
let stride_count = first_instance as u64 + instance_count as u64;
for (idx, (vbs, step)) in vertex.iter().zip(step).enumerate() {
let Some(vbs) = vbs else {
continue;
};
if stride_count == 0 || step.mode != wgt::VertexStepMode::Instance {
continue;
}
let offset = (stride_count - 1) * step.stride + step.last_stride;
let limit = vbs.range.end - vbs.range.start;
if offset > limit {
return Err(DrawError::VertexOutOfBounds {
step_mode: step.mode,
offset,
limit,
slot: idx as u32,
});
}
}
Ok(())
}
/// Describes a [`RenderBundleEncoder`].
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct RenderBundleEncoderDescriptor<'a> {
/// Debug label of the render bundle encoder.
///
@@ -225,7 +141,7 @@ pub struct RenderBundleEncoderDescriptor<'a> {
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
pub struct RenderBundleEncoder {
base: BasePass<RenderCommand>,
parent_id: id::DeviceId,
@@ -234,9 +150,9 @@ pub struct RenderBundleEncoder {
pub(crate) is_stencil_read_only: bool,
// Resource binding dedupe state.
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "serial-pass", serde(skip))]
current_bind_groups: BindGroupStateChange,
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "serial-pass", serde(skip))]
current_pipeline: StateChange<id::RenderPipelineId>,
}
@@ -579,21 +495,28 @@ impl RenderBundleEncoder {
};
let pipeline = state.pipeline(scope)?;
let used_bind_groups = pipeline.used_bind_groups;
validate_draw(
&state.vertex[..],
&pipeline.steps,
first_vertex,
vertex_count,
first_instance,
instance_count,
).map_pass_err(scope)?;
if instance_count > 0 && vertex_count > 0 {
commands.extend(state.flush_vertices());
commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets));
commands.push(command);
let vertex_limits = state.vertex_limits(pipeline);
let last_vertex = first_vertex as u64 + vertex_count as u64;
if last_vertex > vertex_limits.vertex_limit {
return Err(DrawError::VertexBeyondLimit {
last_vertex,
vertex_limit: vertex_limits.vertex_limit,
slot: vertex_limits.vertex_limit_slot,
})
.map_pass_err(scope);
}
let last_instance = first_instance as u64 + instance_count as u64;
if last_instance > vertex_limits.instance_limit {
return Err(DrawError::InstanceBeyondLimit {
last_instance,
instance_limit: vertex_limits.instance_limit,
slot: vertex_limits.instance_limit_slot,
})
.map_pass_err(scope);
}
commands.extend(state.flush_vertices());
commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets));
commands.push(command);
}
RenderCommand::DrawIndexed {
index_count,
@@ -613,23 +536,30 @@ impl RenderBundleEncoder {
Some(ref index) => index,
None => return Err(DrawError::MissingIndexBuffer).map_pass_err(scope),
};
validate_indexed_draw(
&state.vertex[..],
&pipeline.steps,
index,
first_index,
index_count,
first_instance,
instance_count,
).map_pass_err(scope)?;
if instance_count > 0 && index_count > 0 {
commands.extend(state.flush_index());
commands.extend(state.flush_vertices());
commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets));
commands.push(command);
//TODO: validate that base_vertex + max_index() is within the provided range
let vertex_limits = state.vertex_limits(pipeline);
let index_limit = index.limit();
let last_index = first_index as u64 + index_count as u64;
if last_index > index_limit {
return Err(DrawError::IndexBeyondLimit {
last_index,
index_limit,
})
.map_pass_err(scope);
}
let last_instance = first_instance as u64 + instance_count as u64;
if last_instance > vertex_limits.instance_limit {
return Err(DrawError::InstanceBeyondLimit {
last_instance,
instance_limit: vertex_limits.instance_limit,
slot: vertex_limits.instance_limit_slot,
})
.map_pass_err(scope);
}
commands.extend(state.flush_index());
commands.extend(state.flush_vertices());
commands.extend(state.flush_binds(used_bind_groups, base.dynamic_offsets));
commands.push(command);
}
RenderCommand::MultiDrawIndirect {
buffer_id,
@@ -832,7 +762,7 @@ pub struct RenderBundle<A: HalApi> {
pub(super) buffer_memory_init_actions: Vec<BufferInitTrackerAction<A>>,
pub(super) texture_memory_init_actions: Vec<TextureInitTrackerAction<A>>,
pub(super) context: RenderPassContext,
pub(crate) info: ResourceInfo<RenderBundle<A>>,
pub(crate) info: ResourceInfo<RenderBundleId>,
discard_hal_labels: bool,
}
@@ -1067,16 +997,14 @@ impl<A: HalApi> RenderBundle<A> {
}
}
impl<A: HalApi> Resource for RenderBundle<A> {
impl<A: HalApi> Resource<RenderBundleId> for RenderBundle<A> {
const TYPE: ResourceType = "RenderBundle";
type Marker = crate::id::markers::RenderBundle;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<RenderBundleId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<RenderBundleId> {
&mut self.info
}
}
@@ -1185,6 +1113,18 @@ struct BindState<A: HalApi> {
is_dirty: bool,
}
#[derive(Debug)]
struct VertexLimitState {
/// Length of the shortest vertex rate vertex buffer
vertex_limit: u64,
/// Buffer slot which the shortest vertex rate vertex buffer is bound to
vertex_limit_slot: u32,
/// Length of the shortest instance rate vertex buffer
instance_limit: u64,
/// Buffer slot which the shortest instance rate vertex buffer is bound to
instance_limit_slot: u32,
}
/// The bundle's current pipeline, and some cached information needed for validation.
struct PipelineState<A: HalApi> {
/// The pipeline
@@ -1192,7 +1132,7 @@ struct PipelineState<A: HalApi> {
/// How this pipeline's vertex shader traverses each vertex buffer, indexed
/// by vertex buffer slot number.
steps: Vec<VertexStep>,
steps: Vec<pipeline::VertexStep>,
/// Ranges of push constants this pipeline uses, copied from the pipeline
/// layout.
@@ -1277,6 +1217,35 @@ struct State<A: HalApi> {
}
impl<A: HalApi> State<A> {
fn vertex_limits(&self, pipeline: &PipelineState<A>) -> VertexLimitState {
let mut vert_state = VertexLimitState {
vertex_limit: u32::MAX as u64,
vertex_limit_slot: 0,
instance_limit: u32::MAX as u64,
instance_limit_slot: 0,
};
for (idx, (vbs, step)) in self.vertex.iter().zip(&pipeline.steps).enumerate() {
if let Some(ref vbs) = *vbs {
let limit = (vbs.range.end - vbs.range.start) / step.stride;
match step.mode {
wgt::VertexStepMode::Vertex => {
if limit < vert_state.vertex_limit {
vert_state.vertex_limit = limit;
vert_state.vertex_limit_slot = idx as _;
}
}
wgt::VertexStepMode::Instance => {
if limit < vert_state.instance_limit {
vert_state.instance_limit = limit;
vert_state.instance_limit_slot = idx as _;
}
}
}
}
}
vert_state
}
/// Return the id of the current pipeline, if any.
fn pipeline_id(&self) -> Option<id::RenderPipelineId> {
self.pipeline.as_ref().map(|p| p.pipeline.as_info().id())

View File

@@ -10,6 +10,7 @@ use crate::{
global::Global,
hal_api::HalApi,
id::{BufferId, CommandEncoderId, DeviceId, TextureId},
identity::GlobalIdentityHandlerFactory,
init_tracker::{MemoryInitKind, TextureInitRange},
resource::{Resource, Texture, TextureClearMode},
track::{TextureSelector, TextureTracker},
@@ -70,7 +71,7 @@ whereas subesource range specified start {subresource_base_array_layer} and coun
Device(#[from] DeviceError),
}
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn command_encoder_clear_buffer<A: HalApi>(
&self,
command_encoder_id: CommandEncoderId,

View File

@@ -18,6 +18,7 @@ use crate::{
hal_api::HalApi,
hal_label, id,
id::DeviceId,
identity::GlobalIdentityHandlerFactory,
init_tracker::MemoryInitKind,
pipeline,
resource::{self},
@@ -28,9 +29,9 @@ use crate::{
};
use hal::CommandEncoder as _;
#[cfg(feature = "serde")]
#[cfg(any(feature = "serial-pass", feature = "replay"))]
use serde::Deserialize;
#[cfg(feature = "serde")]
#[cfg(any(feature = "serial-pass", feature = "trace"))]
use serde::Serialize;
use thiserror::Error;
@@ -39,7 +40,14 @@ use std::{fmt, mem, str};
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
any(feature = "serial-pass", feature = "trace"),
derive(serde::Serialize)
)]
#[cfg_attr(
any(feature = "serial-pass", feature = "replay"),
derive(serde::Deserialize)
)]
pub enum ComputeCommand {
SetBindGroup {
index: u32,
@@ -90,16 +98,16 @@ pub enum ComputeCommand {
EndPipelineStatisticsQuery,
}
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
pub struct ComputePass {
base: BasePass<ComputeCommand>,
parent_id: id::CommandEncoderId,
timestamp_writes: Option<ComputePassTimestampWrites>,
// Resource binding dedupe state.
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "serial-pass", serde(skip))]
current_bind_groups: BindGroupStateChange,
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "serial-pass", serde(skip))]
current_pipeline: StateChange<id::ComputePipelineId>,
}
@@ -143,7 +151,8 @@ impl fmt::Debug for ComputePass {
/// Describes the writing of timestamp values in a compute pass.
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))]
pub struct ComputePassTimestampWrites {
/// The query set to write the timestamps to.
pub query_set: id::QuerySetId,
@@ -304,7 +313,7 @@ impl<A: HalApi> State<A> {
&mut self,
raw_encoder: &mut A::CommandEncoder,
base_trackers: &mut Tracker<A>,
bind_group_guard: &Storage<BindGroup<A>>,
bind_group_guard: &Storage<BindGroup<A>, id::BindGroupId>,
indirect_buffer: Option<id::BufferId>,
snatch_guard: &SnatchGuard,
) -> Result<(), UsageConflict> {
@@ -339,7 +348,7 @@ impl<A: HalApi> State<A> {
// Common routines between render/compute
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn command_encoder_run_compute_pass<A: HalApi>(
&self,
encoder_id: id::CommandEncoderId,

View File

@@ -8,7 +8,7 @@ use crate::{
track::UsageConflict,
validation::{MissingBufferUsageError, MissingTextureUsageError},
};
use wgt::{BufferAddress, BufferSize, Color, VertexStepMode};
use wgt::{BufferAddress, BufferSize, Color};
use std::num::NonZeroU32;
use thiserror::Error;
@@ -33,13 +33,6 @@ pub enum DrawError {
vertex_limit: u64,
slot: u32,
},
#[error("{step_mode:?} buffer out of bounds at slot {slot}. Offset {offset} beyond limit {limit}. Did you bind the correct `Vertex` step-rate vertex buffer?")]
VertexOutOfBounds {
step_mode: VertexStepMode,
offset: u64,
limit: u64,
slot: u32,
},
#[error("Instance {last_instance} extends beyond limit {instance_limit} imposed by the buffer in slot {slot}. Did you bind the correct `Instance` step-rate vertex buffer?")]
InstanceBeyondLimit {
last_instance: u64,
@@ -126,7 +119,14 @@ impl crate::error::PrettyError for RenderCommandError {
}
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
any(feature = "serial-pass", feature = "trace"),
derive(serde::Serialize)
)]
#[cfg_attr(
any(feature = "serial-pass", feature = "replay"),
derive(serde::Deserialize)
)]
pub struct Rect<T> {
pub x: T,
pub y: T,
@@ -136,7 +136,14 @@ pub struct Rect<T> {
#[doc(hidden)]
#[derive(Clone, Copy, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
any(feature = "serial-pass", feature = "trace"),
derive(serde::Serialize)
)]
#[cfg_attr(
any(feature = "serial-pass", feature = "replay"),
derive(serde::Deserialize)
)]
pub enum RenderCommand {
SetBindGroup {
index: u32,

View File

@@ -27,7 +27,10 @@ use crate::snatch::SnatchGuard;
use crate::init_tracker::BufferInitTrackerAction;
use crate::resource::{Resource, ResourceInfo, ResourceType};
use crate::track::{Tracker, UsageScope};
use crate::{api_log, global::Global, hal_api::HalApi, id, resource_log, Label};
use crate::{
api_log, global::Global, hal_api::HalApi, id, identity::GlobalIdentityHandlerFactory,
resource_log, Label,
};
use hal::CommandEncoder as _;
use parking_lot::Mutex;
@@ -137,7 +140,7 @@ pub struct CommandBuffer<A: HalApi> {
pub(crate) device: Arc<Device<A>>,
limits: wgt::Limits,
support_clear_texture: bool,
pub(crate) info: ResourceInfo<CommandBuffer<A>>,
pub(crate) info: ResourceInfo<CommandBufferId>,
pub(crate) data: Mutex<Option<CommandBufferMutable<A>>>,
}
@@ -252,7 +255,7 @@ impl<A: HalApi> CommandBuffer<A> {
id: id::CommandEncoderId,
) -> Result<Arc<Self>, CommandEncoderError> {
let storage = hub.command_buffers.read();
match storage.get(id.transmute()) {
match storage.get(id) {
Ok(cmd_buf) => match cmd_buf.data.lock().as_ref().unwrap().status {
CommandEncoderStatus::Recording => Ok(cmd_buf.clone()),
CommandEncoderStatus::Finished => Err(CommandEncoderError::NotRecording),
@@ -293,16 +296,14 @@ impl<A: HalApi> CommandBuffer<A> {
}
}
impl<A: HalApi> Resource for CommandBuffer<A> {
impl<A: HalApi> Resource<CommandBufferId> for CommandBuffer<A> {
const TYPE: ResourceType = "CommandBuffer";
type Marker = crate::id::markers::CommandBuffer;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<CommandBufferId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<CommandBufferId> {
&mut self.info
}
@@ -337,7 +338,14 @@ pub struct BasePassRef<'a, C> {
/// [`InsertDebugMarker`]: RenderCommand::InsertDebugMarker
#[doc(hidden)]
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(
any(feature = "serial-pass", feature = "trace"),
derive(serde::Serialize)
)]
#[cfg_attr(
any(feature = "serial-pass", feature = "replay"),
derive(serde::Deserialize)
)]
pub struct BasePass<C> {
pub label: Option<String>,
@@ -407,7 +415,7 @@ pub enum CommandEncoderError {
Device(#[from] DeviceError),
}
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn command_encoder_finish<A: HalApi>(
&self,
encoder_id: id::CommandEncoderId,
@@ -417,7 +425,7 @@ impl Global {
let hub = A::hub(self);
let error = match hub.command_buffers.get(encoder_id.transmute()) {
let error = match hub.command_buffers.get(encoder_id) {
Ok(cmd_buf) => {
let mut cmd_buf_data = cmd_buf.data.lock();
let cmd_buf_data = cmd_buf_data.as_mut().unwrap();
@@ -443,7 +451,7 @@ impl Global {
Err(_) => Some(CommandEncoderError::Invalid),
};
(encoder_id.transmute(), error)
(encoder_id, error)
}
pub fn command_encoder_push_debug_group<A: HalApi>(
@@ -699,7 +707,7 @@ impl PrettyError for PassErrorScope {
// This error is not in the error chain, only notes are needed
match *self {
Self::Pass(id) => {
fmt.command_buffer_label(&id.transmute());
fmt.command_buffer_label(&id);
}
Self::SetBindGroup(id) => {
fmt.bind_group_label(&id);

View File

@@ -7,7 +7,8 @@ use crate::{
device::DeviceError,
global::Global,
hal_api::HalApi,
id::{self, Id},
id::{self, Id, TypedId},
identity::GlobalIdentityHandlerFactory,
init_tracker::MemoryInitKind,
resource::QuerySet,
storage::Storage,
@@ -48,7 +49,7 @@ impl<A: HalApi> QueryResetMap<A> {
pub fn reset_queries(
&mut self,
raw_encoder: &mut A::CommandEncoder,
query_set_storage: &Storage<QuerySet<A>>,
query_set_storage: &Storage<QuerySet<A>, id::QuerySetId>,
backend: wgt::Backend,
) -> Result<(), id::QuerySetId> {
for (query_set_id, (state, epoch)) in self.map.drain() {
@@ -313,7 +314,7 @@ impl<A: HalApi> QuerySet<A> {
pub(super) fn end_occlusion_query<A: HalApi>(
raw_encoder: &mut A::CommandEncoder,
storage: &Storage<QuerySet<A>>,
storage: &Storage<QuerySet<A>, id::QuerySetId>,
active_query: &mut Option<(id::QuerySetId, u32)>,
) -> Result<(), QueryUseError> {
if let Some((query_set_id, query_index)) = active_query.take() {
@@ -330,7 +331,7 @@ pub(super) fn end_occlusion_query<A: HalApi>(
pub(super) fn end_pipeline_statistics_query<A: HalApi>(
raw_encoder: &mut A::CommandEncoder,
storage: &Storage<QuerySet<A>>,
storage: &Storage<QuerySet<A>, id::QuerySetId>,
active_query: &mut Option<(id::QuerySetId, u32)>,
) -> Result<(), QueryUseError> {
if let Some((query_set_id, query_index)) = active_query.take() {
@@ -345,7 +346,7 @@ pub(super) fn end_pipeline_statistics_query<A: HalApi>(
}
}
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn command_encoder_write_timestamp<A: HalApi>(
&self,
command_encoder_id: id::CommandEncoderId,

View File

@@ -1,5 +1,4 @@
use crate::resource::Resource;
use crate::snatch::SnatchGuard;
use crate::{
api_log,
binding_model::BindError,
@@ -20,6 +19,7 @@ use crate::{
global::Global,
hal_api::HalApi,
hal_label, id,
identity::GlobalIdentityHandlerFactory,
init_tracker::{MemoryInitKind, TextureInitRange, TextureInitTrackerAction},
pipeline::{self, PipelineFlags},
resource::{Buffer, QuerySet, Texture, TextureView, TextureViewNotRenderableReason},
@@ -39,9 +39,9 @@ use wgt::{
TextureViewDimension, VertexStepMode,
};
#[cfg(feature = "serde")]
#[cfg(any(feature = "serial-pass", feature = "replay"))]
use serde::Deserialize;
#[cfg(feature = "serde")]
#[cfg(any(feature = "serial-pass", feature = "trace"))]
use serde::Serialize;
use std::sync::Arc;
@@ -55,7 +55,8 @@ use super::{
/// Operation to perform to the output attachment at the start of a renderpass.
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum LoadOp {
/// Clear the output attachment with the clear color. Clearing is faster than loading.
@@ -67,7 +68,8 @@ pub enum LoadOp {
/// Operation to perform to the output attachment at the end of a renderpass.
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum StoreOp {
/// Discards the content of the render target.
@@ -81,7 +83,8 @@ pub enum StoreOp {
/// Describes an individual channel within a render pass, such as color, depth, or stencil.
#[repr(C)]
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))]
pub struct PassChannel<V> {
/// Operation to perform to the output attachment at the start of a
/// renderpass.
@@ -118,7 +121,8 @@ impl<V> PassChannel<V> {
/// Describes a color attachment to a render pass.
#[repr(C)]
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))]
pub struct RenderPassColorAttachment {
/// The view to use as an attachment.
pub view: id::TextureViewId,
@@ -131,7 +135,8 @@ pub struct RenderPassColorAttachment {
/// Describes a depth/stencil attachment to a render pass.
#[repr(C)]
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))]
pub struct RenderPassDepthStencilAttachment {
/// The view to use as an attachment.
pub view: id::TextureViewId,
@@ -182,7 +187,8 @@ impl RenderPassDepthStencilAttachment {
/// Location to write a timestamp to (beginning or end of the pass).
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum RenderPassTimestampLocation {
Beginning = 0,
@@ -192,7 +198,8 @@ pub enum RenderPassTimestampLocation {
/// Describes the writing of timestamp values in a render pass.
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "trace"), derive(Serialize))]
#[cfg_attr(any(feature = "serial-pass", feature = "replay"), derive(Deserialize))]
pub struct RenderPassTimestampWrites {
/// The query set to write the timestamp to.
pub query_set: id::QuerySetId,
@@ -216,7 +223,7 @@ pub struct RenderPassDescriptor<'a> {
pub occlusion_query_set: Option<id::QuerySetId>,
}
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serial-pass", derive(Deserialize, Serialize))]
pub struct RenderPass {
base: BasePass<RenderCommand>,
parent_id: id::CommandEncoderId,
@@ -226,9 +233,9 @@ pub struct RenderPass {
occlusion_query_set_id: Option<id::QuerySetId>,
// Resource binding dedupe state.
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "serial-pass", serde(skip))]
current_bind_groups: BindGroupStateChange,
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "serial-pass", serde(skip))]
current_pipeline: StateChange<id::RenderPipelineId>,
}
@@ -353,7 +360,6 @@ impl VertexBufferState {
total_size: 0,
step: pipeline::VertexStep {
stride: 0,
last_stride: 0,
mode: VertexStepMode::Vertex,
},
bound: false,
@@ -377,33 +383,16 @@ struct VertexState {
impl VertexState {
fn update_limits(&mut self) {
// Implements the validation from https://gpuweb.github.io/gpuweb/#dom-gpurendercommandsmixin-draw
// Except that the formula is shuffled to extract the number of vertices in order
// to carry the bulk of the computation when changing states intead of when producing
// draws. Draw calls tend to happen at a higher frequency. Here we determine vertex
// limits that can be cheaply checked for each draw call.
self.vertex_limit = u32::MAX as u64;
self.instance_limit = u32::MAX as u64;
// Ensure that the limits are always smaller than u32::MAX so that
// interger overlows can be prevented via saturating additions.
let max = u32::MAX as u64;
self.vertex_limit = max;
self.instance_limit = max;
for (idx, vbs) in self.inputs.iter().enumerate() {
if !vbs.bound {
if vbs.step.stride == 0 || !vbs.bound {
continue;
}
let limit = if vbs.total_size < vbs.step.last_stride {
// The buffer cannot fit the last vertex.
0
} else {
if vbs.step.stride == 0 {
// We already checked that the last stride fits, the same
// vertex will be repeated so this slot can accomodate any number of
// vertices.
continue;
}
// The general case.
(vbs.total_size - vbs.step.last_stride) / vbs.step.stride + 1
};
let limit = vbs.total_size / vbs.step.stride;
match vbs.step.mode {
VertexStepMode::Vertex => {
if limit < self.vertex_limit {
@@ -544,8 +533,6 @@ pub enum RenderPassErrorInner {
Encoder(#[from] CommandEncoderError),
#[error("Attachment texture view {0:?} is invalid")]
InvalidAttachment(id::TextureViewId),
#[error("Attachment texture view {0:?} is invalid")]
InvalidResolveTarget(id::TextureViewId),
#[error("The format of the depth-stencil attachment ({0:?}) is not a depth-stencil format")]
InvalidDepthStencilAttachmentFormat(wgt::TextureFormat),
#[error("The format of the {location} ({format:?}) is not resolvable")]
@@ -727,7 +714,7 @@ struct RenderAttachment<'a, A: HalApi> {
impl<A: HalApi> TextureView<A> {
fn to_render_attachment(&self, usage: hal::TextureUses) -> RenderAttachment<A> {
RenderAttachment {
texture: self.parent.clone(),
texture: self.parent.read().as_ref().unwrap().clone(),
selector: &self.selector,
usage,
}
@@ -762,7 +749,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
if channel.load_op == LoadOp::Load {
pending_discard_init_fixups.extend(texture_memory_actions.register_init_action(
&TextureInitTrackerAction {
texture: view.parent.clone(),
texture: view.parent.read().as_ref().unwrap().clone(),
range: TextureInitRange::from(view.selector.clone()),
// Note that this is needed even if the target is discarded,
kind: MemoryInitKind::NeedsInitializedMemory,
@@ -771,7 +758,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
} else if channel.store_op == StoreOp::Store {
// Clear + Store
texture_memory_actions.register_implicit_init(
&view.parent,
view.parent.read().as_ref().unwrap(),
TextureInitRange::from(view.selector.clone()),
);
}
@@ -780,7 +767,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
// discard right away be alright since the texture can't be used
// during the pass anyways
texture_memory_actions.discard(TextureSurfaceDiscard {
texture: view.parent.clone(),
texture: view.parent.read().as_ref().unwrap().clone(),
mip_level: view.selector.mips.start,
layer: view.selector.layers.start,
});
@@ -798,11 +785,10 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
trackers: &mut Tracker<A>,
texture_memory_actions: &mut CommandBufferTextureMemoryActions<A>,
pending_query_resets: &mut QueryResetMap<A>,
view_guard: &'a Storage<TextureView<A>>,
buffer_guard: &'a Storage<Buffer<A>>,
texture_guard: &'a Storage<Texture<A>>,
query_set_guard: &'a Storage<QuerySet<A>>,
snatch_guard: &SnatchGuard<'a>,
view_guard: &'a Storage<TextureView<A>, id::TextureViewId>,
buffer_guard: &'a Storage<Buffer<A>, id::BufferId>,
texture_guard: &'a Storage<Texture<A>, id::TextureId>,
query_set_guard: &'a Storage<QuerySet<A>, id::QuerySetId>,
) -> Result<Self, RenderPassErrorInner> {
profiling::scope!("RenderPassInfo::start");
@@ -950,7 +936,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
if need_init_beforehand {
pending_discard_init_fixups.extend(
texture_memory_actions.register_init_action(&TextureInitTrackerAction {
texture: view.parent.clone(),
texture: view.parent.read().as_ref().unwrap().clone(),
range: TextureInitRange::from(view.selector.clone()),
kind: MemoryInitKind::NeedsInitializedMemory,
}),
@@ -968,7 +954,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
if at.depth.store_op != at.stencil.store_op {
if !need_init_beforehand {
texture_memory_actions.register_implicit_init(
&view.parent,
view.parent.read().as_ref().unwrap(),
TextureInitRange::from(view.selector.clone()),
);
}
@@ -983,7 +969,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
} else if at.depth.store_op == StoreOp::Discard {
// Both are discarded using the regular path.
discarded_surfaces.push(TextureSurfaceDiscard {
texture: view.parent.clone(),
texture: view.parent.read().as_ref().unwrap().clone(),
mip_level: view.selector.mips.start,
layer: view.selector.layers.start,
});
@@ -1007,9 +993,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
depth_stencil = Some(hal::DepthStencilAttachment {
target: hal::Attachment {
view: view
.raw(snatch_guard)
.ok_or_else(|| RenderPassErrorInner::InvalidAttachment(view.info.id()))?,
view: view.raw(),
usage,
},
depth_ops: at.depth.hal_ops(),
@@ -1111,25 +1095,21 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
}
texture_memory_actions.register_implicit_init(
&resolve_view.parent,
resolve_view.parent.read().as_ref().unwrap(),
TextureInitRange::from(resolve_view.selector.clone()),
);
render_attachments
.push(resolve_view.to_render_attachment(hal::TextureUses::COLOR_TARGET));
hal_resolve_target = Some(hal::Attachment {
view: resolve_view.raw(snatch_guard).ok_or_else(|| {
RenderPassErrorInner::InvalidResolveTarget(resolve_view.info.id())
})?,
view: resolve_view.raw(),
usage: hal::TextureUses::COLOR_TARGET,
});
}
colors.push(Some(hal::ColorAttachment {
target: hal::Attachment {
view: color_view.raw(snatch_guard).ok_or_else(|| {
RenderPassErrorInner::InvalidAttachment(color_view.info.id())
})?,
view: color_view.raw(),
usage: hal::TextureUses::COLOR_TARGET,
},
resolve_target: hal_resolve_target,
@@ -1229,7 +1209,6 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
fn finish(
mut self,
raw: &mut A::CommandEncoder,
snatch_guard: &SnatchGuard,
) -> Result<(UsageScope<A>, SurfacesInDiscardState<A>), RenderPassErrorInner> {
profiling::scope!("RenderPassInfo::finish");
unsafe {
@@ -1277,9 +1256,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
color_attachments: &[],
depth_stencil_attachment: Some(hal::DepthStencilAttachment {
target: hal::Attachment {
view: view.raw(snatch_guard).ok_or_else(|| {
RenderPassErrorInner::InvalidAttachment(view.info.id())
})?,
view: view.raw(),
usage: hal::TextureUses::DEPTH_STENCIL_WRITE,
},
depth_ops,
@@ -1302,7 +1279,7 @@ impl<'a, A: HalApi> RenderPassInfo<'a, A> {
// Common routines between render/compute
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn command_encoder_run_render_pass<A: HalApi>(
&self,
encoder_id: id::CommandEncoderId,
@@ -1409,7 +1386,6 @@ impl Global {
&*buffer_guard,
&*texture_guard,
&*query_set_guard,
&snatch_guard,
)
.map_pass_err(pass_scope)?;
@@ -1941,14 +1917,7 @@ impl Global {
}
unsafe {
if instance_count > 0 && vertex_count > 0 {
raw.draw(
first_vertex,
vertex_count,
first_instance,
instance_count,
);
}
raw.draw(first_vertex, vertex_count, first_instance, instance_count);
}
}
RenderCommand::DrawIndexed {
@@ -1989,15 +1958,13 @@ impl Global {
}
unsafe {
if instance_count > 0 && index_count > 0 {
raw.draw_indexed(
first_index,
index_count,
base_vertex,
first_instance,
instance_count,
);
}
raw.draw_indexed(
first_index,
index_count,
base_vertex,
first_instance,
instance_count,
);
}
}
RenderCommand::MultiDrawIndirect {
@@ -2399,13 +2366,13 @@ impl Global {
log::trace!("Merging renderpass into cmd_buf {:?}", encoder_id);
let (trackers, pending_discard_init_fixups) =
info.finish(raw, &snatch_guard).map_pass_err(pass_scope)?;
info.finish(raw).map_pass_err(pass_scope)?;
encoder.close().map_pass_err(pass_scope)?;
(trackers, pending_discard_init_fixups)
};
let cmd_buf = hub.command_buffers.get(encoder_id.transmute()).unwrap();
let cmd_buf = hub.command_buffers.get(encoder_id).unwrap();
let mut cmd_buf_data = cmd_buf.data.lock();
let cmd_buf_data = cmd_buf_data.as_mut().unwrap();

View File

@@ -9,6 +9,7 @@ use crate::{
global::Global,
hal_api::HalApi,
id::{BufferId, CommandEncoderId, DeviceId, TextureId},
identity::GlobalIdentityHandlerFactory,
init_tracker::{
has_copy_partial_init_tracker_coverage, MemoryInitKind, TextureInitRange,
TextureInitTrackerAction,
@@ -553,7 +554,7 @@ fn handle_dst_texture_init<A: HalApi>(
Ok(())
}
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn command_encoder_copy_buffer_to_buffer<A: HalApi>(
&self,
command_encoder_id: CommandEncoderId,

View File

@@ -9,6 +9,7 @@ use crate::{
global::Global,
hal_api::HalApi,
id::{self, AdapterId, DeviceId, QueueId, SurfaceId},
identity::{GlobalIdentityHandlerFactory, Input},
init_tracker::TextureInitTracker,
instance::{self, Adapter, Surface},
pipeline, present,
@@ -34,7 +35,7 @@ use std::{
use super::{ImplicitPipelineIds, InvalidDevice, UserClosures};
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn adapter_is_surface_supported<A: HalApi>(
&self,
adapter_id: AdapterId,
@@ -145,12 +146,12 @@ impl Global {
&self,
device_id: DeviceId,
desc: &resource::BufferDescriptor,
id_in: Option<id::BufferId>,
id_in: Input<G, id::BufferId>,
) -> (id::BufferId, Option<CreateBufferError>) {
profiling::scope!("Device::create_buffer");
let hub = A::hub(self);
let fid = hub.buffers.prepare(id_in);
let fid = hub.buffers.prepare::<G>(id_in);
let mut to_destroy: ArrayVec<resource::Buffer<A>, 2> = ArrayVec::new();
let error = loop {
@@ -308,20 +309,20 @@ impl Global {
/// [`device_create_buffer`]: Global::device_create_buffer
/// [`usage`]: https://www.w3.org/TR/webgpu/#dom-gputexturedescriptor-usage
/// [`wgpu_types::BufferUsages`]: wgt::BufferUsages
pub fn create_buffer_error<A: HalApi>(&self, id_in: Option<id::BufferId>, label: Label) {
pub fn create_buffer_error<A: HalApi>(&self, id_in: Input<G, id::BufferId>, label: Label) {
let hub = A::hub(self);
let fid = hub.buffers.prepare(id_in);
let fid = hub.buffers.prepare::<G>(id_in);
fid.assign_error(label.borrow_or_default());
}
pub fn create_render_bundle_error<A: HalApi>(
&self,
id_in: Option<id::RenderBundleId>,
id_in: Input<G, id::RenderBundleId>,
label: Label,
) {
let hub = A::hub(self);
let fid = hub.render_bundles.prepare(id_in);
let fid = hub.render_bundles.prepare::<G>(id_in);
fid.assign_error(label.borrow_or_default());
}
@@ -329,9 +330,9 @@ impl Global {
/// Assign `id_in` an error with the given `label`.
///
/// See `create_buffer_error` for more context and explaination.
pub fn create_texture_error<A: HalApi>(&self, id_in: Option<id::TextureId>, label: Label) {
pub fn create_texture_error<A: HalApi>(&self, id_in: Input<G, id::TextureId>, label: Label) {
let hub = A::hub(self);
let fid = hub.textures.prepare(id_in);
let fid = hub.textures.prepare::<G>(id_in);
fid.assign_error(label.borrow_or_default());
}
@@ -544,13 +545,13 @@ impl Global {
&self,
device_id: DeviceId,
desc: &resource::TextureDescriptor,
id_in: Option<id::TextureId>,
id_in: Input<G, id::TextureId>,
) -> (id::TextureId, Option<resource::CreateTextureError>) {
profiling::scope!("Device::create_texture");
let hub = A::hub(self);
let fid = hub.textures.prepare(id_in);
let fid = hub.textures.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(device_id) {
@@ -598,13 +599,13 @@ impl Global {
hal_texture: A::Texture,
device_id: DeviceId,
desc: &resource::TextureDescriptor,
id_in: Option<id::TextureId>,
id_in: Input<G, id::TextureId>,
) -> (id::TextureId, Option<resource::CreateTextureError>) {
profiling::scope!("Device::create_texture_from_hal");
let hub = A::hub(self);
let fid = hub.textures.prepare(id_in);
let fid = hub.textures.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(device_id) {
@@ -645,7 +646,7 @@ impl Global {
RwLock::new(TextureInitTracker::new(desc.mip_level_count, 0));
let (id, resource) = fid.assign(texture);
api_log!("Device::create_texture({desc:?}) -> {id:?}");
api_log!("Device::create_texture -> {id:?}");
device.trackers.lock().textures.insert_single(
id,
@@ -672,12 +673,12 @@ impl Global {
hal_buffer: A::Buffer,
device_id: DeviceId,
desc: &resource::BufferDescriptor,
id_in: Option<id::BufferId>,
id_in: Input<G, id::BufferId>,
) -> (id::BufferId, Option<CreateBufferError>) {
profiling::scope!("Device::create_buffer");
let hub = A::hub(self);
let fid = hub.buffers.prepare(id_in);
let fid = hub.buffers.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(device_id) {
@@ -782,13 +783,13 @@ impl Global {
&self,
texture_id: id::TextureId,
desc: &resource::TextureViewDescriptor,
id_in: Option<id::TextureViewId>,
id_in: Input<G, id::TextureViewId>,
) -> (id::TextureViewId, Option<resource::CreateTextureViewError>) {
profiling::scope!("Texture::create_view");
let hub = A::hub(self);
let fid = hub.texture_views.prepare(id_in);
let fid = hub.texture_views.prepare::<G>(id_in);
let error = loop {
let texture = match hub.textures.get(texture_id) {
@@ -817,12 +818,6 @@ impl Global {
};
let (id, resource) = fid.assign(view);
{
let mut views = texture.views.lock();
views.push(Arc::downgrade(&resource));
}
api_log!("Texture::create_view({texture_id:?}) -> {id:?}");
device.trackers.lock().views.insert_single(id, resource);
return (id, None);
@@ -872,12 +867,12 @@ impl Global {
&self,
device_id: DeviceId,
desc: &resource::SamplerDescriptor,
id_in: Option<id::SamplerId>,
id_in: Input<G, id::SamplerId>,
) -> (id::SamplerId, Option<resource::CreateSamplerError>) {
profiling::scope!("Device::create_sampler");
let hub = A::hub(self);
let fid = hub.samplers.prepare(id_in);
let fid = hub.samplers.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(device_id) {
@@ -933,7 +928,7 @@ impl Global {
&self,
device_id: DeviceId,
desc: &binding_model::BindGroupLayoutDescriptor,
id_in: Option<id::BindGroupLayoutId>,
id_in: Input<G, id::BindGroupLayoutId>,
) -> (
id::BindGroupLayoutId,
Option<binding_model::CreateBindGroupLayoutError>,
@@ -941,7 +936,7 @@ impl Global {
profiling::scope!("Device::create_bind_group_layout");
let hub = A::hub(self);
let fid = hub.bind_group_layouts.prepare(id_in);
let fid = hub.bind_group_layouts.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(device_id) {
@@ -1003,7 +998,7 @@ impl Global {
return (id.unwrap(), None);
};
let fid = hub.bind_group_layouts.prepare(id_in);
let fid = hub.bind_group_layouts.prepare::<G>(id_in);
let id = fid.assign_error(desc.label.borrow_or_default());
(id, Some(error))
}
@@ -1032,7 +1027,7 @@ impl Global {
&self,
device_id: DeviceId,
desc: &binding_model::PipelineLayoutDescriptor,
id_in: Option<id::PipelineLayoutId>,
id_in: Input<G, id::PipelineLayoutId>,
) -> (
id::PipelineLayoutId,
Option<binding_model::CreatePipelineLayoutError>,
@@ -1040,7 +1035,7 @@ impl Global {
profiling::scope!("Device::create_pipeline_layout");
let hub = A::hub(self);
let fid = hub.pipeline_layouts.prepare(id_in);
let fid = hub.pipeline_layouts.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(device_id) {
@@ -1093,12 +1088,12 @@ impl Global {
&self,
device_id: DeviceId,
desc: &binding_model::BindGroupDescriptor,
id_in: Option<id::BindGroupId>,
id_in: Input<G, id::BindGroupId>,
) -> (id::BindGroupId, Option<binding_model::CreateBindGroupError>) {
profiling::scope!("Device::create_bind_group");
let hub = A::hub(self);
let fid = hub.bind_groups.prepare(id_in);
let fid = hub.bind_groups.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(device_id) {
@@ -1129,15 +1124,6 @@ impl Global {
};
let (id, resource) = fid.assign(bind_group);
let weak_ref = Arc::downgrade(&resource);
for range in &resource.used_texture_ranges {
range.texture.bind_groups.lock().push(weak_ref.clone());
}
for range in &resource.used_buffer_ranges {
range.buffer.bind_groups.lock().push(weak_ref.clone());
}
api_log!("Device::create_bind_group -> {id:?}");
device
@@ -1177,7 +1163,7 @@ impl Global {
device_id: DeviceId,
desc: &pipeline::ShaderModuleDescriptor,
source: pipeline::ShaderModuleSource,
id_in: Option<id::ShaderModuleId>,
id_in: Input<G, id::ShaderModuleId>,
) -> (
id::ShaderModuleId,
Option<pipeline::CreateShaderModuleError>,
@@ -1185,7 +1171,7 @@ impl Global {
profiling::scope!("Device::create_shader_module");
let hub = A::hub(self);
let fid = hub.shader_modules.prepare(id_in);
let fid = hub.shader_modules.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(device_id) {
@@ -1203,14 +1189,6 @@ impl Global {
pipeline::ShaderModuleSource::Wgsl(ref code) => {
trace.make_binary("wgsl", code.as_bytes())
}
#[cfg(feature = "glsl")]
pipeline::ShaderModuleSource::Glsl(ref code, _) => {
trace.make_binary("glsl", code.as_bytes())
}
#[cfg(feature = "spirv")]
pipeline::ShaderModuleSource::SpirV(ref code, _) => {
trace.make_binary("spirv", bytemuck::cast_slice::<u32, u8>(code))
}
pipeline::ShaderModuleSource::Naga(ref module) => {
let string =
ron::ser::to_string_pretty(module, ron::ser::PrettyConfig::default())
@@ -1255,7 +1233,7 @@ impl Global {
device_id: DeviceId,
desc: &pipeline::ShaderModuleDescriptor,
source: Cow<[u32]>,
id_in: Option<id::ShaderModuleId>,
id_in: Input<G, id::ShaderModuleId>,
) -> (
id::ShaderModuleId,
Option<pipeline::CreateShaderModuleError>,
@@ -1263,7 +1241,7 @@ impl Global {
profiling::scope!("Device::create_shader_module");
let hub = A::hub(self);
let fid = hub.shader_modules.prepare(id_in);
let fid = hub.shader_modules.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(device_id) {
@@ -1317,12 +1295,12 @@ impl Global {
&self,
device_id: DeviceId,
desc: &wgt::CommandEncoderDescriptor<Label>,
id_in: Option<id::CommandEncoderId>,
id_in: Input<G, id::CommandEncoderId>,
) -> (id::CommandEncoderId, Option<DeviceError>) {
profiling::scope!("Device::create_command_encoder");
let hub = A::hub(self);
let fid = hub.command_buffers.prepare(id_in.map(|id| id.transmute()));
let fid = hub.command_buffers.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(device_id) {
@@ -1358,11 +1336,11 @@ impl Global {
let (id, _) = fid.assign(command_buffer);
api_log!("Device::create_command_encoder -> {id:?}");
return (id.transmute(), None);
return (id, None);
};
let id = fid.assign_error(desc.label.borrow_or_default());
(id.transmute(), Some(error))
(id, Some(error))
}
pub fn command_buffer_label<A: HalApi>(&self, id: id::CommandBufferId) -> String {
@@ -1375,10 +1353,7 @@ impl Global {
let hub = A::hub(self);
if let Some(cmd_buf) = hub
.command_buffers
.unregister(command_encoder_id.transmute())
{
if let Some(cmd_buf) = hub.command_buffers.unregister(command_encoder_id) {
cmd_buf
.device
.untrack(&cmd_buf.data.lock().as_ref().unwrap().trackers);
@@ -1388,7 +1363,7 @@ impl Global {
pub fn command_buffer_drop<A: HalApi>(&self, command_buffer_id: id::CommandBufferId) {
profiling::scope!("CommandBuffer::drop");
api_log!("CommandBuffer::drop {command_buffer_id:?}");
self.command_encoder_drop::<A>(command_buffer_id.transmute())
self.command_encoder_drop::<A>(command_buffer_id)
}
pub fn device_create_render_bundle_encoder(
@@ -1396,7 +1371,7 @@ impl Global {
device_id: DeviceId,
desc: &command::RenderBundleEncoderDescriptor,
) -> (
*mut command::RenderBundleEncoder,
id::RenderBundleEncoderId,
Option<command::CreateRenderBundleError>,
) {
profiling::scope!("Device::create_render_bundle_encoder");
@@ -1412,13 +1387,13 @@ impl Global {
&self,
bundle_encoder: command::RenderBundleEncoder,
desc: &command::RenderBundleDescriptor,
id_in: Option<id::RenderBundleId>,
id_in: Input<G, id::RenderBundleId>,
) -> (id::RenderBundleId, Option<command::RenderBundleError>) {
profiling::scope!("RenderBundleEncoder::finish");
let hub = A::hub(self);
let fid = hub.render_bundles.prepare(id_in);
let fid = hub.render_bundles.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(bundle_encoder.parent()) {
@@ -1482,12 +1457,12 @@ impl Global {
&self,
device_id: DeviceId,
desc: &resource::QuerySetDescriptor,
id_in: Option<id::QuerySetId>,
id_in: Input<G, id::QuerySetId>,
) -> (id::QuerySetId, Option<resource::CreateQuerySetError>) {
profiling::scope!("Device::create_query_set");
let hub = A::hub(self);
let fid = hub.query_sets.prepare(id_in);
let fid = hub.query_sets.prepare::<G>(id_in);
let error = loop {
let device = match hub.devices.get(device_id) {
@@ -1556,8 +1531,8 @@ impl Global {
&self,
device_id: DeviceId,
desc: &pipeline::RenderPipelineDescriptor,
id_in: Option<id::RenderPipelineId>,
implicit_pipeline_ids: Option<ImplicitPipelineIds<'_>>,
id_in: Input<G, id::RenderPipelineId>,
implicit_pipeline_ids: Option<ImplicitPipelineIds<G>>,
) -> (
id::RenderPipelineId,
Option<pipeline::CreateRenderPipelineError>,
@@ -1566,7 +1541,7 @@ impl Global {
let hub = A::hub(self);
let fid = hub.render_pipelines.prepare(id_in);
let fid = hub.render_pipelines.prepare::<G>(id_in);
let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub));
let implicit_error_context = implicit_context.clone();
@@ -1635,7 +1610,7 @@ impl Global {
&self,
pipeline_id: id::RenderPipelineId,
index: u32,
id_in: Option<id::BindGroupLayoutId>,
id_in: Input<G, id::BindGroupLayoutId>,
) -> (
id::BindGroupLayoutId,
Option<binding_model::GetBindGroupLayoutError>,
@@ -1648,7 +1623,10 @@ impl Global {
Err(_) => break binding_model::GetBindGroupLayoutError::InvalidPipeline,
};
let id = match pipeline.layout.bind_group_layouts.get(index as usize) {
Some(bg) => hub.bind_group_layouts.prepare(id_in).assign_existing(bg),
Some(bg) => hub
.bind_group_layouts
.prepare::<G>(id_in)
.assign_existing(bg),
None => break binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index),
};
return (id, None);
@@ -1656,7 +1634,7 @@ impl Global {
let id = hub
.bind_group_layouts
.prepare(id_in)
.prepare::<G>(id_in)
.assign_error("<derived>");
(id, Some(error))
}
@@ -1691,8 +1669,8 @@ impl Global {
&self,
device_id: DeviceId,
desc: &pipeline::ComputePipelineDescriptor,
id_in: Option<id::ComputePipelineId>,
implicit_pipeline_ids: Option<ImplicitPipelineIds<'_>>,
id_in: Input<G, id::ComputePipelineId>,
implicit_pipeline_ids: Option<ImplicitPipelineIds<G>>,
) -> (
id::ComputePipelineId,
Option<pipeline::CreateComputePipelineError>,
@@ -1701,7 +1679,7 @@ impl Global {
let hub = A::hub(self);
let fid = hub.compute_pipelines.prepare(id_in);
let fid = hub.compute_pipelines.prepare::<G>(id_in);
let implicit_context = implicit_pipeline_ids.map(|ipi| ipi.prepare(hub));
let implicit_error_context = implicit_context.clone();
@@ -1765,7 +1743,7 @@ impl Global {
&self,
pipeline_id: id::ComputePipelineId,
index: u32,
id_in: Option<id::BindGroupLayoutId>,
id_in: Input<G, id::BindGroupLayoutId>,
) -> (
id::BindGroupLayoutId,
Option<binding_model::GetBindGroupLayoutError>,
@@ -1779,7 +1757,10 @@ impl Global {
};
let id = match pipeline.layout.bind_group_layouts.get(index as usize) {
Some(bg) => hub.bind_group_layouts.prepare(id_in).assign_existing(bg),
Some(bg) => hub
.bind_group_layouts
.prepare::<G>(id_in)
.assign_existing(bg),
None => break binding_model::GetBindGroupLayoutError::InvalidGroupIndex(index),
};
@@ -1788,7 +1769,7 @@ impl Global {
let id = hub
.bind_group_layouts
.prepare(id_in)
.prepare::<G>(id_in)
.assign_error("<derived>");
(id, Some(error))
}
@@ -2114,7 +2095,7 @@ impl Global {
let (closures, queue_empty) = {
if let wgt::Maintain::WaitForSubmissionIndex(submission_index) = maintain {
if submission_index.queue_id != device_id.transmute() {
if submission_index.queue_id != device_id {
return Err(WaitIdleError::WrongSubmissionIndex(
submission_index.queue_id,
device_id,
@@ -2248,7 +2229,7 @@ impl Global {
if let Some(device) = hub.devices.unregister(device_id) {
let device_lost_closure = device.lock_life().device_lost_closure.take();
if let Some(closure) = device_lost_closure {
closure.call(DeviceLostReason::Dropped, String::from("Device dropped."));
closure.call(DeviceLostReason::Unknown, String::from("Device dropped."));
}
// The things `Device::prepare_to_die` takes care are mostly
@@ -2266,8 +2247,8 @@ impl Global {
}
}
// This closure will be called exactly once during "lose the device",
// or when it is replaced.
// This closure will be called exactly once during "lose the device"
// or when the device is dropped, if it was never lost.
pub fn device_set_device_lost_closure<A: HalApi>(
&self,
device_id: DeviceId,
@@ -2277,12 +2258,6 @@ impl Global {
if let Ok(device) = hub.devices.get(device_id) {
let mut life_tracker = device.lock_life();
if let Some(existing_closure) = life_tracker.device_lost_closure.take() {
// It's important to not hold the lock while calling the closure.
drop(life_tracker);
existing_closure.call(DeviceLostReason::ReplacedCallback, "".to_string());
life_tracker = device.lock_life();
}
life_tracker.device_lost_closure = Some(device_lost_closure);
}
}
@@ -2339,7 +2314,7 @@ impl Global {
range: Range<BufferAddress>,
op: BufferMapOperation,
) -> BufferAccessResult {
api_log!("Buffer::map_async {buffer_id:?} range {range:?} op: {op:?}");
api_log!("Buffer::map_async {buffer_id:?}");
// User callbacks must not be called while holding buffer_map_async_inner's locks, so we
// defer the error callback if it needs to be called immediately (typically when running
@@ -2466,7 +2441,7 @@ impl Global {
size: Option<BufferAddress>,
) -> Result<(*mut u8, u64), BufferAccessError> {
profiling::scope!("Buffer::get_mapped_range");
api_log!("Buffer::get_mapped_range {buffer_id:?} offset {offset:?} size {size:?}");
api_log!("Buffer::get_mapped_range {buffer_id:?}");
let hub = A::hub(self);

View File

@@ -7,7 +7,7 @@ use crate::{
},
hal_api::HalApi,
id::{
self, BindGroupId, BindGroupLayoutId, BufferId, ComputePipelineId, Id, PipelineLayoutId,
self, BindGroupId, BindGroupLayoutId, BufferId, ComputePipelineId, PipelineLayoutId,
QuerySetId, RenderBundleId, RenderPipelineId, SamplerId, StagingBufferId, TextureId,
TextureViewId,
},
@@ -419,14 +419,15 @@ impl<A: HalApi> LifetimeTracker<A> {
}
impl<A: HalApi> LifetimeTracker<A> {
fn triage_resources<R>(
resources_map: &mut FastHashMap<Id<R::Marker>, Arc<R>>,
fn triage_resources<Id, R>(
resources_map: &mut FastHashMap<Id, Arc<R>>,
active: &mut [ActiveSubmission<A>],
trackers: &mut impl ResourceTracker<R>,
get_resource_map: impl Fn(&mut ResourceMaps<A>) -> &mut FastHashMap<Id<R::Marker>, Arc<R>>,
trackers: &mut impl ResourceTracker<Id, R>,
get_resource_map: impl Fn(&mut ResourceMaps<A>) -> &mut FastHashMap<Id, Arc<R>>,
) -> Vec<Arc<R>>
where
R: Resource,
Id: id::TypedId,
R: Resource<Id>,
{
let mut removed_resources = Vec::new();
resources_map.retain(|&id, resource| {
@@ -524,12 +525,20 @@ impl<A: HalApi> LifetimeTracker<A> {
fn triage_suspected_texture_views(&mut self, trackers: &Mutex<Tracker<A>>) -> &mut Self {
let mut trackers = trackers.lock();
let resource_map = &mut self.suspected_resources.texture_views;
Self::triage_resources(
let mut removed_resources = Self::triage_resources(
resource_map,
self.active.as_mut_slice(),
&mut trackers.views,
|maps| &mut maps.texture_views,
);
removed_resources.drain(..).for_each(|texture_view| {
let mut lock = texture_view.parent.write();
if let Some(parent_texture) = lock.take() {
self.suspected_resources
.textures
.insert(parent_texture.as_info().id(), parent_texture);
}
});
self
}
@@ -828,4 +837,47 @@ impl<A: HalApi> LifetimeTracker<A> {
}
pending_callbacks
}
pub(crate) fn release_gpu_resources(&mut self) {
// This is called when the device is lost, which makes every associated
// resource invalid and unusable. This is an opportunity to release all of
// the underlying gpu resources, even though the objects remain visible to
// the user agent. We purge this memory naturally when resources have been
// moved into the appropriate buckets, so this function just needs to
// initiate movement into those buckets, and it can do that by calling
// "destroy" on all the resources we know about which aren't already marked
// for cleanup.
// During these iterations, we discard all errors. We don't care!
// Destroy all the mapped buffers.
for buffer in &self.mapped {
let _ = buffer.destroy();
}
// Destroy all the unmapped buffers.
for buffer in &self.ready_to_map {
let _ = buffer.destroy();
}
// Destroy all the future_suspected_buffers.
for buffer in &self.future_suspected_buffers {
let _ = buffer.destroy();
}
// Destroy the buffers in all active submissions.
for submission in &self.active {
for buffer in &submission.mapped {
let _ = buffer.destroy();
}
}
// Destroy all the future_suspected_textures.
// TODO: texture.destroy is not implemented
/*
for texture in &self.future_suspected_textures {
let _ = texture.destroy();
}
*/
}
}

View File

@@ -2,7 +2,8 @@ use crate::{
binding_model,
hal_api::HalApi,
hub::Hub,
id::{BindGroupLayoutId, PipelineLayoutId},
id::{self},
identity::{GlobalIdentityHandlerFactory, Input},
resource::{Buffer, BufferAccessResult},
resource::{BufferAccessError, BufferMapOperation},
resource_log, Label, DOWNLEVEL_ERROR_MESSAGE,
@@ -41,14 +42,15 @@ pub type DeviceDescriptor<'a> = wgt::DeviceDescriptor<Label<'a>>;
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub enum HostMap {
Read,
Write,
}
#[derive(Clone, Debug, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
pub(crate) struct AttachmentData<T> {
pub colors: ArrayVec<Option<T>, { hal::MAX_COLOR_ATTACHMENTS }>,
pub resolves: ArrayVec<T, { hal::MAX_COLOR_ATTACHMENTS }>,
@@ -72,7 +74,7 @@ pub enum RenderPassCompatibilityCheckType {
}
#[derive(Clone, Debug, Hash, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
pub(crate) struct RenderPassContext {
pub attachments: AttachmentData<TextureFormat>,
pub sample_count: u32,
@@ -455,25 +457,26 @@ pub struct MissingFeatures(pub wgt::Features);
pub struct MissingDownlevelFlags(pub wgt::DownlevelFlags);
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ImplicitPipelineContext {
pub root_id: PipelineLayoutId,
pub group_ids: ArrayVec<BindGroupLayoutId, { hal::MAX_BIND_GROUPS }>,
pub root_id: id::PipelineLayoutId,
pub group_ids: ArrayVec<id::BindGroupLayoutId, { hal::MAX_BIND_GROUPS }>,
}
pub struct ImplicitPipelineIds<'a> {
pub root_id: Option<PipelineLayoutId>,
pub group_ids: &'a [Option<BindGroupLayoutId>],
pub struct ImplicitPipelineIds<'a, G: GlobalIdentityHandlerFactory> {
pub root_id: Input<G, id::PipelineLayoutId>,
pub group_ids: &'a [Input<G, id::BindGroupLayoutId>],
}
impl ImplicitPipelineIds<'_> {
impl<G: GlobalIdentityHandlerFactory> ImplicitPipelineIds<'_, G> {
fn prepare<A: HalApi>(self, hub: &Hub<A>) -> ImplicitPipelineContext {
ImplicitPipelineContext {
root_id: hub.pipeline_layouts.prepare(self.root_id).into_id(),
root_id: hub.pipeline_layouts.prepare::<G>(self.root_id).into_id(),
group_ids: self
.group_ids
.iter()
.map(|id_in| hub.bind_group_layouts.prepare(*id_in).into_id())
.map(|id_in| hub.bind_group_layouts.prepare::<G>(*id_in).into_id())
.collect(),
}
}

View File

@@ -13,6 +13,7 @@ use crate::{
hal_api::HalApi,
hal_label,
id::{self, QueueId},
identity::{GlobalIdentityHandlerFactory, Input},
init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange},
resource::{
Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, DestroyedTexture, Resource,
@@ -23,7 +24,6 @@ use crate::{
use hal::{CommandEncoder as _, Device as _, Queue as _};
use parking_lot::Mutex;
use smallvec::SmallVec;
use std::{
iter, mem, ptr,
@@ -36,19 +36,17 @@ use super::Device;
pub struct Queue<A: HalApi> {
pub device: Option<Arc<Device<A>>>,
pub raw: Option<A::Queue>,
pub info: ResourceInfo<Queue<A>>,
pub info: ResourceInfo<QueueId>,
}
impl<A: HalApi> Resource for Queue<A> {
impl<A: HalApi> Resource<QueueId> for Queue<A> {
const TYPE: ResourceType = "Queue";
type Marker = crate::id::markers::Queue;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<QueueId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<QueueId> {
&mut self.info
}
}
@@ -229,18 +227,18 @@ impl<A: HalApi> PendingWrites<A> {
.push(TempResource::StagingBuffer(buffer));
}
fn pre_submit(&mut self) -> Result<Option<&A::CommandBuffer>, DeviceError> {
#[must_use]
fn pre_submit(&mut self) -> Option<&A::CommandBuffer> {
self.dst_buffers.clear();
self.dst_textures.clear();
if self.is_active {
let cmd_buf = unsafe { self.command_encoder.end_encoding()? };
let cmd_buf = unsafe { self.command_encoder.end_encoding().unwrap() };
self.is_active = false;
self.executing_command_buffers.push(cmd_buf);
return Ok(self.executing_command_buffers.last());
self.executing_command_buffers.last()
} else {
None
}
Ok(None)
}
#[must_use]
@@ -363,7 +361,7 @@ pub enum QueueSubmitError {
//TODO: move out common parts of write_xxx.
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn queue_write_buffer<A: HalApi>(
&self,
queue_id: QueueId,
@@ -437,7 +435,7 @@ impl Global {
&self,
queue_id: QueueId,
buffer_size: wgt::BufferSize,
id_in: Option<id::StagingBufferId>,
id_in: Input<G, id::StagingBufferId>,
) -> Result<(id::StagingBufferId, *mut u8), QueueWriteError> {
profiling::scope!("Queue::create_staging_buffer");
let hub = A::hub(self);
@@ -452,7 +450,7 @@ impl Global {
let (staging_buffer, staging_buffer_ptr) =
prepare_staging_buffer(device, buffer_size.get(), device.instance_flags)?;
let fid = hub.staging_buffers.prepare(id_in);
let fid = hub.staging_buffers.prepare::<G>(id_in);
let (id, _) = fid.assign(staging_buffer);
resource_log!("Queue::create_staging_buffer {id:?}");
@@ -670,7 +668,7 @@ impl Global {
.get(destination.texture)
.map_err(|_| TransferError::InvalidTexture(destination.texture))?;
if dst.device.as_info().id() != queue_id.transmute() {
if dst.device.as_info().id() != queue_id {
return Err(DeviceError::WrongDevice.into());
}
@@ -1117,13 +1115,10 @@ impl Global {
.fetch_add(1, Ordering::Relaxed)
+ 1;
let mut active_executions = Vec::new();
let mut used_surface_textures = track::TextureUsageScope::new();
let snatch_guard = device.snatchable_lock.read();
let mut submit_surface_textures_owned = SmallVec::<[_; 2]>::new();
{
let mut command_buffer_guard = hub.command_buffers.write();
@@ -1151,7 +1146,7 @@ impl Global {
Err(_) => continue,
};
if cmdbuf.device.as_info().id() != queue_id.transmute() {
if cmdbuf.device.as_info().id() != queue_id {
return Err(DeviceError::WrongDevice.into());
}
@@ -1222,17 +1217,8 @@ impl Global {
return Err(QueueSubmitError::DestroyedTexture(id));
}
Some(TextureInner::Native { .. }) => false,
Some(TextureInner::Surface {
ref has_work,
ref raw,
..
}) => {
Some(TextureInner::Surface { ref has_work, .. }) => {
has_work.store(true, Ordering::Relaxed);
if raw.is_some() {
submit_surface_textures_owned.push(texture.clone());
}
true
}
};
@@ -1423,17 +1409,8 @@ impl Global {
return Err(QueueSubmitError::DestroyedTexture(id));
}
Some(TextureInner::Native { .. }) => {}
Some(TextureInner::Surface {
ref has_work,
ref raw,
..
}) => {
Some(TextureInner::Surface { ref has_work, .. }) => {
has_work.store(true, Ordering::Relaxed);
if raw.is_some() {
submit_surface_textures_owned.push(texture.clone());
}
unsafe {
used_surface_textures
.merge_single(texture, None, hal::TextureUses::PRESENT)
@@ -1464,7 +1441,7 @@ impl Global {
}
let refs = pending_writes
.pre_submit()?
.pre_submit()
.into_iter()
.chain(
active_executions
@@ -1472,23 +1449,12 @@ impl Global {
.flat_map(|pool_execution| pool_execution.cmd_buffers.iter()),
)
.collect::<Vec<_>>();
let mut submit_surface_textures =
SmallVec::<[_; 2]>::with_capacity(submit_surface_textures_owned.len());
for texture in &submit_surface_textures_owned {
submit_surface_textures.extend(match texture.inner.get(&snatch_guard) {
Some(TextureInner::Surface { raw, .. }) => raw.as_ref(),
_ => None,
});
}
unsafe {
queue
.raw
.as_ref()
.unwrap()
.submit(&refs, &submit_surface_textures, Some((fence, submit_index)))
.submit(&refs, Some((fence, submit_index)))
.map_err(DeviceError::from)?;
}

View File

@@ -12,7 +12,7 @@ use crate::{
hal_api::HalApi,
hal_label,
hub::Hub,
id::QueueId,
id::{self, DeviceId, QueueId},
init_tracker::{
BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange,
TextureInitTracker, TextureInitTrackerAction,
@@ -90,7 +90,7 @@ pub struct Device<A: HalApi> {
pub(crate) queue_id: RwLock<Option<QueueId>>,
queue_to_drop: RwLock<Option<A::Queue>>,
pub(crate) zero_buffer: Option<A::Buffer>,
pub(crate) info: ResourceInfo<Device<A>>,
pub(crate) info: ResourceInfo<DeviceId>,
pub(crate) command_allocator: Mutex<Option<CommandAllocator<A>>>,
//Note: The submission index here corresponds to the last submission that is done.
@@ -380,7 +380,7 @@ impl<A: HalApi> Device<A> {
let mut device_lost_invocations = SmallVec::new();
if !self.is_valid() && life_tracker.queue_empty() {
// We can release gpu resources associated with this device.
self.release_gpu_resources();
life_tracker.release_gpu_resources();
// If we have a DeviceLostClosure, build an invocation with the
// reason DeviceLostReason::Destroyed and no message.
@@ -566,7 +566,6 @@ impl<A: HalApi> Device<A> {
sync_mapped_writes: Mutex::new(None),
map_state: Mutex::new(resource::BufferMapState::Idle),
info: ResourceInfo::new(desc.label.borrow_or_default()),
bind_groups: Mutex::new(Vec::new()),
})
}
@@ -596,8 +595,6 @@ impl<A: HalApi> Device<A> {
},
info: ResourceInfo::new(desc.label.borrow_or_default()),
clear_mode: RwLock::new(clear_mode),
views: Mutex::new(Vec::new()),
bind_groups: Mutex::new(Vec::new()),
}
}
@@ -617,7 +614,6 @@ impl<A: HalApi> Device<A> {
sync_mapped_writes: Mutex::new(None),
map_state: Mutex::new(resource::BufferMapState::Idle),
info: ResourceInfo::new(desc.label.borrow_or_default()),
bind_groups: Mutex::new(Vec::new()),
}
}
@@ -1181,8 +1177,8 @@ impl<A: HalApi> Device<A> {
};
Ok(TextureView {
raw: Snatchable::new(raw),
parent: texture.clone(),
raw: Some(raw),
parent: RwLock::new(Some(texture.clone())),
device: self.clone(),
desc: resource::HalTextureViewDescriptor {
texture_format: texture.desc.format,
@@ -1313,7 +1309,7 @@ impl<A: HalApi> Device<A> {
let (module, source) = match source {
#[cfg(feature = "wgsl")]
pipeline::ShaderModuleSource::Wgsl(code) => {
profiling::scope!("naga::front::wgsl::parse_str");
profiling::scope!("naga::wgsl::parse_str");
let module = naga::front::wgsl::parse_str(&code).map_err(|inner| {
pipeline::CreateShaderModuleError::Parsing(pipeline::ShaderError {
source: code.to_string(),
@@ -1323,32 +1319,6 @@ impl<A: HalApi> Device<A> {
})?;
(Cow::Owned(module), code.into_owned())
}
#[cfg(feature = "spirv")]
pipeline::ShaderModuleSource::SpirV(spv, options) => {
let parser = naga::front::spv::Frontend::new(spv.iter().cloned(), &options);
profiling::scope!("naga::front::spv::Frontend");
let module = parser.parse().map_err(|inner| {
pipeline::CreateShaderModuleError::ParsingSpirV(pipeline::ShaderError {
source: String::new(),
label: desc.label.as_ref().map(|l| l.to_string()),
inner: Box::new(inner),
})
})?;
(Cow::Owned(module), String::new())
}
#[cfg(feature = "glsl")]
pipeline::ShaderModuleSource::Glsl(code, options) => {
let mut parser = naga::front::glsl::Frontend::default();
profiling::scope!("naga::front::glsl::Frontend.parse");
let module = parser.parse(&options, &code).map_err(|inner| {
pipeline::CreateShaderModuleError::ParsingGlsl(pipeline::ShaderError {
source: code.to_string(),
label: desc.label.as_ref().map(|l| l.to_string()),
inner: Box::new(inner),
})
})?;
(Cow::Owned(module), code.into_owned())
}
pipeline::ShaderModuleSource::Naga(module) => (module, String::new()),
pipeline::ShaderModuleSource::Dummy(_) => panic!("found `ShaderModuleSource::Dummy`"),
};
@@ -1785,7 +1755,7 @@ impl<A: HalApi> Device<A> {
dynamic_binding_info: &mut Vec<binding_model::BindGroupDynamicBindingData>,
late_buffer_binding_sizes: &mut FastHashMap<u32, wgt::BufferSize>,
used: &mut BindGroupStates<A>,
storage: &'a Storage<Buffer<A>>,
storage: &'a Storage<Buffer<A>, id::BufferId>,
limits: &wgt::Limits,
snatch_guard: &'a SnatchGuard<'a>,
) -> Result<hal::BufferBinding<'a, A>, binding_model::CreateBindGroupError> {
@@ -1922,13 +1892,17 @@ impl<A: HalApi> Device<A> {
used: &mut BindGroupStates<A>,
used_texture_ranges: &mut Vec<TextureInitTrackerAction<A>>,
) -> Result<(), binding_model::CreateBindGroupError> {
let texture = &view.parent;
let texture_id = texture.as_info().id();
let texture = view.parent.read();
let texture_id = texture.as_ref().unwrap().as_info().id();
// Careful here: the texture may no longer have its own ref count,
// if it was deleted by the user.
let texture = used
.textures
.add_single(texture, Some(view.selector.clone()), internal_use)
.add_single(
texture.as_ref().unwrap(),
Some(view.selector.clone()),
internal_use,
)
.ok_or(binding_model::CreateBindGroupError::InvalidTexture(
texture_id,
))?;
@@ -2130,9 +2104,7 @@ impl<A: HalApi> Device<A> {
)?;
let res_index = hal_textures.len();
hal_textures.push(hal::TextureBinding {
view: view
.raw(&snatch_guard)
.ok_or(Error::InvalidTextureView(id))?,
view: view.raw(),
usage: internal_use,
});
(res_index, 1)
@@ -2158,9 +2130,7 @@ impl<A: HalApi> Device<A> {
&mut used_texture_ranges,
)?;
hal_textures.push(hal::TextureBinding {
view: view
.raw(&snatch_guard)
.ok_or(Error::InvalidTextureView(id))?,
view: view.raw(),
usage: internal_use,
});
}
@@ -2202,7 +2172,7 @@ impl<A: HalApi> Device<A> {
};
Ok(binding_model::BindGroup {
raw: Snatchable::new(raw),
raw: Some(raw),
device: self.clone(),
layout: layout.clone(),
info: ResourceInfo::new(desc.label.borrow_or_default()),
@@ -2386,7 +2356,7 @@ impl<A: HalApi> Device<A> {
pub(crate) fn create_pipeline_layout(
self: &Arc<Self>,
desc: &binding_model::PipelineLayoutDescriptor,
bgl_registry: &Registry<BindGroupLayout<A>>,
bgl_registry: &Registry<id::BindGroupLayoutId, BindGroupLayout<A>>,
) -> Result<binding_model::PipelineLayout<A>, binding_model::CreatePipelineLayoutError> {
use crate::binding_model::CreatePipelineLayoutError as Error;
@@ -2499,8 +2469,8 @@ impl<A: HalApi> Device<A> {
self: &Arc<Self>,
implicit_context: Option<ImplicitPipelineContext>,
mut derived_group_layouts: ArrayVec<bgl::EntryMap, { hal::MAX_BIND_GROUPS }>,
bgl_registry: &Registry<BindGroupLayout<A>>,
pipeline_layout_registry: &Registry<binding_model::PipelineLayout<A>>,
bgl_registry: &Registry<id::BindGroupLayoutId, BindGroupLayout<A>>,
pipeline_layout_registry: &Registry<id::PipelineLayoutId, binding_model::PipelineLayout<A>>,
) -> Result<Arc<binding_model::PipelineLayout<A>>, pipeline::ImplicitLayoutError> {
while derived_group_layouts
.last()
@@ -2717,13 +2687,8 @@ impl<A: HalApi> Device<A> {
let mut shader_expects_dual_source_blending = false;
let mut pipeline_expects_dual_source_blending = false;
for (i, vb_state) in desc.vertex.buffers.iter().enumerate() {
let mut last_stride = 0;
for attribute in vb_state.attributes.iter() {
last_stride = last_stride.max(attribute.offset + attribute.format.size());
}
vertex_steps.push(pipeline::VertexStep {
stride: vb_state.array_stride,
last_stride,
mode: vb_state.step_mode,
});
if vb_state.attributes.is_empty() {
@@ -3366,6 +3331,7 @@ impl<A: HalApi> Device<A> {
// It's important to not hold the lock while calling the closure.
drop(life_lock);
device_lost_closure.call(DeviceLostReason::Unknown, message.to_string());
life_lock = self.lock_life();
}
// 2) Complete any outstanding mapAsync() steps.
@@ -3377,26 +3343,7 @@ impl<A: HalApi> Device<A> {
// until they are cleared, and then drop the device.
// Eagerly release GPU resources.
self.release_gpu_resources();
}
pub(crate) fn release_gpu_resources(&self) {
// This is called when the device is lost, which makes every associated
// resource invalid and unusable. This is an opportunity to release all of
// the underlying gpu resources, even though the objects remain visible to
// the user agent. We purge this memory naturally when resources have been
// moved into the appropriate buckets, so this function just needs to
// initiate movement into those buckets, and it can do that by calling
// "destroy" on all the resources we know about.
// During these iterations, we discard all errors. We don't care!
let trackers = self.trackers.lock();
for buffer in trackers.buffers.used_resources() {
let _ = buffer.destroy();
}
for texture in trackers.textures.used_resources() {
let _ = texture.destroy();
}
life_lock.release_gpu_resources();
}
}
@@ -3433,11 +3380,6 @@ impl<A: HalApi> Device<A> {
current_index,
self.command_allocator.lock().as_mut().unwrap(),
);
if let Some(device_lost_closure) = life_tracker.device_lost_closure.take() {
// It's important to not hold the lock while calling the closure.
drop(life_tracker);
device_lost_closure.call(DeviceLostReason::Dropped, "Device is dying.".to_string());
}
#[cfg(feature = "trace")]
{
*self.trace.lock() = None;
@@ -3445,16 +3387,14 @@ impl<A: HalApi> Device<A> {
}
}
impl<A: HalApi> Resource for Device<A> {
impl<A: HalApi> Resource<DeviceId> for Device<A> {
const TYPE: ResourceType = "Device";
type Marker = crate::id::markers::Device;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<DeviceId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<DeviceId> {
&mut self.info
}
}

View File

@@ -33,7 +33,8 @@ pub(crate) fn new_render_bundle_encoder_descriptor<'a>(
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub enum Action<'a> {
Init {
desc: crate::device::DeviceDescriptor<'a>,
@@ -125,7 +126,8 @@ pub enum Action<'a> {
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub enum Command {
CopyBufferToBuffer {
src: id::BufferId,

View File

@@ -1,11 +1,11 @@
use core::fmt;
use std::error::Error;
use crate::{gfx_select, global::Global};
use crate::{gfx_select, global::Global, identity::IdentityManagerFactory};
pub struct ErrorFormatter<'a> {
writer: &'a mut dyn fmt::Write,
global: &'a Global,
global: &'a Global<IdentityManagerFactory>,
}
impl<'a> ErrorFormatter<'a> {
@@ -94,7 +94,7 @@ pub trait PrettyError: Error + Sized {
pub fn format_pretty_any(
writer: &mut dyn fmt::Write,
global: &Global,
global: &Global<IdentityManagerFactory>,
error: &(dyn Error + 'static),
) {
let mut fmt = ErrorFormatter { writer, global };

View File

@@ -1,10 +1,12 @@
use std::sync::Arc;
use std::{marker::PhantomData, sync::Arc};
use wgt::Backend;
use crate::{
hal_api::HalApi,
hub::{HubReport, Hubs},
id::SurfaceId,
identity::GlobalIdentityHandlerFactory,
instance::{Instance, Surface},
registry::{Registry, RegistryReport},
resource_log,
@@ -43,31 +45,38 @@ impl GlobalReport {
}
}
pub struct Global {
pub struct Global<G: GlobalIdentityHandlerFactory> {
pub instance: Instance,
pub surfaces: Registry<Surface>,
pub surfaces: Registry<SurfaceId, Surface>,
pub(crate) hubs: Hubs,
_phantom: PhantomData<G>,
}
impl Global {
pub fn new(name: &str, instance_desc: wgt::InstanceDescriptor) -> Self {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn new(name: &str, factory: G, instance_desc: wgt::InstanceDescriptor) -> Self {
profiling::scope!("Global::new");
Self {
instance: Instance::new(name, instance_desc),
surfaces: Registry::without_backend(),
hubs: Hubs::new(),
surfaces: Registry::without_backend(&factory),
hubs: Hubs::new(&factory),
_phantom: PhantomData,
}
}
/// # Safety
///
/// Refer to the creation of wgpu-hal Instance for every backend.
pub unsafe fn from_hal_instance<A: HalApi>(name: &str, hal_instance: A::Instance) -> Self {
pub unsafe fn from_hal_instance<A: HalApi>(
name: &str,
factory: G,
hal_instance: A::Instance,
) -> Self {
profiling::scope!("Global::new");
Self {
instance: A::create_instance_from_hal(name, hal_instance),
surfaces: Registry::without_backend(),
hubs: Hubs::new(),
surfaces: Registry::without_backend(&factory),
hubs: Hubs::new(&factory),
_phantom: PhantomData,
}
}
@@ -81,12 +90,13 @@ impl Global {
/// # Safety
///
/// - The raw handles obtained from the Instance must not be manually destroyed
pub unsafe fn from_instance(instance: Instance) -> Self {
pub unsafe fn from_instance(factory: G, instance: Instance) -> Self {
profiling::scope!("Global::new");
Self {
instance,
surfaces: Registry::without_backend(),
hubs: Hubs::new(),
surfaces: Registry::without_backend(&factory),
hubs: Hubs::new(&factory),
_phantom: PhantomData,
}
}
@@ -128,7 +138,7 @@ impl Global {
}
}
impl Drop for Global {
impl<G: GlobalIdentityHandlerFactory> Drop for Global<G> {
fn drop(&mut self) {
profiling::scope!("Global::drop");
resource_log!("Global::drop");
@@ -166,7 +176,7 @@ impl Drop for Global {
}
#[cfg(send_sync)]
fn _test_send_sync(global: &Global) {
fn _test_send_sync(global: &Global<crate::identity::IdentityManagerFactory>) {
fn test_internal<T: Send + Sync>(_: T) {}
test_internal(global)
}

View File

@@ -3,6 +3,7 @@ use wgt::{Backend, WasmNotSendSync};
use crate::{
global::Global,
hub::Hub,
identity::GlobalIdentityHandlerFactory,
instance::{HalSurface, Instance, Surface},
};
@@ -10,7 +11,7 @@ pub trait HalApi: hal::Api + 'static + WasmNotSendSync {
const VARIANT: Backend;
fn create_instance_from_hal(name: &str, hal_instance: Self::Instance) -> Instance;
fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance>;
fn hub(global: &Global) -> &Hub<Self>;
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self>;
fn get_surface(surface: &Surface) -> Option<&HalSurface<Self>>;
}
@@ -22,7 +23,7 @@ impl HalApi for hal::api::Empty {
fn instance_as_hal(_: &Instance) -> Option<&Self::Instance> {
unimplemented!("called empty api")
}
fn hub(_: &Global) -> &Hub<Self> {
fn hub<G: GlobalIdentityHandlerFactory>(_: &Global<G>) -> &Hub<Self> {
unimplemented!("called empty api")
}
fn get_surface(_: &Surface) -> Option<&HalSurface<Self>> {
@@ -43,7 +44,7 @@ impl HalApi for hal::api::Vulkan {
fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> {
instance.vulkan.as_ref()
}
fn hub(global: &Global) -> &Hub<Self> {
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self> {
&global.hubs.vulkan
}
fn get_surface(surface: &Surface) -> Option<&HalSurface<Self>> {
@@ -64,7 +65,7 @@ impl HalApi for hal::api::Metal {
fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> {
instance.metal.as_ref()
}
fn hub(global: &Global) -> &Hub<Self> {
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self> {
&global.hubs.metal
}
fn get_surface(surface: &Surface) -> Option<&HalSurface<Self>> {
@@ -85,7 +86,7 @@ impl HalApi for hal::api::Dx12 {
fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> {
instance.dx12.as_ref()
}
fn hub(global: &Global) -> &Hub<Self> {
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self> {
&global.hubs.dx12
}
fn get_surface(surface: &Surface) -> Option<&HalSurface<Self>> {
@@ -107,7 +108,7 @@ impl HalApi for hal::api::Gles {
fn instance_as_hal(instance: &Instance) -> Option<&Self::Instance> {
instance.gl.as_ref()
}
fn hub(global: &Global) -> &Hub<Self> {
fn hub<G: GlobalIdentityHandlerFactory>(global: &Global<G>) -> &Hub<Self> {
&global.hubs.gl
}
fn get_surface(surface: &Surface) -> Option<&HalSurface<Self>> {

View File

@@ -2,13 +2,10 @@
The `wgpu_core` API uses identifiers of type [`Id<R>`] to refer to
resources of type `R`. For example, [`id::DeviceId`] is an alias for
`Id<markers::Device>`, and [`id::BufferId`] is an alias for
`Id<markers::Buffer>`. `Id` implements `Copy`, `Hash`, `Eq`, `Ord`, and
`Id<Device<Empty>>`, and [`id::BufferId`] is an alias for
`Id<Buffer<Empty>>`. `Id` implements `Copy`, `Hash`, `Eq`, `Ord`, and
of course `Debug`.
[`id::DeviceId`]: crate::id::DeviceId
[`id::BufferId`]: crate::id::BufferId
Each `Id` contains not only an index for the resource it denotes but
also a Backend indicating which `wgpu` backend it belongs to. You
can use the [`gfx_select`] macro to dynamically dispatch on an id's
@@ -40,13 +37,13 @@ specify the id, and they all return the id used. For example, the
declaration of `Global::device_create_buffer` looks like this:
```ignore
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
/* ... */
pub fn device_create_buffer<A: HalApi>(
&self,
device_id: id::DeviceId,
desc: &resource::BufferDescriptor,
id_in: Input<G>,
id_in: Input<G, id::BufferId>,
) -> (id::BufferId, Option<resource::CreateBufferError>) {
/* ... */
}
@@ -60,7 +57,15 @@ itself to choose ids always pass `()`. In either case, the id
ultimately assigned is returned as the first element of the tuple.
Producing true identifiers from `id_in` values is the job of an
[`crate::identity::IdentityManager`] or ids will be received from outside through `Option<Id>` arguments.
[`crate::identity::IdentityManager`], but only if the `IdentityHandlerFactory`
create it and then generated by it, otherwise ids will be received from outside.
`Global::new` expects a `factory` argument that
implements the [`GlobalIdentityHandlerFactory`] trait, which extends
[`crate::identity::IdentityHandlerFactory<I>`] for each resource id type `I`. This
trait, in turn, has a `spawn` method that constructs an
`crate::identity::IdentityManager` for the `Global` to use,
if ids should be generated by wgpu or will return None otherwise.
## Id allocation and streaming
@@ -97,6 +102,7 @@ as much, allowing subsequent operations using that id to be properly
flagged as errors as well.
[`gfx_select`]: crate::gfx_select
[`Input`]: crate::identity::IdentityHandlerFactory::Input
[`process`]: crate::identity::IdentityManager::process
[`Id<R>`]: crate::id::Id
[wrapped in a mutex]: trait.IdentityHandler.html#impl-IdentityHandler%3CI%3E-for-Mutex%3CIdentityManager%3E
@@ -109,6 +115,8 @@ use crate::{
command::{CommandBuffer, RenderBundle},
device::{queue::Queue, Device},
hal_api::HalApi,
id,
identity::GlobalIdentityHandlerFactory,
instance::{Adapter, HalSurface, Surface},
pipeline::{ComputePipeline, RenderPipeline, ShaderModule},
registry::{Registry, RegistryReport},
@@ -169,52 +177,56 @@ impl HubReport {
///
/// [`A::hub(global)`]: HalApi::hub
pub struct Hub<A: HalApi> {
pub adapters: Registry<Adapter<A>>,
pub devices: Registry<Device<A>>,
pub queues: Registry<Queue<A>>,
pub pipeline_layouts: Registry<PipelineLayout<A>>,
pub shader_modules: Registry<ShaderModule<A>>,
pub bind_group_layouts: Registry<BindGroupLayout<A>>,
pub bind_groups: Registry<BindGroup<A>>,
pub command_buffers: Registry<CommandBuffer<A>>,
pub render_bundles: Registry<RenderBundle<A>>,
pub render_pipelines: Registry<RenderPipeline<A>>,
pub compute_pipelines: Registry<ComputePipeline<A>>,
pub query_sets: Registry<QuerySet<A>>,
pub buffers: Registry<Buffer<A>>,
pub staging_buffers: Registry<StagingBuffer<A>>,
pub textures: Registry<Texture<A>>,
pub texture_views: Registry<TextureView<A>>,
pub samplers: Registry<Sampler<A>>,
pub adapters: Registry<id::AdapterId, Adapter<A>>,
pub devices: Registry<id::DeviceId, Device<A>>,
pub queues: Registry<id::QueueId, Queue<A>>,
pub pipeline_layouts: Registry<id::PipelineLayoutId, PipelineLayout<A>>,
pub shader_modules: Registry<id::ShaderModuleId, ShaderModule<A>>,
pub bind_group_layouts: Registry<id::BindGroupLayoutId, BindGroupLayout<A>>,
pub bind_groups: Registry<id::BindGroupId, BindGroup<A>>,
pub command_buffers: Registry<id::CommandBufferId, CommandBuffer<A>>,
pub render_bundles: Registry<id::RenderBundleId, RenderBundle<A>>,
pub render_pipelines: Registry<id::RenderPipelineId, RenderPipeline<A>>,
pub compute_pipelines: Registry<id::ComputePipelineId, ComputePipeline<A>>,
pub query_sets: Registry<id::QuerySetId, QuerySet<A>>,
pub buffers: Registry<id::BufferId, Buffer<A>>,
pub staging_buffers: Registry<id::StagingBufferId, StagingBuffer<A>>,
pub textures: Registry<id::TextureId, Texture<A>>,
pub texture_views: Registry<id::TextureViewId, TextureView<A>>,
pub samplers: Registry<id::SamplerId, Sampler<A>>,
}
impl<A: HalApi> Hub<A> {
fn new() -> Self {
fn new<F: GlobalIdentityHandlerFactory>(factory: &F) -> Self {
Self {
adapters: Registry::new(A::VARIANT),
devices: Registry::new(A::VARIANT),
queues: Registry::new(A::VARIANT),
pipeline_layouts: Registry::new(A::VARIANT),
shader_modules: Registry::new(A::VARIANT),
bind_group_layouts: Registry::new(A::VARIANT),
bind_groups: Registry::new(A::VARIANT),
command_buffers: Registry::new(A::VARIANT),
render_bundles: Registry::new(A::VARIANT),
render_pipelines: Registry::new(A::VARIANT),
compute_pipelines: Registry::new(A::VARIANT),
query_sets: Registry::new(A::VARIANT),
buffers: Registry::new(A::VARIANT),
staging_buffers: Registry::new(A::VARIANT),
textures: Registry::new(A::VARIANT),
texture_views: Registry::new(A::VARIANT),
samplers: Registry::new(A::VARIANT),
adapters: Registry::new(A::VARIANT, factory),
devices: Registry::new(A::VARIANT, factory),
queues: Registry::new(A::VARIANT, factory),
pipeline_layouts: Registry::new(A::VARIANT, factory),
shader_modules: Registry::new(A::VARIANT, factory),
bind_group_layouts: Registry::new(A::VARIANT, factory),
bind_groups: Registry::new(A::VARIANT, factory),
command_buffers: Registry::new(A::VARIANT, factory),
render_bundles: Registry::new(A::VARIANT, factory),
render_pipelines: Registry::new(A::VARIANT, factory),
compute_pipelines: Registry::new(A::VARIANT, factory),
query_sets: Registry::new(A::VARIANT, factory),
buffers: Registry::new(A::VARIANT, factory),
staging_buffers: Registry::new(A::VARIANT, factory),
textures: Registry::new(A::VARIANT, factory),
texture_views: Registry::new(A::VARIANT, factory),
samplers: Registry::new(A::VARIANT, factory),
}
}
//TODO: instead of having a hacky `with_adapters` parameter,
// we should have `clear_device(device_id)` that specifically destroys
// everything related to a logical device.
pub(crate) fn clear(&self, surface_guard: &Storage<Surface>, with_adapters: bool) {
pub(crate) fn clear(
&self,
surface_guard: &Storage<Surface, id::SurfaceId>,
with_adapters: bool,
) {
use hal::Surface;
let mut devices = self.devices.write();
@@ -303,18 +315,18 @@ pub struct Hubs {
}
impl Hubs {
pub(crate) fn new() -> Self {
pub(crate) fn new<F: GlobalIdentityHandlerFactory>(factory: &F) -> Self {
Self {
#[cfg(vulkan)]
vulkan: Hub::new(),
vulkan: Hub::new(factory),
#[cfg(metal)]
metal: Hub::new(),
metal: Hub::new(factory),
#[cfg(dx12)]
dx12: Hub::new(),
dx12: Hub::new(factory),
#[cfg(gles)]
gl: Hub::new(),
gl: Hub::new(factory),
#[cfg(all(not(vulkan), not(metal), not(dx12), not(gles)))]
empty: Hub::new(),
empty: Hub::new(factory),
}
}
}

View File

@@ -1,5 +1,6 @@
use crate::{Epoch, Index};
use std::{
any::Any,
cmp::Ordering,
fmt::{self, Debug},
hash::Hash,
@@ -8,80 +9,15 @@ use std::{
use wgt::{Backend, WasmNotSendSync};
type IdType = u64;
type ZippedIndex = Index;
type NonZeroId = std::num::NonZeroU64;
type ZippedIndex = Index;
const INDEX_BITS: usize = std::mem::size_of::<ZippedIndex>() * 8;
const EPOCH_BITS: usize = INDEX_BITS - BACKEND_BITS;
const BACKEND_BITS: usize = 3;
const BACKEND_SHIFT: usize = INDEX_BITS * 2 - BACKEND_BITS;
pub const EPOCH_MASK: u32 = (1 << (EPOCH_BITS)) - 1;
/// The raw underlying representation of an identifier.
#[repr(transparent)]
#[cfg_attr(any(feature = "serde", feature = "trace"), derive(serde::Serialize))]
#[cfg_attr(any(feature = "serde", feature = "replay"), derive(serde::Deserialize))]
#[cfg_attr(feature = "trace", serde(into = "SerialId"))]
#[cfg_attr(feature = "replay", serde(from = "SerialId"))]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RawId(NonZeroId);
impl RawId {
#[doc(hidden)]
#[inline]
pub fn from_non_zero(non_zero: NonZeroId) -> Self {
Self(non_zero)
}
#[doc(hidden)]
#[inline]
pub fn into_non_zero(self) -> NonZeroId {
self.0
}
/// Zip together an identifier and return its raw underlying representation.
pub fn zip(index: Index, epoch: Epoch, backend: Backend) -> RawId {
assert_eq!(0, epoch >> EPOCH_BITS);
assert_eq!(0, (index as IdType) >> INDEX_BITS);
let v = index as IdType
| ((epoch as IdType) << INDEX_BITS)
| ((backend as IdType) << BACKEND_SHIFT);
Self(NonZeroId::new(v).unwrap())
}
/// Unzip a raw identifier into its components.
#[allow(trivial_numeric_casts)]
pub fn unzip(self) -> (Index, Epoch, Backend) {
(
(self.0.get() as ZippedIndex) as Index,
(((self.0.get() >> INDEX_BITS) as ZippedIndex) & (EPOCH_MASK as ZippedIndex)) as Index,
self.backend(),
)
}
pub fn backend(self) -> Backend {
match self.0.get() >> (BACKEND_SHIFT) as u8 {
0 => Backend::Empty,
1 => Backend::Vulkan,
2 => Backend::Metal,
3 => Backend::Dx12,
4 => Backend::Gl,
_ => unreachable!(),
}
}
}
/// Coerce a slice of identifiers into a slice of optional raw identifiers.
///
/// There's two reasons why we know this is correct:
/// * `Option<T>` is guarnateed to be niche-filled to 0's.
/// * The `T` in `Option<T>` can inhabit any representation except 0's, since
/// its underlying representation is `NonZero*`.
pub fn as_option_slice<T: Marker>(ids: &[Id<T>]) -> &[Option<Id<T>>] {
// SAFETY: Any Id<T> is repr(transparent) over `Option<RawId>`, since both
// are backed by non-zero types.
unsafe { std::slice::from_raw_parts(ids.as_ptr().cast(), ids.len()) }
}
type Dummy = hal::api::Empty;
/// An identifier for a wgpu object.
///
@@ -113,55 +49,63 @@ pub fn as_option_slice<T: Marker>(ids: &[Id<T>]) -> &[Option<Id<T>>] {
/// [`Registry`]: crate::hub::Registry
/// [`Empty`]: hal::api::Empty
#[repr(transparent)]
#[cfg_attr(any(feature = "serde", feature = "trace"), derive(serde::Serialize))]
#[cfg_attr(any(feature = "serde", feature = "replay"), derive(serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize), serde(into = "SerialId"))]
#[cfg_attr(
any(feature = "serde", feature = "trace", feature = "replay"),
serde(transparent)
feature = "replay",
derive(serde::Deserialize),
serde(from = "SerialId")
)]
pub struct Id<T: Marker>(RawId, PhantomData<T>);
#[cfg_attr(
all(feature = "serde", not(feature = "trace")),
derive(serde::Serialize)
)]
#[cfg_attr(
all(feature = "serde", not(feature = "replay")),
derive(serde::Deserialize)
)]
pub struct Id<T: 'static + WasmNotSendSync>(NonZeroId, PhantomData<T>);
// This type represents Id in a more readable (and editable) way.
#[allow(dead_code)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
enum SerialId {
// The only variant forces RON to not ignore "Id"
Id(Index, Epoch, Backend),
}
#[cfg(feature = "trace")]
impl From<RawId> for SerialId {
fn from(id: RawId) -> Self {
impl<T> From<Id<T>> for SerialId
where
T: 'static + WasmNotSendSync,
{
fn from(id: Id<T>) -> Self {
let (index, epoch, backend) = id.unzip();
Self::Id(index, epoch, backend)
}
}
#[cfg(feature = "replay")]
impl From<SerialId> for RawId {
impl<T> From<SerialId> for Id<T>
where
T: 'static + WasmNotSendSync,
{
fn from(id: SerialId) -> Self {
match id {
SerialId::Id(index, epoch, backend) => RawId::zip(index, epoch, backend),
SerialId::Id(index, epoch, backend) => TypedId::zip(index, epoch, backend),
}
}
}
impl<T> Id<T>
where
T: Marker,
T: 'static + WasmNotSendSync,
{
/// # Safety
///
/// The raw id must be valid for the type.
pub unsafe fn from_raw(raw: RawId) -> Self {
pub unsafe fn from_raw(raw: NonZeroId) -> Self {
Self(raw, PhantomData)
}
/// Coerce the identifiers into its raw underlying representation.
pub fn into_raw(self) -> RawId {
self.0
}
#[allow(dead_code)]
pub(crate) fn dummy(index: u32) -> Self {
Id::zip(index, 1, Backend::Empty)
@@ -172,53 +116,24 @@ where
self.backend() != Backend::Empty
}
/// Get the backend this identifier corresponds to.
#[inline]
pub fn backend(self) -> Backend {
self.0.backend()
}
/// Transmute this identifier to one with a different marker trait.
///
/// Legal use is governed through a sealed trait, however it's correctness
/// depends on the current implementation of `wgpu-core`.
#[inline]
pub const fn transmute<U: self::transmute::Transmute<T>>(self) -> Id<U> {
Id(self.0, PhantomData)
}
#[inline]
pub fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self {
Id(RawId::zip(index, epoch, backend), PhantomData)
}
#[inline]
pub fn unzip(self) -> (Index, Epoch, Backend) {
self.0.unzip()
match self.0.get() >> (BACKEND_SHIFT) as u8 {
0 => Backend::Empty,
1 => Backend::Vulkan,
2 => Backend::Metal,
3 => Backend::Dx12,
4 => Backend::Gl,
_ => unreachable!(),
}
}
}
pub(crate) mod transmute {
// This trait is effectively sealed to prevent illegal transmutes.
pub trait Transmute<U>: super::Marker {}
// Self-transmute is always legal.
impl<T> Transmute<T> for T where T: super::Marker {}
// TODO: Remove these once queues have their own identifiers.
impl Transmute<super::markers::Queue> for super::markers::Device {}
impl Transmute<super::markers::Device> for super::markers::Queue {}
impl Transmute<super::markers::CommandBuffer> for super::markers::CommandEncoder {}
impl Transmute<super::markers::CommandEncoder> for super::markers::CommandBuffer {}
}
impl<T> Copy for Id<T> where T: Marker {}
impl<T> Copy for Id<T> where T: 'static + WasmNotSendSync {}
impl<T> Clone for Id<T>
where
T: Marker,
T: 'static + WasmNotSendSync,
{
#[inline]
fn clone(&self) -> Self {
*self
}
@@ -226,7 +141,7 @@ where
impl<T> Debug for Id<T>
where
T: Marker,
T: 'static + WasmNotSendSync,
{
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let (index, epoch, backend) = self.unzip();
@@ -245,9 +160,8 @@ where
impl<T> Hash for Id<T>
where
T: Marker,
T: 'static + WasmNotSendSync,
{
#[inline]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
@@ -255,21 +169,19 @@ where
impl<T> PartialEq for Id<T>
where
T: Marker,
T: 'static + WasmNotSendSync,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T> Eq for Id<T> where T: Marker {}
impl<T> Eq for Id<T> where T: 'static + WasmNotSendSync {}
impl<T> PartialOrd for Id<T>
where
T: Marker,
T: 'static + WasmNotSendSync,
{
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.0.partial_cmp(&other.0)
}
@@ -277,73 +189,78 @@ where
impl<T> Ord for Id<T>
where
T: Marker,
T: 'static + WasmNotSendSync,
{
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(&other.0)
}
}
/// Marker trait used to determine which types uniquely identify a resource.
/// Trait carrying methods for direct `Id` access.
///
/// For example, `Device<A>` will have the same type of identifier as
/// `Device<B>` because `Device<T>` for any `T` defines the same maker type.
pub trait Marker: 'static + WasmNotSendSync {}
/// Most `wgpu-core` clients should not use this trait. Unusual clients that
/// need to construct `Id` values directly, or access their components, like the
/// WGPU recording player, may use this trait to do so.
pub trait TypedId: Copy + Debug + Any + 'static + WasmNotSendSync + Eq + Hash {
fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self;
fn unzip(self) -> (Index, Epoch, Backend);
fn into_raw(self) -> NonZeroId;
}
// This allows `()` to be used as a marker type for tests.
//
// We don't want these in production code, since they essentially remove type
// safety, like how identifiers across different types can be compared.
#[cfg(test)]
impl Marker for () {}
#[allow(trivial_numeric_casts)]
impl<T> TypedId for Id<T>
where
T: 'static + WasmNotSendSync,
{
fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self {
assert_eq!(0, epoch >> EPOCH_BITS);
assert_eq!(0, (index as IdType) >> INDEX_BITS);
let v = index as IdType
| ((epoch as IdType) << INDEX_BITS)
| ((backend as IdType) << BACKEND_SHIFT);
Id(NonZeroId::new(v).unwrap(), PhantomData)
}
/// Define identifiers for each resource.
macro_rules! ids {
($(
$(#[$($meta:meta)*])*
pub type $name:ident $marker:ident;
)*) => {
/// Marker types for each resource.
pub mod markers {
$(
#[derive(Debug)]
pub enum $marker {}
impl super::Marker for $marker {}
)*
}
fn unzip(self) -> (Index, Epoch, Backend) {
(
(self.0.get() as ZippedIndex) as Index,
(((self.0.get() >> INDEX_BITS) as ZippedIndex) & (EPOCH_MASK as ZippedIndex)) as Index,
self.backend(),
)
}
$(
$(#[$($meta)*])*
pub type $name = Id<self::markers::$marker>;
)*
fn into_raw(self) -> NonZeroId {
self.0
}
}
ids! {
pub type AdapterId Adapter;
pub type SurfaceId Surface;
pub type DeviceId Device;
pub type QueueId Queue;
pub type BufferId Buffer;
pub type StagingBufferId StagingBuffer;
pub type TextureViewId TextureView;
pub type TextureId Texture;
pub type SamplerId Sampler;
pub type BindGroupLayoutId BindGroupLayout;
pub type PipelineLayoutId PipelineLayout;
pub type BindGroupId BindGroup;
pub type ShaderModuleId ShaderModule;
pub type RenderPipelineId RenderPipeline;
pub type ComputePipelineId ComputePipeline;
pub type CommandEncoderId CommandEncoder;
pub type CommandBufferId CommandBuffer;
pub type RenderPassEncoderId RenderPassEncoder;
pub type ComputePassEncoderId ComputePassEncoder;
pub type RenderBundleEncoderId RenderBundleEncoder;
pub type RenderBundleId RenderBundle;
pub type QuerySetId QuerySet;
}
pub type AdapterId = Id<crate::instance::Adapter<Dummy>>;
pub type SurfaceId = Id<crate::instance::Surface>;
// Device
pub type DeviceId = Id<crate::device::Device<Dummy>>;
pub type QueueId = DeviceId;
// Resource
pub type BufferId = Id<crate::resource::Buffer<Dummy>>;
pub type StagingBufferId = Id<crate::resource::StagingBuffer<Dummy>>;
pub type TextureViewId = Id<crate::resource::TextureView<Dummy>>;
pub type TextureId = Id<crate::resource::Texture<Dummy>>;
pub type SamplerId = Id<crate::resource::Sampler<Dummy>>;
// Binding model
pub type BindGroupLayoutId = Id<crate::binding_model::BindGroupLayout<Dummy>>;
pub type PipelineLayoutId = Id<crate::binding_model::PipelineLayout<Dummy>>;
pub type BindGroupId = Id<crate::binding_model::BindGroup<Dummy>>;
// Pipeline
pub type ShaderModuleId = Id<crate::pipeline::ShaderModule<Dummy>>;
pub type RenderPipelineId = Id<crate::pipeline::RenderPipeline<Dummy>>;
pub type ComputePipelineId = Id<crate::pipeline::ComputePipeline<Dummy>>;
// Command
pub type CommandEncoderId = CommandBufferId;
pub type CommandBufferId = Id<crate::command::CommandBuffer<Dummy>>;
pub type RenderPassEncoderId = *mut crate::command::RenderPass;
pub type ComputePassEncoderId = *mut crate::command::ComputePass;
pub type RenderBundleEncoderId = *mut crate::command::RenderBundleEncoder;
pub type RenderBundleId = Id<crate::command::RenderBundle<Dummy>>;
pub type QuerySetId = Id<crate::resource::QuerySet<Dummy>>;
#[test]
fn test_id_backend() {
@@ -354,7 +271,7 @@ fn test_id_backend() {
Backend::Dx12,
Backend::Gl,
] {
let id = crate::id::Id::<()>::zip(1, 0, b);
let id: Id<()> = Id::zip(1, 0, b);
let (_id, _epoch, backend) = id.unzip();
assert_eq!(id.backend(), b);
assert_eq!(backend, b);
@@ -376,7 +293,7 @@ fn test_id() {
for &i in &indexes {
for &e in &epochs {
for &b in &backends {
let id = crate::id::Id::<()>::zip(i, e, b);
let id: Id<()> = Id::zip(i, e, b);
let (index, epoch, backend) = id.unzip();
assert_eq!(index, i);
assert_eq!(epoch, e);

View File

@@ -2,10 +2,10 @@ use parking_lot::Mutex;
use wgt::Backend;
use crate::{
id::{Id, Marker},
id::{self},
Epoch, FastHashMap, Index,
};
use std::{fmt::Debug, marker::PhantomData};
use std::{fmt::Debug, marker::PhantomData, sync::Arc};
/// A simple structure to allocate [`Id`] identifiers.
///
@@ -47,10 +47,10 @@ impl IdentityValues {
///
/// The backend is incorporated into the id, so that ids allocated with
/// different `backend` values are always distinct.
pub fn alloc<T: Marker>(&mut self, backend: Backend) -> Id<T> {
pub fn alloc<I: id::TypedId>(&mut self, backend: Backend) -> I {
self.count += 1;
match self.free.pop() {
Some((index, epoch)) => Id::zip(index, epoch + 1, backend),
Some((index, epoch)) => I::zip(index, epoch + 1, backend),
None => {
let epoch = 1;
let used = self.used.entry(epoch).or_insert_with(Default::default);
@@ -60,12 +60,12 @@ impl IdentityValues {
0
};
used.push(index);
Id::zip(index, epoch, backend)
I::zip(index, epoch, backend)
}
}
}
pub fn mark_as_used<T: Marker>(&mut self, id: Id<T>) -> Id<T> {
pub fn mark_as_used<I: id::TypedId>(&mut self, id: I) -> I {
self.count += 1;
let (index, epoch, _backend) = id.unzip();
let used = self.used.entry(epoch).or_insert_with(Default::default);
@@ -74,7 +74,7 @@ impl IdentityValues {
}
/// Free `id`. It will never be returned from `alloc` again.
pub fn release<T: Marker>(&mut self, id: Id<T>) {
pub fn release<I: id::TypedId>(&mut self, id: I) {
let (index, epoch, _backend) = id.unzip();
self.free.push((index, epoch));
self.count -= 1;
@@ -86,24 +86,24 @@ impl IdentityValues {
}
#[derive(Debug)]
pub struct IdentityManager<T: Marker> {
pub struct IdentityManager<I: id::TypedId> {
pub(super) values: Mutex<IdentityValues>,
_phantom: PhantomData<T>,
_phantom: PhantomData<I>,
}
impl<T: Marker> IdentityManager<T> {
pub fn process(&self, backend: Backend) -> Id<T> {
impl<I: id::TypedId> IdentityManager<I> {
pub fn process(&self, backend: Backend) -> I {
self.values.lock().alloc(backend)
}
pub fn mark_as_used(&self, id: Id<T>) -> Id<T> {
pub fn mark_as_used(&self, id: I) -> I {
self.values.lock().mark_as_used(id)
}
pub fn free(&self, id: Id<T>) {
pub fn free(&self, id: I) {
self.values.lock().release(id)
}
}
impl<T: Marker> IdentityManager<T> {
impl<I: id::TypedId> IdentityManager<I> {
pub fn new() -> Self {
Self {
values: Mutex::new(IdentityValues::default()),
@@ -112,11 +112,74 @@ impl<T: Marker> IdentityManager<T> {
}
}
/// A type that can produce [`IdentityManager`] filters for ids of type `I`.
///
/// See the module-level documentation for details.
pub trait IdentityHandlerFactory<I: id::TypedId> {
type Input: Copy;
/// Create an [`IdentityManager<I>`] implementation that can
/// transform proto-ids into ids of type `I`.
/// It can return None if ids are passed from outside
/// and are not generated by wgpu
///
/// [`IdentityManager<I>`]: IdentityManager
fn spawn(&self) -> Arc<IdentityManager<I>> {
Arc::new(IdentityManager::new())
}
fn autogenerate_ids() -> bool;
fn input_to_id(id_in: Self::Input) -> I;
}
/// A global identity handler factory based on [`IdentityManager`].
///
/// Each of this type's `IdentityHandlerFactory<I>::spawn` methods
/// returns a `Mutex<IdentityManager<I>>`, which allocates fresh `I`
/// ids itself, and takes `()` as its proto-id type.
#[derive(Debug)]
pub struct IdentityManagerFactory;
impl<I: id::TypedId> IdentityHandlerFactory<I> for IdentityManagerFactory {
type Input = ();
fn autogenerate_ids() -> bool {
true
}
fn input_to_id(_id_in: Self::Input) -> I {
unreachable!("It should not be called")
}
}
/// A factory that can build [`IdentityManager`]s for all resource
/// types.
pub trait GlobalIdentityHandlerFactory:
IdentityHandlerFactory<id::AdapterId>
+ IdentityHandlerFactory<id::DeviceId>
+ IdentityHandlerFactory<id::PipelineLayoutId>
+ IdentityHandlerFactory<id::ShaderModuleId>
+ IdentityHandlerFactory<id::BindGroupLayoutId>
+ IdentityHandlerFactory<id::BindGroupId>
+ IdentityHandlerFactory<id::CommandBufferId>
+ IdentityHandlerFactory<id::RenderBundleId>
+ IdentityHandlerFactory<id::RenderPipelineId>
+ IdentityHandlerFactory<id::ComputePipelineId>
+ IdentityHandlerFactory<id::QuerySetId>
+ IdentityHandlerFactory<id::BufferId>
+ IdentityHandlerFactory<id::StagingBufferId>
+ IdentityHandlerFactory<id::TextureId>
+ IdentityHandlerFactory<id::TextureViewId>
+ IdentityHandlerFactory<id::SamplerId>
+ IdentityHandlerFactory<id::SurfaceId>
{
}
impl GlobalIdentityHandlerFactory for IdentityManagerFactory {}
pub type Input<G, I> = <G as IdentityHandlerFactory<I>>::Input;
#[test]
fn test_epoch_end_of_life() {
use crate::id;
let man = IdentityManager::<id::markers::Buffer>::new();
use id::TypedId as _;
let man = IdentityManager::<id::BufferId>::new();
let forced_id = man.mark_as_used(id::BufferId::zip(0, 1, Backend::Empty));
assert_eq!(forced_id.unzip().0, 0);
let id1 = man.process(Backend::Empty);

View File

@@ -6,8 +6,8 @@ use crate::{
device::{queue::Queue, resource::Device, DeviceDescriptor},
global::Global,
hal_api::HalApi,
id::markers,
id::{AdapterId, DeviceId, Id, Marker, QueueId, SurfaceId},
id::{AdapterId, DeviceId, QueueId, SurfaceId},
identity::{GlobalIdentityHandlerFactory, Input},
present::Presentation,
resource::{Resource, ResourceInfo, ResourceType},
resource_log, LabelHelpers, DOWNLEVEL_WARNING_MESSAGE,
@@ -149,20 +149,18 @@ impl Instance {
pub struct Surface {
pub(crate) presentation: Mutex<Option<Presentation>>,
pub(crate) info: ResourceInfo<Surface>,
pub(crate) info: ResourceInfo<SurfaceId>,
pub(crate) raw: AnySurface,
}
impl Resource for Surface {
impl Resource<SurfaceId> for Surface {
const TYPE: ResourceType = "Surface";
type Marker = markers::Surface;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<SurfaceId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<SurfaceId> {
&mut self.info
}
@@ -192,7 +190,7 @@ impl Surface {
pub struct Adapter<A: HalApi> {
pub(crate) raw: hal::ExposedAdapter<A>,
pub(crate) info: ResourceInfo<Adapter<A>>,
pub(crate) info: ResourceInfo<AdapterId>,
}
impl<A: HalApi> Adapter<A> {
@@ -384,16 +382,14 @@ impl<A: HalApi> Adapter<A> {
}
}
impl<A: HalApi> Resource for Adapter<A> {
impl<A: HalApi> Resource<AdapterId> for Adapter<A> {
const TYPE: ResourceType = "Adapter";
type Marker = markers::Adapter;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<AdapterId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<AdapterId> {
&mut self.info
}
}
@@ -438,15 +434,15 @@ pub enum RequestDeviceError {
UnsupportedFeature(wgt::Features),
}
pub enum AdapterInputs<'a, M: Marker> {
IdSet(&'a [Id<M>]),
Mask(Backends, fn(Backend) -> Option<Id<M>>),
pub enum AdapterInputs<'a, I> {
IdSet(&'a [I], fn(&I) -> Backend),
Mask(Backends, fn(Backend) -> I),
}
impl<M: Marker> AdapterInputs<'_, M> {
fn find(&self, b: Backend) -> Option<Option<Id<M>>> {
impl<I: Copy> AdapterInputs<'_, I> {
fn find(&self, b: Backend) -> Option<I> {
match *self {
Self::IdSet(ids) => Some(Some(ids.iter().find(|id| id.backend() == b).copied()?)),
Self::IdSet(ids, ref fun) => ids.iter().find(|id| fun(id) == b).copied(),
Self::Mask(bits, ref fun) => {
if bits.contains(b.into()) {
Some(fun(b))
@@ -471,16 +467,7 @@ pub enum RequestAdapterError {
InvalidSurface(SurfaceId),
}
#[derive(Clone, Debug, Error)]
#[non_exhaustive]
pub enum CreateSurfaceError {
#[error("No backend is available")]
NoSupportedBackend,
#[error(transparent)]
InstanceError(#[from] hal::InstanceError),
}
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
/// # Safety
///
/// - `display_handle` must be a valid object to create a surface upon.
@@ -491,8 +478,8 @@ impl Global {
&self,
display_handle: raw_window_handle::RawDisplayHandle,
window_handle: raw_window_handle::RawWindowHandle,
id_in: Option<SurfaceId>,
) -> Result<SurfaceId, CreateSurfaceError> {
id_in: Input<G, SurfaceId>,
) -> Result<SurfaceId, hal::InstanceError> {
profiling::scope!("Instance::create_surface");
fn init<A: HalApi>(
@@ -530,7 +517,8 @@ impl Global {
hal_surface = init::<hal::api::Gles>(&self.instance.gl, display_handle, window_handle);
}
let hal_surface = hal_surface.ok_or(CreateSurfaceError::NoSupportedBackend)??;
// This is only None if there's no instance at all.
let hal_surface = hal_surface.unwrap()?;
let surface = Surface {
presentation: Mutex::new(None),
@@ -538,7 +526,7 @@ impl Global {
raw: hal_surface,
};
let (id, _) = self.surfaces.prepare(id_in).assign(surface);
let (id, _) = self.surfaces.prepare::<G>(id_in).assign(surface);
Ok(id)
}
@@ -549,7 +537,7 @@ impl Global {
pub unsafe fn instance_create_surface_metal(
&self,
layer: *mut std::ffi::c_void,
id_in: Option<SurfaceId>,
id_in: Input<G, SurfaceId>,
) -> SurfaceId {
profiling::scope!("Instance::create_surface_metal");
@@ -573,7 +561,7 @@ impl Global {
},
};
let (id, _) = self.surfaces.prepare(id_in).assign(surface);
let (id, _) = self.surfaces.prepare::<G>(id_in).assign(surface);
id
}
@@ -584,7 +572,7 @@ impl Global {
pub unsafe fn instance_create_surface_from_visual(
&self,
visual: *mut std::ffi::c_void,
id_in: Option<SurfaceId>,
id_in: Input<G, SurfaceId>,
) -> SurfaceId {
profiling::scope!("Instance::instance_create_surface_from_visual");
@@ -604,7 +592,7 @@ impl Global {
},
};
let (id, _) = self.surfaces.prepare(id_in).assign(surface);
let (id, _) = self.surfaces.prepare::<G>(id_in).assign(surface);
id
}
@@ -615,7 +603,7 @@ impl Global {
pub unsafe fn instance_create_surface_from_surface_handle(
&self,
surface_handle: *mut std::ffi::c_void,
id_in: Option<SurfaceId>,
id_in: Input<G, SurfaceId>,
) -> SurfaceId {
profiling::scope!("Instance::instance_create_surface_from_surface_handle");
@@ -637,7 +625,7 @@ impl Global {
},
};
let (id, _) = self.surfaces.prepare(id_in).assign(surface);
let (id, _) = self.surfaces.prepare::<G>(id_in).assign(surface);
id
}
@@ -648,7 +636,7 @@ impl Global {
pub unsafe fn instance_create_surface_from_swap_chain_panel(
&self,
swap_chain_panel: *mut std::ffi::c_void,
id_in: Option<SurfaceId>,
id_in: Input<G, SurfaceId>,
) -> SurfaceId {
profiling::scope!("Instance::instance_create_surface_from_swap_chain_panel");
@@ -670,7 +658,7 @@ impl Global {
},
};
let (id, _) = self.surfaces.prepare(id_in).assign(surface);
let (id, _) = self.surfaces.prepare::<G>(id_in).assign(surface);
id
}
@@ -679,7 +667,11 @@ impl Global {
api_log!("Surface::drop {id:?}");
fn unconfigure<A: HalApi>(global: &Global, surface: &AnySurface, present: &Presentation) {
fn unconfigure<G: GlobalIdentityHandlerFactory, A: HalApi>(
global: &Global<G>,
surface: &AnySurface,
present: &Presentation,
) {
let hub = HalApi::hub(global);
if let Some(hal_surface) = surface.downcast_ref::<A>() {
if let Some(device) = present.device.downcast_ref::<A>() {
@@ -692,13 +684,13 @@ impl Global {
if let Some(surface) = Arc::into_inner(surface.unwrap()) {
if let Some(present) = surface.presentation.lock().take() {
#[cfg(vulkan)]
unconfigure::<hal::api::Vulkan>(self, &surface.raw, &present);
unconfigure::<_, hal::api::Vulkan>(self, &surface.raw, &present);
#[cfg(metal)]
unconfigure::<hal::api::Metal>(self, &surface.raw, &present);
unconfigure::<_, hal::api::Metal>(self, &surface.raw, &present);
#[cfg(dx12)]
unconfigure::<hal::api::Dx12>(self, &surface.raw, &present);
unconfigure::<_, hal::api::Dx12>(self, &surface.raw, &present);
#[cfg(gles)]
unconfigure::<hal::api::Gles>(self, &surface.raw, &present);
unconfigure::<_, hal::api::Gles>(self, &surface.raw, &present);
}
self.instance.destroy_surface(surface);
@@ -711,7 +703,7 @@ impl Global {
&self,
_: A,
instance: &Option<A::Instance>,
inputs: &AdapterInputs<markers::Adapter>,
inputs: &AdapterInputs<Input<G, AdapterId>>,
list: &mut Vec<AdapterId>,
) {
let inst = match *instance {
@@ -730,12 +722,12 @@ impl Global {
for raw in hal_adapters {
let adapter = Adapter::new(raw);
log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info);
let (id, _) = hub.adapters.prepare(id_backend).assign(adapter);
let (id, _) = hub.adapters.prepare::<G>(id_backend).assign(adapter);
list.push(id);
}
}
pub fn enumerate_adapters(&self, inputs: AdapterInputs<markers::Adapter>) -> Vec<AdapterId> {
pub fn enumerate_adapters(&self, inputs: AdapterInputs<Input<G, AdapterId>>) -> Vec<AdapterId> {
profiling::scope!("Instance::enumerate_adapters");
api_log!("Instance::enumerate_adapters");
@@ -766,7 +758,7 @@ impl Global {
fn select<A: HalApi>(
&self,
selected: &mut usize,
new_id: Option<AdapterId>,
new_id: Option<Input<G, AdapterId>>,
mut list: Vec<hal::ExposedAdapter<A>>,
) -> Option<AdapterId> {
match selected.checked_sub(list.len()) {
@@ -777,7 +769,10 @@ impl Global {
None => {
let adapter = Adapter::new(list.swap_remove(*selected));
log::info!("Adapter {:?} {:?}", A::VARIANT, adapter.raw.info);
let (id, _) = HalApi::hub(self).adapters.prepare(new_id).assign(adapter);
let (id, _) = HalApi::hub(self)
.adapters
.prepare::<G>(new_id.unwrap())
.assign(adapter);
Some(id)
}
}
@@ -786,22 +781,22 @@ impl Global {
pub fn request_adapter(
&self,
desc: &RequestAdapterOptions,
inputs: AdapterInputs<markers::Adapter>,
inputs: AdapterInputs<Input<G, AdapterId>>,
) -> Result<AdapterId, RequestAdapterError> {
profiling::scope!("Instance::request_adapter");
api_log!("Instance::request_adapter");
fn gather<A: HalApi>(
fn gather<A: HalApi, I: Copy>(
_: A,
instance: Option<&A::Instance>,
inputs: &AdapterInputs<markers::Adapter>,
inputs: &AdapterInputs<I>,
compatible_surface: Option<&Surface>,
force_software: bool,
device_types: &mut Vec<wgt::DeviceType>,
) -> (Option<Id<markers::Adapter>>, Vec<hal::ExposedAdapter<A>>) {
) -> (Option<I>, Vec<hal::ExposedAdapter<A>>) {
let id = inputs.find(A::VARIANT);
match (id, instance) {
(Some(id), Some(inst)) => {
match instance {
Some(inst) if id.is_some() => {
let mut adapters = unsafe { inst.enumerate_adapters() };
if force_software {
adapters.retain(|exposed| exposed.info.device_type == wgt::DeviceType::Cpu);
@@ -821,7 +816,7 @@ impl Global {
device_types.extend(adapters.iter().map(|ad| ad.info.device_type));
(id, adapters)
}
_ => (None, Vec::new()),
_ => (id, Vec::new()),
}
}
@@ -952,23 +947,24 @@ impl Global {
pub unsafe fn create_adapter_from_hal<A: HalApi>(
&self,
hal_adapter: hal::ExposedAdapter<A>,
input: Option<AdapterId>,
input: Input<G, AdapterId>,
) -> AdapterId {
profiling::scope!("Instance::create_adapter_from_hal");
let fid = A::hub(self).adapters.prepare(input);
let fid = A::hub(self).adapters.prepare::<G>(input);
let (id, _adapter): (_, Arc<Adapter<A>>) = match A::VARIANT {
#[cfg(vulkan)]
Backend::Vulkan => fid.assign(Adapter::new(hal_adapter)),
#[cfg(metal)]
Backend::Metal => fid.assign(Adapter::new(hal_adapter)),
#[cfg(dx12)]
Backend::Dx12 => fid.assign(Adapter::new(hal_adapter)),
#[cfg(gles)]
Backend::Gl => fid.assign(Adapter::new(hal_adapter)),
_ => unreachable!(),
};
let (id, _adapter): (crate::id::Id<Adapter<hal::empty::Api>>, Arc<Adapter<A>>) =
match A::VARIANT {
#[cfg(vulkan)]
Backend::Vulkan => fid.assign(Adapter::new(hal_adapter)),
#[cfg(metal)]
Backend::Metal => fid.assign(Adapter::new(hal_adapter)),
#[cfg(dx12)]
Backend::Dx12 => fid.assign(Adapter::new(hal_adapter)),
#[cfg(gles)]
Backend::Gl => fid.assign(Adapter::new(hal_adapter)),
_ => unreachable!(),
};
resource_log!("Created Adapter {:?}", id);
id
}
@@ -1063,21 +1059,21 @@ impl Global {
}
}
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn adapter_request_device<A: HalApi>(
&self,
adapter_id: AdapterId,
desc: &DeviceDescriptor,
trace_path: Option<&std::path::Path>,
device_id_in: Option<DeviceId>,
queue_id_in: Option<QueueId>,
device_id_in: Input<G, DeviceId>,
queue_id_in: Input<G, QueueId>,
) -> (DeviceId, QueueId, Option<RequestDeviceError>) {
profiling::scope!("Adapter::request_device");
api_log!("Adapter::request_device");
let hub = A::hub(self);
let device_fid = hub.devices.prepare(device_id_in);
let queue_fid = hub.queues.prepare(queue_id_in);
let device_fid = hub.devices.prepare::<G>(device_id_in);
let queue_fid = hub.queues.prepare::<G>(queue_id_in);
let error = loop {
let adapter = match hub.adapters.get(adapter_id) {
@@ -1118,14 +1114,14 @@ impl Global {
hal_device: OpenDevice<A>,
desc: &DeviceDescriptor,
trace_path: Option<&std::path::Path>,
device_id_in: Option<DeviceId>,
queue_id_in: Option<QueueId>,
device_id_in: Input<G, DeviceId>,
queue_id_in: Input<G, QueueId>,
) -> (DeviceId, QueueId, Option<RequestDeviceError>) {
profiling::scope!("Global::create_device_from_hal");
let hub = A::hub(self);
let devices_fid = hub.devices.prepare(device_id_in);
let queues_fid = hub.queues.prepare(queue_id_in);
let devices_fid = hub.devices.prepare::<G>(device_id_in);
let queues_fid = hub.queues.prepare::<G>(queue_id_in);
let error = loop {
let adapter = match hub.adapters.get(adapter_id) {

View File

@@ -13,9 +13,9 @@
//! [https://renderdoc.org/](https://renderdoc.org/)
//! - **`strict_asserts`** --- Apply run-time checks, even in release builds. These are in addition
//! to the validation carried out at public APIs in all builds.
//! - **`serde`** --- Enables serialization via `serde` on common wgpu types.
//! - **`trace`** --- Enable API tracing.
//! - **`replay`** --- Enable API replaying
//! - **`serial-pass`** --- Enable serializable compute/render passes, and bundle encoders.
//! - **`wgsl`** --- Enable `ShaderModuleSource::Wgsl`
//! - **`fragile-send-sync-non-atomic-wasm`** --- Implement `Send` and `Sync` on Wasm, but only if
//! atomics are not enabled.
@@ -289,7 +289,7 @@ define_backend_caller! { gfx_if_empty, gfx_if_empty_hidden, "empty" if all(
/// where the `device_create_buffer` method is defined like this:
///
/// ```ignore
/// impl Global {
/// impl<...> Global<...> {
/// pub fn device_create_buffer<A: HalApi>(&self, ...) -> ...
/// { ... }
/// }

View File

@@ -5,7 +5,7 @@ use crate::{
command::ColorAttachmentError,
device::{Device, DeviceError, MissingDownlevelFlags, MissingFeatures, RenderPassContext},
hal_api::HalApi,
id::{PipelineLayoutId, ShaderModuleId},
id::{ComputePipelineId, PipelineLayoutId, RenderPipelineId, ShaderModuleId},
resource::{Resource, ResourceInfo, ResourceType},
resource_log, validation, Label,
};
@@ -26,10 +26,6 @@ pub(crate) struct LateSizedBufferGroup {
pub enum ShaderModuleSource<'a> {
#[cfg(feature = "wgsl")]
Wgsl(Cow<'a, str>),
#[cfg(feature = "glsl")]
Glsl(Cow<'a, str>, naga::front::glsl::Options),
#[cfg(feature = "spirv")]
SpirV(Cow<'a, [u32]>, naga::front::spv::Options),
Naga(Cow<'static, naga::Module>),
/// Dummy variant because `Naga` doesn't have a lifetime and without enough active features it
/// could be the last one active.
@@ -38,7 +34,8 @@ pub enum ShaderModuleSource<'a> {
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ShaderModuleDescriptor<'a> {
pub label: Label<'a>,
#[cfg_attr(feature = "serde", serde(default))]
@@ -50,7 +47,7 @@ pub struct ShaderModule<A: HalApi> {
pub(crate) raw: Option<A::ShaderModule>,
pub(crate) device: Arc<Device<A>>,
pub(crate) interface: Option<validation::Interface>,
pub(crate) info: ResourceInfo<ShaderModule<A>>,
pub(crate) info: ResourceInfo<ShaderModuleId>,
pub(crate) label: String,
}
@@ -70,16 +67,14 @@ impl<A: HalApi> Drop for ShaderModule<A> {
}
}
impl<A: HalApi> Resource for ShaderModule<A> {
impl<A: HalApi> Resource<ShaderModuleId> for ShaderModule<A> {
const TYPE: ResourceType = "ShaderModule";
type Marker = crate::id::markers::ShaderModule;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<ShaderModuleId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<ShaderModuleId> {
&mut self.info
}
@@ -108,22 +103,6 @@ impl fmt::Display for ShaderError<naga::front::wgsl::ParseError> {
write!(f, "\nShader '{label}' parsing {string}")
}
}
#[cfg(feature = "glsl")]
impl fmt::Display for ShaderError<naga::front::glsl::ParseError> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let label = self.label.as_deref().unwrap_or_default();
let string = self.inner.emit_to_string(&self.source);
write!(f, "\nShader '{label}' parsing {string}")
}
}
#[cfg(feature = "spirv")]
impl fmt::Display for ShaderError<naga::front::spv::Error> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let label = self.label.as_deref().unwrap_or_default();
let string = self.inner.emit_to_string(&self.source);
write!(f, "\nShader '{label}' parsing {string}")
}
}
impl fmt::Display for ShaderError<naga::WithSpan<naga::valid::ValidationError>> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use codespan_reporting::{
@@ -172,12 +151,6 @@ pub enum CreateShaderModuleError {
#[cfg(feature = "wgsl")]
#[error(transparent)]
Parsing(#[from] ShaderError<naga::front::wgsl::ParseError>),
#[cfg(feature = "glsl")]
#[error(transparent)]
ParsingGlsl(#[from] ShaderError<naga::front::glsl::ParseError>),
#[cfg(feature = "spirv")]
#[error(transparent)]
ParsingSpirV(#[from] ShaderError<naga::front::spv::Error>),
#[error("Failed to generate the backend-specific code")]
Generation,
#[error(transparent)]
@@ -209,7 +182,8 @@ impl CreateShaderModuleError {
/// Describes a programmable pipeline stage.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ProgrammableStageDescriptor<'a> {
/// The compiled shader module for this stage.
pub module: ShaderModuleId,
@@ -236,7 +210,8 @@ pub enum ImplicitLayoutError {
/// Describes a compute pipeline.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ComputePipelineDescriptor<'a> {
pub label: Label<'a>,
/// The layout of bind groups for this pipeline.
@@ -269,7 +244,7 @@ pub struct ComputePipeline<A: HalApi> {
pub(crate) device: Arc<Device<A>>,
pub(crate) _shader_module: Arc<ShaderModule<A>>,
pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
pub(crate) info: ResourceInfo<ComputePipeline<A>>,
pub(crate) info: ResourceInfo<ComputePipelineId>,
}
impl<A: HalApi> Drop for ComputePipeline<A> {
@@ -290,16 +265,14 @@ impl<A: HalApi> Drop for ComputePipeline<A> {
}
}
impl<A: HalApi> Resource for ComputePipeline<A> {
impl<A: HalApi> Resource<ComputePipelineId> for ComputePipeline<A> {
const TYPE: ResourceType = "ComputePipeline";
type Marker = crate::id::markers::ComputePipeline;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<ComputePipelineId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<ComputePipelineId> {
&mut self.info
}
}
@@ -312,7 +285,8 @@ impl<A: HalApi> ComputePipeline<A> {
/// Describes how the vertex buffer is interpreted.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct VertexBufferLayout<'a> {
/// The stride, in bytes, between elements of this buffer.
@@ -325,7 +299,8 @@ pub struct VertexBufferLayout<'a> {
/// Describes the vertex process in a render pipeline.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct VertexState<'a> {
/// The compiled vertex stage and its entry point.
pub stage: ProgrammableStageDescriptor<'a>,
@@ -335,7 +310,8 @@ pub struct VertexState<'a> {
/// Describes fragment processing in a render pipeline.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct FragmentState<'a> {
/// The compiled fragment stage and its entry point.
pub stage: ProgrammableStageDescriptor<'a>,
@@ -345,7 +321,8 @@ pub struct FragmentState<'a> {
/// Describes a render (graphics) pipeline.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct RenderPipelineDescriptor<'a> {
pub label: Label<'a>,
/// The layout of bind groups for this pipeline.
@@ -353,13 +330,13 @@ pub struct RenderPipelineDescriptor<'a> {
/// The vertex processing state for this pipeline.
pub vertex: VertexState<'a>,
/// The properties of the pipeline at the primitive assembly and rasterization level.
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))]
pub primitive: wgt::PrimitiveState,
/// The effect of draw calls on the depth and stencil aspects of the output target, if any.
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))]
pub depth_stencil: Option<wgt::DepthStencilState>,
/// The multi-sampling properties of the pipeline.
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(any(feature = "replay", feature = "trace"), serde(default))]
pub multisample: wgt::MultisampleState,
/// The fragment processing state for this pipeline.
pub fragment: Option<FragmentState<'a>>,
@@ -490,9 +467,6 @@ pub struct VertexStep {
/// The byte stride in the buffer between one attribute value and the next.
pub stride: wgt::BufferAddress,
/// The byte size required to fit the last vertex in the stream.
pub last_stride: wgt::BufferAddress,
/// Whether the buffer is indexed by vertex number or instance number.
pub mode: wgt::VertexStepMode,
}
@@ -501,7 +475,6 @@ impl Default for VertexStep {
fn default() -> Self {
Self {
stride: 0,
last_stride: 0,
mode: wgt::VertexStepMode::Vertex,
}
}
@@ -519,7 +492,7 @@ pub struct RenderPipeline<A: HalApi> {
pub(crate) strip_index_format: Option<wgt::IndexFormat>,
pub(crate) vertex_steps: Vec<VertexStep>,
pub(crate) late_sized_buffer_groups: ArrayVec<LateSizedBufferGroup, { hal::MAX_BIND_GROUPS }>,
pub(crate) info: ResourceInfo<RenderPipeline<A>>,
pub(crate) info: ResourceInfo<RenderPipelineId>,
}
impl<A: HalApi> Drop for RenderPipeline<A> {
@@ -540,16 +513,14 @@ impl<A: HalApi> Drop for RenderPipeline<A> {
}
}
impl<A: HalApi> Resource for RenderPipeline<A> {
impl<A: HalApi> Resource<RenderPipelineId> for RenderPipeline<A> {
const TYPE: ResourceType = "RenderPipeline";
type Marker = crate::id::markers::RenderPipeline;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<RenderPipelineId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<RenderPipelineId> {
&mut self.info
}
}

View File

@@ -22,7 +22,9 @@ use crate::{
device::{DeviceError, MissingDownlevelFlags, WaitIdleError},
global::Global,
hal_api::HalApi,
hal_label, id,
hal_label,
id::{SurfaceId, TextureId},
identity::{GlobalIdentityHandlerFactory, Input},
init_tracker::TextureInitTracker,
resource::{self, ResourceInfo},
snatch::Snatchable,
@@ -30,7 +32,7 @@ use crate::{
};
use hal::{Queue as _, Surface as _};
use parking_lot::{Mutex, RwLock};
use parking_lot::RwLock;
use thiserror::Error;
use wgt::SurfaceStatus as Status;
@@ -40,7 +42,7 @@ const FRAME_TIMEOUT_MS: u32 = 1000;
pub(crate) struct Presentation {
pub(crate) device: AnyDevice,
pub(crate) config: wgt::SurfaceConfiguration<Vec<wgt::TextureFormat>>,
pub(crate) acquired_texture: Option<id::TextureId>,
pub(crate) acquired_texture: Option<TextureId>,
}
#[derive(Clone, Debug, Error)]
@@ -116,20 +118,20 @@ impl From<WaitIdleError> for ConfigureSurfaceError {
#[derive(Debug)]
pub struct SurfaceOutput {
pub status: Status,
pub texture_id: Option<id::TextureId>,
pub texture_id: Option<TextureId>,
}
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
pub fn surface_get_current_texture<A: HalApi>(
&self,
surface_id: id::SurfaceId,
texture_id_in: Option<id::TextureId>,
surface_id: SurfaceId,
texture_id_in: Input<G, TextureId>,
) -> Result<SurfaceOutput, SurfaceError> {
profiling::scope!("SwapChain::get_next_texture");
let hub = A::hub(self);
let fid = hub.textures.prepare(texture_id_in);
let fid = hub.textures.prepare::<G>(texture_id_in);
let surface = self
.surfaces
@@ -229,8 +231,6 @@ impl Global {
clear_mode: RwLock::new(resource::TextureClearMode::Surface {
clear_view: Some(clear_view),
}),
views: Mutex::new(Vec::new()),
bind_groups: Mutex::new(Vec::new()),
};
let (id, resource) = fid.assign(texture);
@@ -278,7 +278,7 @@ impl Global {
pub fn surface_present<A: HalApi>(
&self,
surface_id: id::SurfaceId,
surface_id: SurfaceId,
) -> Result<Status, SurfaceError> {
profiling::scope!("SwapChain::present");
@@ -376,7 +376,7 @@ impl Global {
pub fn surface_texture_discard<A: HalApi>(
&self,
surface_id: id::SurfaceId,
surface_id: SurfaceId,
) -> Result<(), SurfaceError> {
profiling::scope!("SwapChain::discard");

View File

@@ -4,8 +4,8 @@ use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use wgt::Backend;
use crate::{
id::Id,
identity::IdentityManager,
id,
identity::{IdentityHandlerFactory, IdentityManager},
resource::Resource,
storage::{Element, InvalidId, Storage},
};
@@ -37,40 +37,40 @@ impl RegistryReport {
/// any other dependent resource
///
#[derive(Debug)]
pub struct Registry<T: Resource> {
identity: Arc<IdentityManager<T::Marker>>,
storage: RwLock<Storage<T>>,
pub struct Registry<I: id::TypedId, T: Resource<I>> {
identity: Arc<IdentityManager<I>>,
storage: RwLock<Storage<T, I>>,
backend: Backend,
}
impl<T: Resource> Registry<T> {
pub(crate) fn new(backend: Backend) -> Self {
impl<I: id::TypedId, T: Resource<I>> Registry<I, T> {
pub(crate) fn new<F: IdentityHandlerFactory<I>>(backend: Backend, factory: &F) -> Self {
Self {
identity: Arc::new(IdentityManager::new()),
identity: factory.spawn(),
storage: RwLock::new(Storage::new()),
backend,
}
}
pub(crate) fn without_backend() -> Self {
Self::new(Backend::Empty)
pub(crate) fn without_backend<F: IdentityHandlerFactory<I>>(factory: &F) -> Self {
Self::new(Backend::Empty, factory)
}
}
#[must_use]
pub(crate) struct FutureId<'a, T: Resource> {
id: Id<T::Marker>,
identity: Arc<IdentityManager<T::Marker>>,
data: &'a RwLock<Storage<T>>,
pub(crate) struct FutureId<'a, I: id::TypedId, T: Resource<I>> {
id: I,
identity: Arc<IdentityManager<I>>,
data: &'a RwLock<Storage<T, I>>,
}
impl<T: Resource> FutureId<'_, T> {
impl<I: id::TypedId + Copy, T: Resource<I>> FutureId<'_, I, T> {
#[allow(dead_code)]
pub fn id(&self) -> Id<T::Marker> {
pub fn id(&self) -> I {
self.id
}
pub fn into_id(self) -> Id<T::Marker> {
pub fn into_id(self) -> I {
self.id
}
@@ -82,7 +82,7 @@ impl<T: Resource> FutureId<'_, T> {
/// Assign a new resource to this ID.
///
/// Registers it with the registry, and fills out the resource info.
pub fn assign(self, value: T) -> (Id<T::Marker>, Arc<T>) {
pub fn assign(self, value: T) -> (I, Arc<T>) {
let mut data = self.data.write();
data.insert(self.id, self.init(value));
(self.id, data.get(self.id).unwrap().clone())
@@ -94,73 +94,73 @@ impl<T: Resource> FutureId<'_, T> {
///
/// This _will_ leak the ID, and it will not be recycled again.
/// See https://github.com/gfx-rs/wgpu/issues/4912.
pub fn assign_existing(self, value: &Arc<T>) -> Id<T::Marker> {
pub fn assign_existing(self, value: &Arc<T>) -> I {
let mut data = self.data.write();
debug_assert!(!data.contains(self.id));
data.insert(self.id, value.clone());
self.id
}
pub fn assign_error(self, label: &str) -> Id<T::Marker> {
pub fn assign_error(self, label: &str) -> I {
self.data.write().insert_error(self.id, label);
self.id
}
}
impl<T: Resource> Registry<T> {
pub(crate) fn prepare(&self, id_in: Option<Id<T::Marker>>) -> FutureId<T> {
impl<I: id::TypedId, T: Resource<I>> Registry<I, T> {
pub(crate) fn prepare<F>(&self, id_in: F::Input) -> FutureId<I, T>
where
F: IdentityHandlerFactory<I>,
{
FutureId {
id: match id_in {
Some(id_in) => {
self.identity.mark_as_used(id_in);
id_in
}
None => self.identity.process(self.backend),
id: if F::autogenerate_ids() {
self.identity.process(self.backend)
} else {
self.identity.mark_as_used(F::input_to_id(id_in))
},
identity: self.identity.clone(),
data: &self.storage,
}
}
pub(crate) fn request(&self) -> FutureId<T> {
pub(crate) fn request(&self) -> FutureId<I, T> {
FutureId {
id: self.identity.process(self.backend),
identity: self.identity.clone(),
data: &self.storage,
}
}
pub(crate) fn try_get(&self, id: Id<T::Marker>) -> Result<Option<Arc<T>>, InvalidId> {
pub(crate) fn try_get(&self, id: I) -> Result<Option<Arc<T>>, InvalidId> {
self.read().try_get(id).map(|o| o.cloned())
}
pub(crate) fn get(&self, id: Id<T::Marker>) -> Result<Arc<T>, InvalidId> {
pub(crate) fn get(&self, id: I) -> Result<Arc<T>, InvalidId> {
self.read().get_owned(id)
}
pub(crate) fn read<'a>(&'a self) -> RwLockReadGuard<'a, Storage<T>> {
pub(crate) fn read<'a>(&'a self) -> RwLockReadGuard<'a, Storage<T, I>> {
self.storage.read()
}
pub(crate) fn write<'a>(&'a self) -> RwLockWriteGuard<'a, Storage<T>> {
pub(crate) fn write<'a>(&'a self) -> RwLockWriteGuard<'a, Storage<T, I>> {
self.storage.write()
}
pub fn unregister_locked(&self, id: Id<T::Marker>, storage: &mut Storage<T>) -> Option<Arc<T>> {
pub fn unregister_locked(&self, id: I, storage: &mut Storage<T, I>) -> Option<Arc<T>> {
storage.remove(id)
}
pub fn force_replace(&self, id: Id<T::Marker>, mut value: T) {
pub fn force_replace(&self, id: I, mut value: T) {
let mut storage = self.storage.write();
value.as_info_mut().set_id(id, &self.identity);
storage.force_replace(id, value)
}
pub fn force_replace_with_error(&self, id: Id<T::Marker>, label: &str) {
pub fn force_replace_with_error(&self, id: I, label: &str) {
let mut storage = self.storage.write();
storage.remove(id);
storage.insert_error(id, label);
}
pub(crate) fn unregister(&self, id: Id<T::Marker>) -> Option<Arc<T>> {
pub(crate) fn unregister(&self, id: I) -> Option<Arc<T>> {
let value = self.storage.write().remove(id);
//Returning None is legal if it's an error ID
value
}
pub fn label_for_resource(&self, id: Id<T::Marker>) -> String {
pub fn label_for_resource(&self, id: I) -> String {
let guard = self.storage.read();
let type_name = guard.kind();

View File

@@ -1,15 +1,17 @@
#[cfg(feature = "trace")]
use crate::device::trace;
use crate::{
binding_model::BindGroup,
device::{
queue, BufferMapPendingClosure, Device, DeviceError, HostMap, MissingDownlevelFlags,
MissingFeatures,
},
global::Global,
hal_api::HalApi,
id::{AdapterId, BufferId, DeviceId, Id, Marker, SurfaceId, TextureId},
identity::IdentityManager,
id::{
AdapterId, BufferId, DeviceId, QuerySetId, SamplerId, StagingBufferId, SurfaceId,
TextureId, TextureViewId, TypedId,
},
identity::{GlobalIdentityHandlerFactory, IdentityManager},
init_tracker::{BufferInitTracker, TextureInitTracker},
resource, resource_log,
snatch::{ExclusiveSnatchGuard, SnatchGuard, Snatchable},
@@ -32,7 +34,7 @@ use std::{
ptr::NonNull,
sync::{
atomic::{AtomicBool, AtomicUsize, Ordering},
Arc, Weak,
Arc,
},
};
@@ -56,9 +58,9 @@ use std::{
/// [`Device`]: crate::device::resource::Device
/// [`Buffer`]: crate::resource::Buffer
#[derive(Debug)]
pub struct ResourceInfo<T: Resource> {
id: Option<Id<T::Marker>>,
identity: Option<Arc<IdentityManager<T::Marker>>>,
pub struct ResourceInfo<Id: TypedId> {
id: Option<Id>,
identity: Option<Arc<IdentityManager<Id>>>,
/// The index of the last queue submission in which the resource
/// was used.
///
@@ -72,7 +74,7 @@ pub struct ResourceInfo<T: Resource> {
pub(crate) label: String,
}
impl<T: Resource> Drop for ResourceInfo<T> {
impl<Id: TypedId> Drop for ResourceInfo<Id> {
fn drop(&mut self) {
if let Some(identity) = self.identity.as_ref() {
let id = self.id.as_ref().unwrap();
@@ -81,7 +83,7 @@ impl<T: Resource> Drop for ResourceInfo<T> {
}
}
impl<T: Resource> ResourceInfo<T> {
impl<Id: TypedId> ResourceInfo<Id> {
#[allow(unused_variables)]
pub(crate) fn new(label: &str) -> Self {
Self {
@@ -94,7 +96,7 @@ impl<T: Resource> ResourceInfo<T> {
pub(crate) fn label(&self) -> &dyn Debug
where
Id<T::Marker>: Debug,
Id: Debug,
{
if !self.label.is_empty() {
return &self.label;
@@ -107,11 +109,11 @@ impl<T: Resource> ResourceInfo<T> {
&""
}
pub(crate) fn id(&self) -> Id<T::Marker> {
pub(crate) fn id(&self) -> Id {
self.id.unwrap()
}
pub(crate) fn set_id(&mut self, id: Id<T::Marker>, identity: &Arc<IdentityManager<T::Marker>>) {
pub(crate) fn set_id(&mut self, id: Id, identity: &Arc<IdentityManager<Id>>) {
self.id = Some(id);
self.identity = Some(identity.clone());
}
@@ -130,11 +132,10 @@ impl<T: Resource> ResourceInfo<T> {
pub(crate) type ResourceType = &'static str;
pub trait Resource: 'static + Sized + WasmNotSendSync {
type Marker: Marker;
pub trait Resource<Id: TypedId>: 'static + WasmNotSendSync {
const TYPE: ResourceType;
fn as_info(&self) -> &ResourceInfo<Self>;
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self>;
fn as_info(&self) -> &ResourceInfo<Id>;
fn as_info_mut(&mut self) -> &mut ResourceInfo<Id>;
fn label(&self) -> String {
self.as_info().label.clone()
}
@@ -375,9 +376,8 @@ pub struct Buffer<A: HalApi> {
pub(crate) size: wgt::BufferAddress,
pub(crate) initialization_status: RwLock<BufferInitTracker>,
pub(crate) sync_mapped_writes: Mutex<Option<hal::MemoryRange>>,
pub(crate) info: ResourceInfo<Buffer<A>>,
pub(crate) info: ResourceInfo<BufferId>,
pub(crate) map_state: Mutex<BufferMapState<A>>,
pub(crate) bind_groups: Mutex<Vec<Weak<BindGroup<A>>>>,
}
impl<A: HalApi> Drop for Buffer<A> {
@@ -541,18 +541,12 @@ impl<A: HalApi> Buffer<A> {
}
};
let bind_groups = {
let mut guard = self.bind_groups.lock();
std::mem::take(&mut *guard)
};
queue::TempResource::DestroyedBuffer(Arc::new(DestroyedBuffer {
raw: Some(raw),
device: Arc::clone(&self.device),
submission_index: self.info.submission_index(),
id: self.info.id.unwrap(),
label: self.info.label.clone(),
bind_groups,
}))
};
@@ -590,43 +584,18 @@ pub enum CreateBufferError {
MissingDownlevelFlags(#[from] MissingDownlevelFlags),
}
impl<A: HalApi> Resource for Buffer<A> {
impl<A: HalApi> Resource<BufferId> for Buffer<A> {
const TYPE: ResourceType = "Buffer";
type Marker = crate::id::markers::Buffer;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<BufferId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<BufferId> {
&mut self.info
}
}
fn snatch_and_destroy_bind_groups<A: HalApi>(
device: &Device<A>,
bind_groups: &[Weak<BindGroup<A>>],
) {
for bind_group in bind_groups {
if let Some(bind_group) = bind_group.upgrade() {
if let Some(raw_bind_group) = bind_group.raw.snatch(device.snatchable_lock.write()) {
resource_log!("Destroy raw BindGroup (destroyed) {:?}", bind_group.label());
#[cfg(feature = "trace")]
if let Some(t) = device.trace.lock().as_mut() {
t.add(trace::Action::DestroyBindGroup(bind_group.info.id()));
}
unsafe {
use hal::Device;
device.raw().destroy_bind_group(raw_bind_group);
}
}
}
}
}
/// A buffer that has been marked as destroyed and is staged for actual deletion soon.
#[derive(Debug)]
pub struct DestroyedBuffer<A: HalApi> {
@@ -635,7 +604,6 @@ pub struct DestroyedBuffer<A: HalApi> {
label: String,
pub(crate) id: BufferId,
pub(crate) submission_index: u64,
bind_groups: Vec<Weak<BindGroup<A>>>,
}
impl<A: HalApi> DestroyedBuffer<A> {
@@ -650,8 +618,6 @@ impl<A: HalApi> DestroyedBuffer<A> {
impl<A: HalApi> Drop for DestroyedBuffer<A> {
fn drop(&mut self) {
snatch_and_destroy_bind_groups(&self.device, &self.bind_groups);
if let Some(raw) = self.raw.take() {
resource_log!("Destroy raw Buffer (destroyed) {:?}", self.label());
@@ -693,7 +659,7 @@ pub struct StagingBuffer<A: HalApi> {
pub(crate) device: Arc<Device<A>>,
pub(crate) size: wgt::BufferAddress,
pub(crate) is_coherent: bool,
pub(crate) info: ResourceInfo<StagingBuffer<A>>,
pub(crate) info: ResourceInfo<StagingBufferId>,
}
impl<A: HalApi> Drop for StagingBuffer<A> {
@@ -708,16 +674,14 @@ impl<A: HalApi> Drop for StagingBuffer<A> {
}
}
impl<A: HalApi> Resource for StagingBuffer<A> {
impl<A: HalApi> Resource<StagingBufferId> for StagingBuffer<A> {
const TYPE: ResourceType = "StagingBuffer";
type Marker = crate::id::markers::StagingBuffer;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<StagingBufferId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<StagingBufferId> {
&mut self.info
}
@@ -775,10 +739,8 @@ pub struct Texture<A: HalApi> {
pub(crate) format_features: wgt::TextureFormatFeatures,
pub(crate) initialization_status: RwLock<TextureInitTracker>,
pub(crate) full_range: TextureSelector,
pub(crate) info: ResourceInfo<Texture<A>>,
pub(crate) info: ResourceInfo<TextureId>,
pub(crate) clear_mode: RwLock<TextureClearMode<A>>,
pub(crate) views: Mutex<Vec<Weak<TextureView<A>>>>,
pub(crate) bind_groups: Mutex<Vec<Weak<BindGroup<A>>>>,
}
impl<A: HalApi> Drop for Texture<A> {
@@ -890,20 +852,8 @@ impl<A: HalApi> Texture<A> {
}
};
let views = {
let mut guard = self.views.lock();
std::mem::take(&mut *guard)
};
let bind_groups = {
let mut guard = self.bind_groups.lock();
std::mem::take(&mut *guard)
};
queue::TempResource::DestroyedTexture(Arc::new(DestroyedTexture {
raw: Some(raw),
views,
bind_groups,
device: Arc::clone(&self.device),
submission_index: self.info.submission_index(),
id: self.info.id.unwrap(),
@@ -926,7 +876,7 @@ impl<A: HalApi> Texture<A> {
}
}
impl Global {
impl<G: GlobalIdentityHandlerFactory> Global<G> {
/// # Safety
///
/// - The raw texture handle must not be manually destroyed
@@ -1020,8 +970,6 @@ impl Global {
#[derive(Debug)]
pub struct DestroyedTexture<A: HalApi> {
raw: Option<A::Texture>,
views: Vec<Weak<TextureView<A>>>,
bind_groups: Vec<Weak<BindGroup<A>>>,
device: Arc<Device<A>>,
label: String,
pub(crate) id: TextureId,
@@ -1040,26 +988,6 @@ impl<A: HalApi> DestroyedTexture<A> {
impl<A: HalApi> Drop for DestroyedTexture<A> {
fn drop(&mut self) {
let device = &self.device;
snatch_and_destroy_bind_groups(device, &self.bind_groups);
for view in self.views.drain(..) {
if let Some(view) = view.upgrade() {
if let Some(raw_view) = view.raw.snatch(device.snatchable_lock.write()) {
resource_log!("Destroy raw TextureView (destroyed) {:?}", view.label());
#[cfg(feature = "trace")]
if let Some(t) = self.device.trace.lock().as_mut() {
t.add(trace::Action::DestroyTextureView(view.info.id()));
}
unsafe {
use hal::Device;
self.device.raw().destroy_texture_view(raw_view);
}
}
}
}
if let Some(raw) = self.raw.take() {
resource_log!("Destroy raw Texture (destroyed) {:?}", self.label());
@@ -1168,16 +1096,14 @@ pub enum CreateTextureError {
MissingDownlevelFlags(#[from] MissingDownlevelFlags),
}
impl<A: HalApi> Resource for Texture<A> {
impl<A: HalApi> Resource<TextureId> for Texture<A> {
const TYPE: ResourceType = "Texture";
type Marker = crate::id::markers::Texture;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<TextureId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<TextureId> {
&mut self.info
}
}
@@ -1190,8 +1116,8 @@ impl<A: HalApi> Borrow<TextureSelector> for Texture<A> {
/// Describes a [`TextureView`].
#[derive(Clone, Debug, Default, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize), serde(default))]
pub struct TextureViewDescriptor<'a> {
/// Debug label of the texture view.
///
@@ -1244,9 +1170,9 @@ pub enum TextureViewNotRenderableReason {
#[derive(Debug)]
pub struct TextureView<A: HalApi> {
pub(crate) raw: Snatchable<A::TextureView>,
pub(crate) raw: Option<A::TextureView>,
// if it's a surface texture - it's none
pub(crate) parent: Arc<Texture<A>>,
pub(crate) parent: RwLock<Option<Arc<Texture<A>>>>,
pub(crate) device: Arc<Device<A>>,
//TODO: store device_id for quick access?
pub(crate) desc: HalTextureViewDescriptor,
@@ -1255,7 +1181,7 @@ pub struct TextureView<A: HalApi> {
pub(crate) render_extent: Result<wgt::Extent3d, TextureViewNotRenderableReason>,
pub(crate) samples: u32,
pub(crate) selector: TextureSelector,
pub(crate) info: ResourceInfo<TextureView<A>>,
pub(crate) info: ResourceInfo<TextureViewId>,
}
impl<A: HalApi> Drop for TextureView<A> {
@@ -1277,8 +1203,8 @@ impl<A: HalApi> Drop for TextureView<A> {
}
impl<A: HalApi> TextureView<A> {
pub(crate) fn raw<'a>(&'a self, snatch_guard: &'a SnatchGuard) -> Option<&'a A::TextureView> {
self.raw.get(snatch_guard)
pub(crate) fn raw(&self) -> &A::TextureView {
self.raw.as_ref().unwrap()
}
}
@@ -1333,23 +1259,22 @@ pub enum CreateTextureViewError {
#[non_exhaustive]
pub enum TextureViewDestroyError {}
impl<A: HalApi> Resource for TextureView<A> {
impl<A: HalApi> Resource<TextureViewId> for TextureView<A> {
const TYPE: ResourceType = "TextureView";
type Marker = crate::id::markers::TextureView;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<TextureViewId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<TextureViewId> {
&mut self.info
}
}
/// Describes a [`Sampler`]
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct SamplerDescriptor<'a> {
/// Debug label of the sampler.
///
@@ -1380,7 +1305,7 @@ pub struct SamplerDescriptor<'a> {
pub struct Sampler<A: HalApi> {
pub(crate) raw: Option<A::Sampler>,
pub(crate) device: Arc<Device<A>>,
pub(crate) info: ResourceInfo<Self>,
pub(crate) info: ResourceInfo<SamplerId>,
/// `true` if this is a comparison sampler
pub(crate) comparison: bool,
/// `true` if this is a filtering sampler
@@ -1454,16 +1379,14 @@ pub enum CreateSamplerError {
MissingFeatures(#[from] MissingFeatures),
}
impl<A: HalApi> Resource for Sampler<A> {
impl<A: HalApi> Resource<SamplerId> for Sampler<A> {
const TYPE: ResourceType = "Sampler";
type Marker = crate::id::markers::Sampler;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<SamplerId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<SamplerId> {
&mut self.info
}
}
@@ -1487,7 +1410,7 @@ pub type QuerySetDescriptor<'a> = wgt::QuerySetDescriptor<Label<'a>>;
pub struct QuerySet<A: HalApi> {
pub(crate) raw: Option<A::QuerySet>,
pub(crate) device: Arc<Device<A>>,
pub(crate) info: ResourceInfo<Self>,
pub(crate) info: ResourceInfo<QuerySetId>,
pub(crate) desc: wgt::QuerySetDescriptor<()>,
}
@@ -1508,16 +1431,14 @@ impl<A: HalApi> Drop for QuerySet<A> {
}
}
impl<A: HalApi> Resource for QuerySet<A> {
impl<A: HalApi> Resource<QuerySetId> for QuerySet<A> {
const TYPE: ResourceType = "QuerySet";
type Marker = crate::id::markers::QuerySet;
fn as_info(&self) -> &ResourceInfo<Self> {
fn as_info(&self) -> &ResourceInfo<QuerySetId> {
&self.info
}
fn as_info_mut(&mut self) -> &mut ResourceInfo<Self> {
fn as_info_mut(&mut self) -> &mut ResourceInfo<QuerySetId> {
&mut self.info
}
}

View File

@@ -1,11 +1,8 @@
use std::ops;
use std::sync::Arc;
use std::{marker::PhantomData, ops, sync::Arc};
use wgt::Backend;
use crate::id::Id;
use crate::resource::Resource;
use crate::{Epoch, Index};
use crate::{id, resource::Resource, Epoch, Index};
/// An entry in a `Storage::map` table.
#[derive(Debug)]
@@ -33,41 +30,47 @@ pub(crate) struct InvalidId;
/// values, so you should use an id allocator like `IdentityManager`
/// that keeps the index values dense and close to zero.
#[derive(Debug)]
pub struct Storage<T>
pub struct Storage<T, I>
where
T: Resource,
T: Resource<I>,
I: id::TypedId,
{
pub(crate) map: Vec<Element<T>>,
kind: &'static str,
_phantom: PhantomData<I>,
}
impl<T> ops::Index<Id<T::Marker>> for Storage<T>
impl<T, I> ops::Index<I> for Storage<T, I>
where
T: Resource,
T: Resource<I>,
I: id::TypedId,
{
type Output = Arc<T>;
fn index(&self, id: Id<T::Marker>) -> &Arc<T> {
fn index(&self, id: I) -> &Arc<T> {
self.get(id).unwrap()
}
}
impl<T> Storage<T>
impl<T, I> Storage<T, I>
where
T: Resource,
T: Resource<I>,
I: id::TypedId,
{
pub(crate) fn new() -> Self {
Self {
map: Vec::new(),
kind: T::TYPE,
_phantom: PhantomData,
}
}
}
impl<T> Storage<T>
impl<T, I> Storage<T, I>
where
T: Resource,
T: Resource<I>,
I: id::TypedId,
{
#[allow(dead_code)]
pub(crate) fn contains(&self, id: Id<T::Marker>) -> bool {
pub(crate) fn contains(&self, id: I) -> bool {
let (index, epoch, _) = id.unzip();
match self.map.get(index as usize) {
Some(&Element::Vacant) => false,
@@ -85,7 +88,7 @@ where
/// This function is primarily intended for the `as_hal` family of functions
/// where you may need to fallibly get a object backed by an id that could
/// be in a different hub.
pub(crate) fn try_get(&self, id: Id<T::Marker>) -> Result<Option<&Arc<T>>, InvalidId> {
pub(crate) fn try_get(&self, id: I) -> Result<Option<&Arc<T>>, InvalidId> {
let (index, epoch, _) = id.unzip();
let (result, storage_epoch) = match self.map.get(index as usize) {
Some(&Element::Occupied(ref v, epoch)) => (Ok(Some(v)), epoch),
@@ -103,7 +106,7 @@ where
/// Get a reference to an item behind a potentially invalid ID.
/// Panics if there is an epoch mismatch, or the entry is empty.
pub(crate) fn get(&self, id: Id<T::Marker>) -> Result<&Arc<T>, InvalidId> {
pub(crate) fn get(&self, id: I) -> Result<&Arc<T>, InvalidId> {
let (index, epoch, _) = id.unzip();
let (result, storage_epoch) = match self.map.get(index as usize) {
Some(&Element::Occupied(ref v, epoch)) => (Ok(v), epoch),
@@ -121,11 +124,11 @@ where
/// Get an owned reference to an item behind a potentially invalid ID.
/// Panics if there is an epoch mismatch, or the entry is empty.
pub(crate) fn get_owned(&self, id: Id<T::Marker>) -> Result<Arc<T>, InvalidId> {
pub(crate) fn get_owned(&self, id: I) -> Result<Arc<T>, InvalidId> {
Ok(Arc::clone(self.get(id)?))
}
pub(crate) fn label_for_invalid_id(&self, id: Id<T::Marker>) -> &str {
pub(crate) fn label_for_invalid_id(&self, id: I) -> &str {
let (index, _, _) = id.unzip();
match self.map.get(index as usize) {
Some(Element::Error(_, label)) => label,
@@ -158,13 +161,13 @@ where
}
}
pub(crate) fn insert(&mut self, id: Id<T::Marker>, value: Arc<T>) {
pub(crate) fn insert(&mut self, id: I, value: Arc<T>) {
log::trace!("User is inserting {}{:?}", T::TYPE, id);
let (index, epoch, _backend) = id.unzip();
self.insert_impl(index as usize, epoch, Element::Occupied(value, epoch))
}
pub(crate) fn insert_error(&mut self, id: Id<T::Marker>, label: &str) {
pub(crate) fn insert_error(&mut self, id: I, label: &str) {
log::trace!("User is insering as error {}{:?}", T::TYPE, id);
let (index, epoch, _) = id.unzip();
self.insert_impl(
@@ -174,7 +177,7 @@ where
)
}
pub(crate) fn replace_with_error(&mut self, id: Id<T::Marker>) -> Result<Arc<T>, InvalidId> {
pub(crate) fn replace_with_error(&mut self, id: I) -> Result<Arc<T>, InvalidId> {
let (index, epoch, _) = id.unzip();
match std::mem::replace(
&mut self.map[index as usize],
@@ -189,13 +192,13 @@ where
}
}
pub(crate) fn force_replace(&mut self, id: Id<T::Marker>, value: T) {
pub(crate) fn force_replace(&mut self, id: I, value: T) {
log::trace!("User is replacing {}{:?}", T::TYPE, id);
let (index, epoch, _) = id.unzip();
self.map[index as usize] = Element::Occupied(Arc::new(value), epoch);
}
pub(crate) fn remove(&mut self, id: Id<T::Marker>) -> Option<Arc<T>> {
pub(crate) fn remove(&mut self, id: I) -> Option<Arc<T>> {
log::trace!("User is removing {}{:?}", T::TYPE, id);
let (index, epoch, _) = id.unzip();
match std::mem::replace(&mut self.map[index as usize], Element::Vacant) {
@@ -208,13 +211,13 @@ where
}
}
pub(crate) fn iter(&self, backend: Backend) -> impl Iterator<Item = (Id<T::Marker>, &Arc<T>)> {
pub(crate) fn iter(&self, backend: Backend) -> impl Iterator<Item = (I, &Arc<T>)> {
self.map
.iter()
.enumerate()
.filter_map(move |(index, x)| match *x {
Element::Occupied(ref value, storage_epoch) => {
Some((Id::zip(index as Index, storage_epoch, backend), value))
Some((I::zip(index as Index, storage_epoch, backend), value))
}
_ => None,
})

View File

@@ -10,7 +10,7 @@ use std::{borrow::Cow, marker::PhantomData, sync::Arc};
use super::{PendingTransition, ResourceTracker};
use crate::{
hal_api::HalApi,
id::BufferId,
id::{BufferId, TypedId},
resource::{Buffer, Resource},
snatch::SnatchGuard,
storage::Storage,
@@ -26,6 +26,7 @@ use wgt::{strict_assert, strict_assert_eq};
impl ResourceUses for BufferUses {
const EXCLUSIVE: Self = Self::EXCLUSIVE;
type Id = BufferId;
type Selector = ();
fn bits(self) -> u16 {
@@ -91,7 +92,7 @@ impl<A: HalApi> BufferBindGroupState<A> {
/// Adds the given resource with the given state.
pub fn add_single<'a>(
&self,
storage: &'a Storage<Buffer<A>>,
storage: &'a Storage<Buffer<A>, BufferId>,
id: BufferId,
state: BufferUses,
) -> Option<&'a Arc<Buffer<A>>> {
@@ -109,7 +110,7 @@ impl<A: HalApi> BufferBindGroupState<A> {
pub(crate) struct BufferUsageScope<A: HalApi> {
state: Vec<BufferUses>,
metadata: ResourceMetadata<A, Buffer<A>>,
metadata: ResourceMetadata<A, BufferId, Buffer<A>>,
}
impl<A: HalApi> BufferUsageScope<A> {
@@ -247,7 +248,7 @@ impl<A: HalApi> BufferUsageScope<A> {
/// the vectors will be extended. A call to set_size is not needed.
pub fn merge_single<'a>(
&mut self,
storage: &'a Storage<Buffer<A>>,
storage: &'a Storage<Buffer<A>, BufferId>,
id: BufferId,
new_state: BufferUses,
) -> Result<&'a Arc<Buffer<A>>, UsageConflict> {
@@ -287,12 +288,12 @@ pub(crate) struct BufferTracker<A: HalApi> {
start: Vec<BufferUses>,
end: Vec<BufferUses>,
metadata: ResourceMetadata<A, Buffer<A>>,
metadata: ResourceMetadata<A, BufferId, Buffer<A>>,
temp: Vec<PendingTransition<BufferUses>>,
}
impl<A: HalApi> ResourceTracker<Buffer<A>> for BufferTracker<A> {
impl<A: HalApi> ResourceTracker<BufferId, Buffer<A>> for BufferTracker<A> {
/// Try to remove the buffer `id` from this tracker if it is otherwise unused.
///
/// A buffer is 'otherwise unused' when the only references to it are:
@@ -653,11 +654,11 @@ impl BufferStateProvider<'_> {
unsafe fn insert_or_merge<A: HalApi>(
start_states: Option<&mut [BufferUses]>,
current_states: &mut [BufferUses],
resource_metadata: &mut ResourceMetadata<A, Buffer<A>>,
resource_metadata: &mut ResourceMetadata<A, BufferId, Buffer<A>>,
index32: u32,
index: usize,
state_provider: BufferStateProvider<'_>,
metadata_provider: ResourceMetadataProvider<'_, A, Buffer<A>>,
metadata_provider: ResourceMetadataProvider<'_, A, BufferId, Buffer<A>>,
) -> Result<(), UsageConflict> {
let currently_owned = unsafe { resource_metadata.contains_unchecked(index) };
@@ -708,11 +709,11 @@ unsafe fn insert_or_merge<A: HalApi>(
unsafe fn insert_or_barrier_update<A: HalApi>(
start_states: Option<&mut [BufferUses]>,
current_states: &mut [BufferUses],
resource_metadata: &mut ResourceMetadata<A, Buffer<A>>,
resource_metadata: &mut ResourceMetadata<A, BufferId, Buffer<A>>,
index: usize,
start_state_provider: BufferStateProvider<'_>,
end_state_provider: Option<BufferStateProvider<'_>>,
metadata_provider: ResourceMetadataProvider<'_, A, Buffer<A>>,
metadata_provider: ResourceMetadataProvider<'_, A, BufferId, Buffer<A>>,
barriers: &mut Vec<PendingTransition<BufferUses>>,
) {
let currently_owned = unsafe { resource_metadata.contains_unchecked(index) };
@@ -742,11 +743,11 @@ unsafe fn insert_or_barrier_update<A: HalApi>(
unsafe fn insert<A: HalApi>(
start_states: Option<&mut [BufferUses]>,
current_states: &mut [BufferUses],
resource_metadata: &mut ResourceMetadata<A, Buffer<A>>,
resource_metadata: &mut ResourceMetadata<A, BufferId, Buffer<A>>,
index: usize,
start_state_provider: BufferStateProvider<'_>,
end_state_provider: Option<BufferStateProvider<'_>>,
metadata_provider: ResourceMetadataProvider<'_, A, Buffer<A>>,
metadata_provider: ResourceMetadataProvider<'_, A, BufferId, Buffer<A>>,
) {
let new_start_state = unsafe { start_state_provider.get_state(index) };
let new_end_state =
@@ -776,7 +777,7 @@ unsafe fn merge<A: HalApi>(
index32: u32,
index: usize,
state_provider: BufferStateProvider<'_>,
metadata_provider: ResourceMetadataProvider<'_, A, Buffer<A>>,
metadata_provider: ResourceMetadataProvider<'_, A, BufferId, Buffer<A>>,
) -> Result<(), UsageConflict> {
let current_state = unsafe { current_states.get_unchecked_mut(index) };
let new_state = unsafe { state_provider.get_state(index) };

View File

@@ -1,6 +1,6 @@
//! The `ResourceMetadata` type.
use crate::{hal_api::HalApi, resource::Resource, Epoch};
use crate::{hal_api::HalApi, id::TypedId, resource::Resource, Epoch};
use bit_vec::BitVec;
use std::{borrow::Cow, marker::PhantomData, mem, sync::Arc};
use wgt::strict_assert;
@@ -13,7 +13,7 @@ use wgt::strict_assert;
/// members, but a bit vector tracks occupancy, so iteration touches
/// only occupied elements.
#[derive(Debug)]
pub(super) struct ResourceMetadata<A: HalApi, T: Resource> {
pub(super) struct ResourceMetadata<A: HalApi, I: TypedId, T: Resource<I>> {
/// If the resource with index `i` is a member, `owned[i]` is `true`.
owned: BitVec<usize>,
@@ -21,10 +21,10 @@ pub(super) struct ResourceMetadata<A: HalApi, T: Resource> {
resources: Vec<Option<Arc<T>>>,
/// This tells Rust that this type should be covariant with `A`.
_phantom: PhantomData<A>,
_phantom: PhantomData<(A, I)>,
}
impl<A: HalApi, T: Resource> ResourceMetadata<A, T> {
impl<A: HalApi, I: TypedId, T: Resource<I>> ResourceMetadata<A, I, T> {
pub(super) fn new() -> Self {
Self {
owned: BitVec::default(),
@@ -172,15 +172,15 @@ impl<A: HalApi, T: Resource> ResourceMetadata<A, T> {
///
/// This is used to abstract over the various places
/// trackers can get new resource metadata from.
pub(super) enum ResourceMetadataProvider<'a, A: HalApi, T: Resource> {
pub(super) enum ResourceMetadataProvider<'a, A: HalApi, I: TypedId, T: Resource<I>> {
/// Comes directly from explicit values.
Direct { resource: Cow<'a, Arc<T>> },
/// Comes from another metadata tracker.
Indirect {
metadata: &'a ResourceMetadata<A, T>,
metadata: &'a ResourceMetadata<A, I, T>,
},
}
impl<A: HalApi, T: Resource> ResourceMetadataProvider<'_, A, T> {
impl<A: HalApi, I: TypedId, T: Resource<I>> ResourceMetadataProvider<'_, A, I, T> {
/// Get the epoch and an owned refcount from this.
///
/// # Safety

View File

@@ -104,7 +104,7 @@ mod texture;
use crate::{
binding_model, command, conv,
hal_api::HalApi,
id::{self, Id},
id::{self, TypedId},
pipeline, resource,
snatch::SnatchGuard,
storage::Storage,
@@ -182,6 +182,8 @@ pub(crate) trait ResourceUses:
/// All flags that are exclusive.
const EXCLUSIVE: Self;
/// The relevant resource ID type.
type Id: Copy + fmt::Debug + TypedId;
/// The selector used by this resource.
type Selector: fmt::Debug;
@@ -318,8 +320,8 @@ impl<T: ResourceUses> fmt::Display for InvalidUse<T> {
pub(crate) struct BindGroupStates<A: HalApi> {
pub buffers: BufferBindGroupState<A>,
pub textures: TextureBindGroupState<A>,
pub views: StatelessBindGroupSate<resource::TextureView<A>>,
pub samplers: StatelessBindGroupSate<resource::Sampler<A>>,
pub views: StatelessBindGroupSate<id::TextureViewId, resource::TextureView<A>>,
pub samplers: StatelessBindGroupSate<id::SamplerId, resource::Sampler<A>>,
}
impl<A: HalApi> BindGroupStates<A> {
@@ -352,19 +354,20 @@ pub(crate) struct RenderBundleScope<A: HalApi> {
pub buffers: RwLock<BufferUsageScope<A>>,
pub textures: RwLock<TextureUsageScope<A>>,
// Don't need to track views and samplers, they are never used directly, only by bind groups.
pub bind_groups: RwLock<StatelessTracker<A, binding_model::BindGroup<A>>>,
pub render_pipelines: RwLock<StatelessTracker<A, pipeline::RenderPipeline<A>>>,
pub query_sets: RwLock<StatelessTracker<A, resource::QuerySet<A>>>,
pub bind_groups: RwLock<StatelessTracker<A, id::BindGroupId, binding_model::BindGroup<A>>>,
pub render_pipelines:
RwLock<StatelessTracker<A, id::RenderPipelineId, pipeline::RenderPipeline<A>>>,
pub query_sets: RwLock<StatelessTracker<A, id::QuerySetId, resource::QuerySet<A>>>,
}
impl<A: HalApi> RenderBundleScope<A> {
/// Create the render bundle scope and pull the maximum IDs from the hubs.
pub fn new(
buffers: &Storage<resource::Buffer<A>>,
textures: &Storage<resource::Texture<A>>,
bind_groups: &Storage<binding_model::BindGroup<A>>,
render_pipelines: &Storage<pipeline::RenderPipeline<A>>,
query_sets: &Storage<resource::QuerySet<A>>,
buffers: &Storage<resource::Buffer<A>, id::BufferId>,
textures: &Storage<resource::Texture<A>, id::TextureId>,
bind_groups: &Storage<binding_model::BindGroup<A>, id::BindGroupId>,
render_pipelines: &Storage<pipeline::RenderPipeline<A>, id::RenderPipelineId>,
query_sets: &Storage<resource::QuerySet<A>, id::QuerySetId>,
) -> Self {
let value = Self {
buffers: RwLock::new(BufferUsageScope::new()),
@@ -421,8 +424,8 @@ pub(crate) struct UsageScope<A: HalApi> {
impl<A: HalApi> UsageScope<A> {
/// Create the render bundle scope and pull the maximum IDs from the hubs.
pub fn new(
buffers: &Storage<resource::Buffer<A>>,
textures: &Storage<resource::Texture<A>>,
buffers: &Storage<resource::Buffer<A>, id::BufferId>,
textures: &Storage<resource::Texture<A>, id::TextureId>,
) -> Self {
let mut value = Self {
buffers: BufferUsageScope::new(),
@@ -478,24 +481,25 @@ impl<A: HalApi> UsageScope<A> {
}
}
pub(crate) trait ResourceTracker<R>
pub(crate) trait ResourceTracker<Id, R>
where
R: resource::Resource,
Id: TypedId,
R: resource::Resource<Id>,
{
fn remove_abandoned(&mut self, id: Id<R::Marker>) -> bool;
fn remove_abandoned(&mut self, id: Id) -> bool;
}
/// A full double sided tracker used by CommandBuffers and the Device.
pub(crate) struct Tracker<A: HalApi> {
pub buffers: BufferTracker<A>,
pub textures: TextureTracker<A>,
pub views: StatelessTracker<A, resource::TextureView<A>>,
pub samplers: StatelessTracker<A, resource::Sampler<A>>,
pub bind_groups: StatelessTracker<A, binding_model::BindGroup<A>>,
pub compute_pipelines: StatelessTracker<A, pipeline::ComputePipeline<A>>,
pub render_pipelines: StatelessTracker<A, pipeline::RenderPipeline<A>>,
pub bundles: StatelessTracker<A, command::RenderBundle<A>>,
pub query_sets: StatelessTracker<A, resource::QuerySet<A>>,
pub views: StatelessTracker<A, id::TextureViewId, resource::TextureView<A>>,
pub samplers: StatelessTracker<A, id::SamplerId, resource::Sampler<A>>,
pub bind_groups: StatelessTracker<A, id::BindGroupId, binding_model::BindGroup<A>>,
pub compute_pipelines: StatelessTracker<A, id::ComputePipelineId, pipeline::ComputePipeline<A>>,
pub render_pipelines: StatelessTracker<A, id::RenderPipelineId, pipeline::RenderPipeline<A>>,
pub bundles: StatelessTracker<A, id::RenderBundleId, command::RenderBundle<A>>,
pub query_sets: StatelessTracker<A, id::QuerySetId, resource::QuerySet<A>>,
}
impl<A: HalApi> Tracker<A> {
@@ -516,15 +520,15 @@ impl<A: HalApi> Tracker<A> {
/// Pull the maximum IDs from the hubs.
pub fn set_size(
&mut self,
buffers: Option<&Storage<resource::Buffer<A>>>,
textures: Option<&Storage<resource::Texture<A>>>,
views: Option<&Storage<resource::TextureView<A>>>,
samplers: Option<&Storage<resource::Sampler<A>>>,
bind_groups: Option<&Storage<binding_model::BindGroup<A>>>,
compute_pipelines: Option<&Storage<pipeline::ComputePipeline<A>>>,
render_pipelines: Option<&Storage<pipeline::RenderPipeline<A>>>,
bundles: Option<&Storage<command::RenderBundle<A>>>,
query_sets: Option<&Storage<resource::QuerySet<A>>>,
buffers: Option<&Storage<resource::Buffer<A>, id::BufferId>>,
textures: Option<&Storage<resource::Texture<A>, id::TextureId>>,
views: Option<&Storage<resource::TextureView<A>, id::TextureViewId>>,
samplers: Option<&Storage<resource::Sampler<A>, id::SamplerId>>,
bind_groups: Option<&Storage<binding_model::BindGroup<A>, id::BindGroupId>>,
compute_pipelines: Option<&Storage<pipeline::ComputePipeline<A>, id::ComputePipelineId>>,
render_pipelines: Option<&Storage<pipeline::RenderPipeline<A>, id::RenderPipelineId>>,
bundles: Option<&Storage<command::RenderBundle<A>, id::RenderBundleId>>,
query_sets: Option<&Storage<resource::QuerySet<A>, id::QuerySetId>>,
) {
if let Some(buffers) = buffers {
self.buffers.set_size(buffers.len());

View File

@@ -4,27 +4,24 @@
* distinction between a usage scope and a full tracker.
!*/
use std::sync::Arc;
use std::{marker::PhantomData, sync::Arc};
use parking_lot::Mutex;
use crate::{
hal_api::HalApi, id::Id, resource::Resource, resource_log, storage::Storage,
hal_api::HalApi, id::TypedId, resource::Resource, resource_log, storage::Storage,
track::ResourceMetadata,
};
use super::ResourceTracker;
/// Satisfy clippy.
type Pair<T> = (Id<<T as Resource>::Marker>, Arc<T>);
/// Stores all the resources that a bind group stores.
#[derive(Debug)]
pub(crate) struct StatelessBindGroupSate<T: Resource> {
resources: Mutex<Vec<Pair<T>>>,
pub(crate) struct StatelessBindGroupSate<Id: TypedId, T: Resource<Id>> {
resources: Mutex<Vec<(Id, Arc<T>)>>,
}
impl<T: Resource> StatelessBindGroupSate<T> {
impl<Id: TypedId, T: Resource<Id>> StatelessBindGroupSate<Id, T> {
pub fn new() -> Self {
Self {
resources: Mutex::new(Vec::new()),
@@ -61,7 +58,7 @@ impl<T: Resource> StatelessBindGroupSate<T> {
}
/// Adds the given resource.
pub fn add_single<'a>(&self, storage: &'a Storage<T>, id: Id<T::Marker>) -> Option<&'a T> {
pub fn add_single<'a>(&self, storage: &'a Storage<T, Id>, id: Id) -> Option<&'a T> {
let resource = storage.get(id).ok()?;
let mut resources = self.resources.lock();
@@ -73,11 +70,14 @@ impl<T: Resource> StatelessBindGroupSate<T> {
/// Stores all resource state within a command buffer or device.
#[derive(Debug)]
pub(crate) struct StatelessTracker<A: HalApi, T: Resource> {
metadata: ResourceMetadata<A, T>,
pub(crate) struct StatelessTracker<A: HalApi, Id: TypedId, T: Resource<Id>> {
metadata: ResourceMetadata<A, Id, T>,
_phantom: PhantomData<Id>,
}
impl<A: HalApi, T: Resource> ResourceTracker<T> for StatelessTracker<A, T> {
impl<A: HalApi, Id: TypedId, T: Resource<Id>> ResourceTracker<Id, T>
for StatelessTracker<A, Id, T>
{
/// Try to remove the given resource from the tracker iff we have the last reference to the
/// resource and the epoch matches.
///
@@ -85,7 +85,7 @@ impl<A: HalApi, T: Resource> ResourceTracker<T> for StatelessTracker<A, T> {
///
/// If the ID is higher than the length of internal vectors,
/// false will be returned.
fn remove_abandoned(&mut self, id: Id<T::Marker>) -> bool {
fn remove_abandoned(&mut self, id: Id) -> bool {
let index = id.unzip().0 as usize;
if index >= self.metadata.size() {
@@ -120,10 +120,11 @@ impl<A: HalApi, T: Resource> ResourceTracker<T> for StatelessTracker<A, T> {
}
}
impl<A: HalApi, T: Resource> StatelessTracker<A, T> {
impl<A: HalApi, Id: TypedId, T: Resource<Id>> StatelessTracker<A, Id, T> {
pub fn new() -> Self {
Self {
metadata: ResourceMetadata::new(),
_phantom: PhantomData,
}
}
@@ -163,7 +164,7 @@ impl<A: HalApi, T: Resource> StatelessTracker<A, T> {
///
/// If the ID is higher than the length of internal vectors,
/// the vectors will be extended. A call to set_size is not needed.
pub fn insert_single(&mut self, id: Id<T::Marker>, resource: Arc<T>) {
pub fn insert_single(&mut self, id: Id, resource: Arc<T>) {
let (index32, _epoch, _) = id.unzip();
let index = index32 as usize;
@@ -180,11 +181,7 @@ impl<A: HalApi, T: Resource> StatelessTracker<A, T> {
///
/// If the ID is higher than the length of internal vectors,
/// the vectors will be extended. A call to set_size is not needed.
pub fn add_single<'a>(
&mut self,
storage: &'a Storage<T>,
id: Id<T::Marker>,
) -> Option<&'a Arc<T>> {
pub fn add_single<'a>(&mut self, storage: &'a Storage<T, Id>, id: Id) -> Option<&'a Arc<T>> {
let resource = storage.get(id).ok()?;
let (index32, _epoch, _) = id.unzip();
@@ -225,7 +222,7 @@ impl<A: HalApi, T: Resource> StatelessTracker<A, T> {
}
}
pub fn get(&self, id: Id<T::Marker>) -> Option<&Arc<T>> {
pub fn get(&self, id: Id) -> Option<&Arc<T>> {
let index = id.unzip().0 as usize;
if index > self.metadata.size() {
return None;

View File

@@ -22,7 +22,7 @@
use super::{range::RangedStates, PendingTransition, PendingTransitionList, ResourceTracker};
use crate::{
hal_api::HalApi,
id::TextureId,
id::{TextureId, TypedId},
resource::{Resource, Texture, TextureInner},
snatch::SnatchGuard,
track::{
@@ -50,6 +50,7 @@ pub struct TextureSelector {
impl ResourceUses for TextureUses {
const EXCLUSIVE: Self = Self::EXCLUSIVE;
type Id = TextureId;
type Selector = TextureSelector;
fn bits(self) -> u16 {
@@ -231,7 +232,7 @@ impl TextureStateSet {
#[derive(Debug)]
pub(crate) struct TextureUsageScope<A: HalApi> {
set: TextureStateSet,
metadata: ResourceMetadata<A, Texture<A>>,
metadata: ResourceMetadata<A, TextureId, Texture<A>>,
}
impl<A: HalApi> TextureUsageScope<A> {
@@ -386,14 +387,14 @@ pub(crate) struct TextureTracker<A: HalApi> {
start_set: TextureStateSet,
end_set: TextureStateSet,
metadata: ResourceMetadata<A, Texture<A>>,
metadata: ResourceMetadata<A, TextureId, Texture<A>>,
temp: Vec<PendingTransition<TextureUses>>,
_phantom: PhantomData<A>,
}
impl<A: HalApi> ResourceTracker<Texture<A>> for TextureTracker<A> {
impl<A: HalApi> ResourceTracker<TextureId, Texture<A>> for TextureTracker<A> {
/// Try to remove the given resource from the tracker iff we have the last reference to the
/// resource and the epoch matches.
///
@@ -863,10 +864,10 @@ impl<'a> TextureStateProvider<'a> {
unsafe fn insert_or_merge<A: HalApi>(
texture_selector: &TextureSelector,
current_state_set: &mut TextureStateSet,
resource_metadata: &mut ResourceMetadata<A, Texture<A>>,
resource_metadata: &mut ResourceMetadata<A, TextureId, Texture<A>>,
index: usize,
state_provider: TextureStateProvider<'_>,
metadata_provider: ResourceMetadataProvider<'_, A, Texture<A>>,
metadata_provider: ResourceMetadataProvider<'_, A, TextureId, Texture<A>>,
) -> Result<(), UsageConflict> {
let currently_owned = unsafe { resource_metadata.contains_unchecked(index) };
@@ -919,11 +920,11 @@ unsafe fn insert_or_barrier_update<A: HalApi>(
texture_selector: &TextureSelector,
start_state: Option<&mut TextureStateSet>,
current_state_set: &mut TextureStateSet,
resource_metadata: &mut ResourceMetadata<A, Texture<A>>,
resource_metadata: &mut ResourceMetadata<A, TextureId, Texture<A>>,
index: usize,
start_state_provider: TextureStateProvider<'_>,
end_state_provider: Option<TextureStateProvider<'_>>,
metadata_provider: ResourceMetadataProvider<'_, A, Texture<A>>,
metadata_provider: ResourceMetadataProvider<'_, A, TextureId, Texture<A>>,
barriers: &mut Vec<PendingTransition<TextureUses>>,
) {
let currently_owned = unsafe { resource_metadata.contains_unchecked(index) };
@@ -972,11 +973,11 @@ unsafe fn insert<A: HalApi>(
texture_selector: Option<&TextureSelector>,
start_state: Option<&mut TextureStateSet>,
end_state: &mut TextureStateSet,
resource_metadata: &mut ResourceMetadata<A, Texture<A>>,
resource_metadata: &mut ResourceMetadata<A, TextureId, Texture<A>>,
index: usize,
start_state_provider: TextureStateProvider<'_>,
end_state_provider: Option<TextureStateProvider<'_>>,
metadata_provider: ResourceMetadataProvider<'_, A, Texture<A>>,
metadata_provider: ResourceMetadataProvider<'_, A, TextureId, Texture<A>>,
) {
let start_layers = unsafe { start_state_provider.get_state(texture_selector, index) };
match start_layers {
@@ -1059,7 +1060,7 @@ unsafe fn merge<A: HalApi>(
current_state_set: &mut TextureStateSet,
index: usize,
state_provider: TextureStateProvider<'_>,
metadata_provider: ResourceMetadataProvider<'_, A, Texture<A>>,
metadata_provider: ResourceMetadataProvider<'_, A, TextureId, Texture<A>>,
) -> Result<(), UsageConflict> {
let current_simple = unsafe { current_state_set.simple.get_unchecked_mut(index) };
let current_state = if *current_simple == TextureUses::COMPLEX {

File diff suppressed because one or more lines are too long

View File

@@ -87,7 +87,7 @@ path = "../naga"
features = ["wgsl-in"]
[dev-dependencies.winit]
version = "0.29.10"
version = "0.29.9"
features = ["android-native-activity"]
[build-dependencies]

View File

@@ -490,7 +490,7 @@ impl<A: hal::Api> Example<A> {
let mut fence = device.create_fence().unwrap();
let init_cmd = cmd_encoder.end_encoding().unwrap();
queue
.submit(&[&init_cmd], &[], Some((&mut fence, init_fence_value)))
.submit(&[&init_cmd], Some((&mut fence, init_fence_value)))
.unwrap();
device.wait(&fence, init_fence_value, !0).unwrap();
device.destroy_buffer(staging_buffer);
@@ -542,7 +542,7 @@ impl<A: hal::Api> Example<A> {
{
let ctx = &mut self.contexts[self.context_index];
self.queue
.submit(&[], &[], Some((&mut ctx.fence, ctx.fence_value)))
.submit(&[], Some((&mut ctx.fence, ctx.fence_value)))
.unwrap();
}
@@ -729,9 +729,7 @@ impl<A: hal::Api> Example<A> {
} else {
None
};
self.queue
.submit(&[&cmd_buf], &[&surface_tex], fence_param)
.unwrap();
self.queue.submit(&[&cmd_buf], fence_param).unwrap();
self.queue.present(&self.surface, surface_tex).unwrap();
ctx.used_cmd_bufs.push(cmd_buf);
ctx.used_views.push(surface_tex_view);

View File

@@ -183,6 +183,6 @@ fn fill_screen(exposed: &hal::ExposedAdapter<hal::api::Gles>, width: u32, height
encoder.begin_render_pass(&rp_desc);
encoder.end_render_pass();
let cmd_buf = encoder.end_encoding().unwrap();
od.queue.submit(&[&cmd_buf], &[], None).unwrap();
od.queue.submit(&[&cmd_buf], None).unwrap();
}
}

View File

@@ -755,7 +755,7 @@ impl<A: hal::Api> Example<A> {
let mut fence = device.create_fence().unwrap();
let init_cmd = cmd_encoder.end_encoding().unwrap();
queue
.submit(&[&init_cmd], &[], Some((&mut fence, init_fence_value)))
.submit(&[&init_cmd], Some((&mut fence, init_fence_value)))
.unwrap();
device.wait(&fence, init_fence_value, !0).unwrap();
cmd_encoder.reset_all(iter::once(init_cmd));
@@ -960,9 +960,7 @@ impl<A: hal::Api> Example<A> {
} else {
None
};
self.queue
.submit(&[&cmd_buf], &[&surface_tex], fence_param)
.unwrap();
self.queue.submit(&[&cmd_buf], fence_param).unwrap();
self.queue.present(&self.surface, surface_tex).unwrap();
ctx.used_cmd_bufs.push(cmd_buf);
ctx.used_views.push(surface_tex_view);
@@ -1001,7 +999,7 @@ impl<A: hal::Api> Example<A> {
{
let ctx = &mut self.contexts[self.context_index];
self.queue
.submit(&[], &[], Some((&mut ctx.fence, ctx.fence_value)))
.submit(&[], Some((&mut ctx.fence, ctx.fence_value)))
.unwrap();
}

View File

@@ -289,13 +289,14 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
}
unsafe fn end_encoding(&mut self) -> Result<super::CommandBuffer, crate::DeviceError> {
let raw = self.list.take().unwrap();
raw.close()
.into_device_result("GraphicsCommandList::close")?;
Ok(super::CommandBuffer { raw })
let closed = raw.close().into_result().is_ok();
Ok(super::CommandBuffer { raw, closed })
}
unsafe fn reset_all<I: Iterator<Item = super::CommandBuffer>>(&mut self, command_buffers: I) {
for cmd_buf in command_buffers {
self.free_lists.push(cmd_buf.raw);
if cmd_buf.closed {
self.free_lists.push(cmd_buf.raw);
}
}
self.allocator.reset();
}

View File

@@ -7,9 +7,7 @@ use std::{mem, sync::Arc};
impl Drop for super::Instance {
fn drop(&mut self) {
if self.flags.contains(wgt::InstanceFlags::VALIDATION) {
crate::auxil::dxgi::exception::unregister_exception_handler();
}
crate::auxil::dxgi::exception::unregister_exception_handler();
}
}
@@ -20,26 +18,12 @@ impl crate::Instance<super::Api> for super::Instance {
crate::InstanceError::with_source(String::from("failed to load d3d12.dll"), e)
})?;
if desc
.flags
.intersects(wgt::InstanceFlags::VALIDATION | wgt::InstanceFlags::GPU_BASED_VALIDATION)
{
if desc.flags.contains(wgt::InstanceFlags::VALIDATION) {
// Enable debug layer
match lib_main.get_debug_interface() {
Ok(pair) => match pair.into_result() {
Ok(debug_controller) => {
if desc.flags.intersects(wgt::InstanceFlags::VALIDATION) {
debug_controller.enable_layer();
}
if desc
.flags
.intersects(wgt::InstanceFlags::GPU_BASED_VALIDATION)
{
#[allow(clippy::collapsible_if)]
if !debug_controller.enable_gpu_based_validation() {
log::warn!("Failed to enable GPU-based validation");
}
}
debug_controller.enable_layer();
}
Err(err) => {
log::warn!("Unable to enable D3D12 debug interface: {}", err);

View File

@@ -386,6 +386,7 @@ impl fmt::Debug for CommandEncoder {
#[derive(Debug)]
pub struct CommandBuffer {
raw: d3d12::GraphicsCommandList,
closed: bool,
}
unsafe impl Send for CommandBuffer {}
@@ -885,7 +886,6 @@ impl crate::Queue<Api> for Queue {
unsafe fn submit(
&self,
command_buffers: &[&CommandBuffer],
_surface_textures: &[&Texture],
signal_fence: Option<(&mut Fence, crate::FenceValue)>,
) -> Result<(), crate::DeviceError> {
let mut temp_lists = self.temp_lists.lock();

View File

@@ -104,7 +104,6 @@ impl crate::Queue<Api> for Context {
unsafe fn submit(
&self,
command_buffers: &[&Resource],
surface_textures: &[&Resource],
signal_fence: Option<(&mut Resource, crate::FenceValue)>,
) -> DeviceResult<()> {
Ok(())

View File

@@ -1092,7 +1092,6 @@ impl Surface {
.map_err(|e| {
log::error!("swap_buffers failed: {}", e);
crate::SurfaceError::Lost
// TODO: should we unset the current context here?
})?;
self.egl
.instance

View File

@@ -1748,7 +1748,6 @@ impl crate::Queue<super::Api> for super::Queue {
unsafe fn submit(
&self,
command_buffers: &[&super::CommandBuffer],
_surface_textures: &[&super::Texture],
signal_fence: Option<(&mut super::Fence, crate::FenceValue)>,
) -> Result<(), crate::DeviceError> {
let shared = Arc::clone(&self.shared);

View File

@@ -77,24 +77,6 @@ impl AdapterContext {
AdapterContextLock { inner }
}
/// Obtain a lock to the WGL context and get handle to the [`glow::Context`] that can be used to
/// do rendering.
///
/// Unlike [`lock`](Self::lock), this accepts a device to pass to `make_current` and exposes the error
/// when `make_current` fails.
#[track_caller]
fn lock_with_dc(&self, device: HDC) -> Result<AdapterContextLock<'_>, Error> {
let inner = self
.inner
.try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))
.expect("Could not lock adapter context. This is most-likely a deadlock.");
inner
.context
.make_current(device)
.map(|()| AdapterContextLock { inner })
}
}
/// A guard containing a lock to an [`AdapterContext`]
@@ -621,10 +603,16 @@ impl Surface {
window: self.window,
};
let gl = context.lock_with_dc(dc.device).map_err(|e| {
let inner = context.inner.lock();
if let Err(e) = inner.context.make_current(dc.device) {
log::error!("unable to make the OpenGL context current for surface: {e}",);
crate::SurfaceError::Other("unable to make the OpenGL context current for surface")
})?;
return Err(crate::SurfaceError::Other(
"unable to make the OpenGL context current for surface",
));
}
let gl = &inner.gl;
unsafe { gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None) };
unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(sc.framebuffer)) };
@@ -705,11 +693,16 @@ impl crate::Surface<super::Api> for Surface {
}
let format_desc = device.shared.describe_texture_format(config.format);
let gl = &device.shared.context.lock_with_dc(dc.device).map_err(|e| {
log::error!("unable to make the OpenGL context current for surface: {e}",);
crate::SurfaceError::Other("unable to make the OpenGL context current for surface")
})?;
let inner = &device.shared.context.inner.lock();
if let Err(e) = inner.context.make_current(dc.device) {
log::error!("unable to make the OpenGL context current for surface: {e}",);
return Err(crate::SurfaceError::Other(
"unable to make the OpenGL context current for surface",
));
}
let gl = &inner.gl;
let renderbuffer = unsafe { gl.create_renderbuffer() }.map_err(|error| {
log::error!("Internal swapchain renderbuffer creation failed: {error}");
crate::DeviceError::OutOfMemory

View File

@@ -413,12 +413,9 @@ pub trait Queue<A: Api>: WasmNotSendSync {
/// - all of the command buffers were created from command pools
/// that are associated with this queue.
/// - all of the command buffers had `CommadBuffer::finish()` called.
/// - all surface textures that the command buffers write to must be
/// passed to the surface_textures argument.
unsafe fn submit(
&self,
command_buffers: &[&A::CommandBuffer],
surface_textures: &[&A::SurfaceTexture],
signal_fence: Option<(&mut A::Fence, FenceValue)>,
) -> Result<(), DeviceError>;
unsafe fn present(

View File

@@ -368,7 +368,6 @@ impl crate::Queue<Api> for Queue {
unsafe fn submit(
&self,
command_buffers: &[&CommandBuffer],
_surface_textures: &[&SurfaceTexture],
signal_fence: Option<(&mut Fence, crate::FenceValue)>,
) -> Result<(), crate::DeviceError> {
objc::rc::autoreleasepool(|| {

View File

@@ -627,16 +627,8 @@ impl super::Device {
let images =
unsafe { functor.get_swapchain_images(raw) }.map_err(crate::DeviceError::from)?;
// NOTE: It's important that we define at least images.len() + 1 wait
// semaphores, since we prospectively need to provide the call to
// acquire the next image with an unsignaled semaphore.
let surface_semaphores = (0..images.len() + 1)
.map(|_| unsafe {
self.shared
.raw
.create_semaphore(&vk::SemaphoreCreateInfo::builder(), None)
})
.collect::<Result<Vec<_>, _>>()
let vk_info = vk::FenceCreateInfo::builder().build();
let fence = unsafe { self.shared.raw.create_fence(&vk_info, None) }
.map_err(crate::DeviceError::from)?;
Ok(super::Swapchain {
@@ -644,11 +636,10 @@ impl super::Device {
raw_flags,
functor,
device: Arc::clone(&self.shared),
fence,
images,
config: config.clone(),
view_formats: wgt_view_formats,
surface_semaphores,
next_surface_index: 0,
})
}

View File

@@ -169,7 +169,7 @@ impl super::Swapchain {
/// # Safety
///
/// - The device must have been made idle before calling this function.
unsafe fn release_resources(mut self, device: &ash::Device) -> Self {
unsafe fn release_resources(self, device: &ash::Device) -> Self {
profiling::scope!("Swapchain::release_resources");
{
profiling::scope!("vkDeviceWaitIdle");
@@ -177,13 +177,7 @@ impl super::Swapchain {
// the presentation work is done, we are forced to wait until the device is idle.
let _ = unsafe { device.device_wait_idle() };
};
for semaphore in self.surface_semaphores.drain(..) {
unsafe {
device.destroy_semaphore(semaphore, None);
}
}
unsafe { device.destroy_fence(self.fence, None) };
self
}
}
@@ -940,12 +934,10 @@ impl crate::Surface<super::Api> for super::Surface {
timeout_ns = u64::MAX;
}
let wait_semaphore = sc.surface_semaphores[sc.next_surface_index];
// will block if no image is available
let (index, suboptimal) = match unsafe {
sc.functor
.acquire_next_image(sc.raw, timeout_ns, wait_semaphore, vk::Fence::null())
.acquire_next_image(sc.raw, timeout_ns, vk::Semaphore::null(), sc.fence)
} {
// We treat `VK_SUBOPTIMAL_KHR` as `VK_SUCCESS` on Android.
// See the comment in `Queue::present`.
@@ -965,14 +957,17 @@ impl crate::Surface<super::Api> for super::Surface {
}
};
sc.next_surface_index += 1;
sc.next_surface_index %= sc.surface_semaphores.len();
// special case for Intel Vulkan returning bizzare values (ugh)
if sc.device.vendor_id == crate::auxil::db::intel::VENDOR && index > 0x100 {
return Err(crate::SurfaceError::Outdated);
}
let fences = &[sc.fence];
unsafe { sc.device.raw.wait_for_fences(fences, true, !0) }
.map_err(crate::DeviceError::from)?;
unsafe { sc.device.raw.reset_fences(fences) }.map_err(crate::DeviceError::from)?;
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkRenderPassBeginInfo.html#VUID-VkRenderPassBeginInfo-framebuffer-03209
let raw_flags = if sc
.raw_flags
@@ -999,7 +994,6 @@ impl crate::Surface<super::Api> for super::Surface {
},
view_formats: sc.view_formats.clone(),
},
wait_semaphore,
};
Ok(Some(crate::AcquiredSurfaceTexture {
texture,

View File

@@ -146,14 +146,10 @@ struct Swapchain {
raw_flags: vk::SwapchainCreateFlagsKHR,
functor: khr::Swapchain,
device: Arc<DeviceShared>,
fence: vk::Fence,
images: Vec<vk::Image>,
config: crate::SurfaceConfiguration,
view_formats: Vec<wgt::TextureFormat>,
/// One wait semaphore per swapchain image. This will be associated with the
/// surface texture, and later collected during submission.
surface_semaphores: Vec<vk::Semaphore>,
/// Current semaphore index to use when acquiring a surface.
next_surface_index: usize,
}
pub struct Surface {
@@ -167,7 +163,6 @@ pub struct Surface {
pub struct SurfaceTexture {
index: u32,
texture: Texture,
wait_semaphore: vk::Semaphore,
}
impl Borrow<Texture> for SurfaceTexture {
@@ -590,43 +585,29 @@ impl crate::Queue<Api> for Queue {
unsafe fn submit(
&self,
command_buffers: &[&CommandBuffer],
surface_textures: &[&SurfaceTexture],
signal_fence: Option<(&mut Fence, crate::FenceValue)>,
) -> Result<(), crate::DeviceError> {
let vk_cmd_buffers = command_buffers
.iter()
.map(|cmd| cmd.raw)
.collect::<Vec<_>>();
let mut vk_info = vk::SubmitInfo::builder().command_buffers(&vk_cmd_buffers);
let mut fence_raw = vk::Fence::null();
let mut wait_stage_masks = Vec::new();
let mut wait_semaphores = Vec::new();
let mut signal_semaphores = ArrayVec::<_, 2>::new();
let mut signal_values = ArrayVec::<_, 2>::new();
for &surface_texture in surface_textures {
wait_stage_masks.push(vk::PipelineStageFlags::TOP_OF_PIPE);
wait_semaphores.push(surface_texture.wait_semaphore);
}
let old_index = self.relay_index.load(Ordering::Relaxed);
let sem_index = if old_index >= 0 {
wait_stage_masks.push(vk::PipelineStageFlags::TOP_OF_PIPE);
wait_semaphores.push(self.relay_semaphores[old_index as usize]);
(old_index as usize + 1) % self.relay_semaphores.len()
} else {
0
};
signal_semaphores.push(self.relay_semaphores[sem_index]);
self.relay_index
.store(sem_index as isize, Ordering::Relaxed);
let mut vk_timeline_info;
let mut signal_semaphores = [vk::Semaphore::null(), vk::Semaphore::null()];
let signal_values;
if let Some((fence, value)) = signal_fence {
fence.maintain(&self.device.raw)?;
match *fence {
Fence::TimelineSemaphore(raw) => {
signal_semaphores.push(raw);
signal_values.push(!0);
signal_values.push(value);
signal_values = [!0, value];
signal_semaphores[1] = raw;
vk_timeline_info = vk::TimelineSemaphoreSubmitInfo::builder()
.signal_semaphore_values(&signal_values);
vk_info = vk_info.push_next(&mut vk_timeline_info);
}
Fence::FencePool {
ref mut active,
@@ -646,25 +627,26 @@ impl crate::Queue<Api> for Queue {
}
}
let vk_cmd_buffers = command_buffers
.iter()
.map(|cmd| cmd.raw)
.collect::<Vec<_>>();
let wait_stage_mask = [vk::PipelineStageFlags::TOP_OF_PIPE];
let old_index = self.relay_index.load(Ordering::Relaxed);
let sem_index = if old_index >= 0 {
vk_info = vk_info
.wait_semaphores(&self.relay_semaphores[old_index as usize..old_index as usize + 1])
.wait_dst_stage_mask(&wait_stage_mask);
(old_index as usize + 1) % self.relay_semaphores.len()
} else {
0
};
self.relay_index
.store(sem_index as isize, Ordering::Relaxed);
signal_semaphores[0] = self.relay_semaphores[sem_index];
let mut vk_info = vk::SubmitInfo::builder().command_buffers(&vk_cmd_buffers);
vk_info = vk_info
.wait_semaphores(&wait_semaphores)
.wait_dst_stage_mask(&wait_stage_masks)
.signal_semaphores(&signal_semaphores);
let mut vk_timeline_info;
if !signal_values.is_empty() {
vk_timeline_info =
vk::TimelineSemaphoreSubmitInfo::builder().signal_semaphore_values(&signal_values);
vk_info = vk_info.push_next(&mut vk_timeline_info);
}
let signal_count = if signal_semaphores[1] == vk::Semaphore::null() {
1
} else {
2
};
vk_info = vk_info.signal_semaphores(&signal_semaphores[..signal_count]);
profiling::scope!("vkQueueSubmit");
unsafe {

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"6b0d7ddecc26e3b72cb6d47793770203147f851f048da8d1f5d8f508e40d4f82","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"d24ea48c4ddcce18997fbc101f798f647334b370746643df6fb5ad161373323e","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}
{"files":{"Cargo.toml":"577d13b5d0a571c9610e782f9aba2655e896f5959009b32d023d186a0268aca1","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"3fe98027aa73970c8ab7874a3e13dbfd6faa87df2081beb5c83aeec4c60f372f","src/lib.rs":"013810123a44be78ed2f35902c52c4fa90c84a3d8a2f15f25541e7761cc726d8","src/math.rs":"4d03039736dd6926feb139bc68734cb59df34ede310427bbf059e5c925e0af3b"},"package":null}

View File

@@ -53,7 +53,9 @@ features = ["serde_derive"]
[features]
fragile-send-sync-non-atomic-wasm = []
replay = ["serde"]
strict_asserts = []
trace = ["serde"]
[target."cfg(target_arch = \"wasm32\")".dependencies]
js-sys = "0.3.67"

View File

@@ -10,9 +10,7 @@
#![warn(missing_docs, unsafe_op_in_unsafe_fn)]
#[cfg(any(feature = "serde", test))]
use serde::Deserialize;
#[cfg(any(feature = "serde", test))]
use serde::Serialize;
use serde::{Deserialize, Serialize};
use std::hash::{Hash, Hasher};
use std::path::PathBuf;
use std::{num::NonZeroU32, ops::Range};
@@ -98,13 +96,13 @@ pub const QUERY_SIZE: u32 = 8;
pub enum Backend {
/// Dummy backend, used for testing.
Empty = 0,
/// Vulkan API (Windows, Linux, Android, MacOS via `vulkan-portability`/MoltenVK)
/// Vulkan API
Vulkan = 1,
/// Metal API (Apple platforms)
Metal = 2,
/// Direct3D-12 (Windows)
Dx12 = 3,
/// OpenGL 3.3+ (Windows), OpenGL ES 3.0+ (Linux, Android, MacOS via Angle), and WebGL2
/// OpenGL ES-3 (Linux, Android)
Gl = 4,
/// WebGPU in the browser
BrowserWebGpu = 5,
@@ -112,7 +110,7 @@ pub enum Backend {
impl Backend {
/// Returns the string name of the backend.
pub const fn to_str(self) -> &'static str {
pub fn to_str(self) -> &'static str {
match self {
Backend::Empty => "empty",
Backend::Vulkan => "vulkan",
@@ -124,19 +122,14 @@ impl Backend {
}
}
impl std::fmt::Display for Backend {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.to_str())
}
}
/// Power Preference when choosing a physical adapter.
///
/// Corresponds to [WebGPU `GPUPowerPreference`](
/// https://gpuweb.github.io/gpuweb/#enumdef-gpupowerpreference).
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum PowerPreference {
#[default]
@@ -204,7 +197,8 @@ impl From<Backend> for Backends {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpurequestadapteroptions).
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RequestAdapterOptions<S> {
/// Power preference for the adapter.
pub power_preference: PowerPreference,
@@ -901,14 +895,6 @@ bitflags::bitflags! {
/// This mainly applies to a Vulkan driver's compliance version. If the major compliance version
/// is `0`, then the driver is ignored. This flag allows that driver to be enabled for testing.
const ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER = 1 << 3;
/// Enable GPU-based validation. Currently, this only changes behavior on the DX12
/// backend.
///
/// Supported platforms:
///
/// - D3D12; called ["GPU-based validation", or
/// "GBV"](https://web.archive.org/web/20230206120404/https://learn.microsoft.com/en-us/windows/win32/direct3d12/using-d3d12-debug-layer-gpu-based-validation)
const GPU_BASED_VALIDATION = 1 << 4;
}
}
@@ -919,9 +905,9 @@ impl Default for InstanceFlags {
}
impl InstanceFlags {
/// Enable recommended debugging and validation flags.
/// Enable debugging and validation flags.
pub fn debugging() -> Self {
InstanceFlags::DEBUG | InstanceFlags::VALIDATION | InstanceFlags::GPU_BASED_VALIDATION
InstanceFlags::DEBUG | InstanceFlags::VALIDATION
}
/// Infer good defaults from the build type
@@ -964,9 +950,6 @@ impl InstanceFlags {
if let Some(bit) = env("WGPU_ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER") {
self.set(Self::ALLOW_UNDERLYING_NONCOMPLIANT_ADAPTER, bit);
}
if let Some(bit) = env("WGPU_GPU_BASED_VALIDATION") {
self.set(Self::GPU_BASED_VALIDATION, bit);
}
self
}
@@ -1006,7 +989,7 @@ impl InstanceFlags {
/// [`downlevel_defaults()`]: Limits::downlevel_defaults
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase", default))]
pub struct Limits {
/// Maximum allowed value for the `size.width` of a texture created with `TextureDimension::D1`.
@@ -1681,7 +1664,8 @@ pub struct AdapterInfo {
/// https://gpuweb.github.io/gpuweb/#gpudevicedescriptor).
#[repr(C)]
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct DeviceDescriptor<L> {
/// Debug label for the device.
pub label: L,
@@ -1743,7 +1727,8 @@ impl_bitflags!(ShaderStages);
/// https://gpuweb.github.io/gpuweb/#enumdef-gputextureviewdimension).
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum TextureViewDimension {
/// A one dimensional texture. `texture_1d` in WGSL and `texture1D` in GLSL.
#[cfg_attr(feature = "serde", serde(rename = "1d"))]
@@ -1787,7 +1772,8 @@ impl TextureViewDimension {
/// used with the first render target.
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum BlendFactor {
/// 0.0
@@ -1849,7 +1835,8 @@ impl BlendFactor {
/// https://gpuweb.github.io/gpuweb/#enumdef-gpublendoperation).
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum BlendOperation {
/// Src + Dst
@@ -1871,7 +1858,8 @@ pub enum BlendOperation {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpublendcomponent).
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct BlendComponent {
/// Multiplier for the source, which is produced by the fragment shader.
@@ -1926,7 +1914,8 @@ impl Default for BlendComponent {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpublendstate).
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct BlendState {
/// Color equation.
@@ -1965,7 +1954,8 @@ impl BlendState {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpucolortargetstate).
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct ColorTargetState {
/// The [`TextureFormat`] of the image that this pipeline will render to. Must match the format
@@ -1997,7 +1987,8 @@ impl From<TextureFormat> for ColorTargetState {
/// https://gpuweb.github.io/gpuweb/#enumdef-gpuprimitivetopology).
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum PrimitiveTopology {
/// Vertex data is a list of points. Each vertex is a new point.
@@ -2037,7 +2028,8 @@ impl PrimitiveTopology {
/// https://gpuweb.github.io/gpuweb/#enumdef-gpufrontface).
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum FrontFace {
/// Triangles with vertices in counter clockwise order are considered the front face.
@@ -2058,7 +2050,8 @@ pub enum FrontFace {
/// except that the `"none"` value is represented using `Option<Face>` instead.
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum Face {
/// Front face
@@ -2070,7 +2063,8 @@ pub enum Face {
/// Type of drawing mode for polygons
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum PolygonMode {
/// Polygons are filled
@@ -2088,7 +2082,8 @@ pub enum PolygonMode {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpuprimitivestate).
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct PrimitiveState {
/// The primitive topology used to interpret vertices.
@@ -2128,7 +2123,8 @@ pub struct PrimitiveState {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpumultisamplestate).
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct MultisampleState {
/// The number of samples calculated per pixel (for MSAA). For non-multisampled textures,
@@ -2227,7 +2223,7 @@ pub struct TextureFormatFeatures {
/// ASTC block dimensions
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum AstcBlock {
/// 4x4 block compressed texture. 16 bytes per block (8 bit/px).
B4x4,
@@ -2262,7 +2258,7 @@ pub enum AstcBlock {
/// ASTC RGBA channel
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum AstcChannel {
/// 8 bit integer RGBA, [0, 255] converted to/from linear-color float [0, 1] in shader.
///
@@ -4370,7 +4366,8 @@ impl MaintainResult {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate).
#[repr(C)]
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct StencilState {
/// Front face mode.
pub front: StencilFaceState,
@@ -4417,7 +4414,8 @@ impl StencilState {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate).
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct DepthBiasState {
/// Constant depth biasing factor, in basic units of the depth format.
pub constant: i32,
@@ -4458,7 +4456,8 @@ impl Eq for DepthBiasState {}
/// https://gpuweb.github.io/gpuweb/#dictdef-gpudepthstencilstate).
#[repr(C)]
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct DepthStencilState {
/// Format of the depth/stencil buffer, must be special depth format. Must match the format
/// of the depth/stencil attachment in [`CommandEncoder::begin_render_pass`][CEbrp].
@@ -4470,10 +4469,10 @@ pub struct DepthStencilState {
/// Comparison function used to compare depth values in the depth test.
pub depth_compare: CompareFunction,
/// Stencil state.
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))]
pub stencil: StencilState,
/// Depth bias state.
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))]
pub bias: DepthBiasState,
}
@@ -4505,7 +4504,7 @@ impl DepthStencilState {
/// https://gpuweb.github.io/gpuweb/#enumdef-gpuindexformat).
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum IndexFormat {
/// Indices are 16 bit unsigned integers.
@@ -4521,7 +4520,8 @@ pub enum IndexFormat {
/// https://gpuweb.github.io/gpuweb/#enumdef-gpustenciloperation).
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum StencilOperation {
/// Keep stencil value unchanged.
@@ -4554,7 +4554,8 @@ pub enum StencilOperation {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpustencilfacestate).
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct StencilFaceState {
/// Comparison function that determines if the fail_op or pass_op is used on the stencil buffer.
@@ -4604,7 +4605,8 @@ impl Default for StencilFaceState {
/// https://gpuweb.github.io/gpuweb/#enumdef-gpucomparefunction).
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum CompareFunction {
/// Function never passes
@@ -4698,7 +4700,8 @@ impl CompareFunction {
/// [`Instance`]: VertexStepMode::Instance
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum VertexStepMode {
/// Vertex data is advanced every vertex.
@@ -4719,7 +4722,8 @@ pub enum VertexStepMode {
/// [`vertex_attr_array`]: ../wgpu/macro.vertex_attr_array.html
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct VertexAttribute {
/// Format of the input
@@ -4736,7 +4740,8 @@ pub struct VertexAttribute {
/// https://gpuweb.github.io/gpuweb/#enumdef-gpuvertexformat).
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
pub enum VertexFormat {
/// Two unsigned bytes (u8). `vec2<u32>` in shaders.
@@ -4895,7 +4900,8 @@ impl_bitflags!(BufferUsages);
/// https://gpuweb.github.io/gpuweb/#dictdef-gpubufferdescriptor).
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BufferDescriptor<L> {
/// Debug label of a buffer. This will show up in graphics debuggers for easy identification.
pub label: L,
@@ -4929,7 +4935,8 @@ impl<L> BufferDescriptor<L> {
/// Corresponds to [WebGPU `GPUCommandEncoderDescriptor`](
/// https://gpuweb.github.io/gpuweb/#dictdef-gpucommandencoderdescriptor).
#[repr(C)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct CommandEncoderDescriptor<L> {
/// Debug label for the command encoder. This will show up in graphics debuggers for easy identification.
@@ -4954,7 +4961,8 @@ impl<T> Default for CommandEncoderDescriptor<Option<T>> {
/// Behavior of the presentation engine based on frame rate.
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum PresentMode {
/// Chooses FifoRelaxed -> Fifo based on availability.
///
@@ -5026,7 +5034,8 @@ pub enum PresentMode {
/// compositing.
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
pub enum CompositeAlphaMode {
/// Chooses either `Opaque` or `Inherit` automaticallydepending on the
@@ -5125,7 +5134,8 @@ impl Default for SurfaceCapabilities {
/// [`Surface`]: ../wgpu/struct.Surface.html
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct SurfaceConfiguration<V> {
/// The usage of the swap chain. The only supported usage is `RENDER_ATTACHMENT`.
pub usage: TextureUsages,
@@ -5251,7 +5261,7 @@ impl PresentationTimestamp {
/// This is not to be used as a generic color type, only for specific wgpu interfaces.
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Color {
/// Red component of the color
@@ -5310,7 +5320,8 @@ impl Color {
/// https://gpuweb.github.io/gpuweb/#enumdef-gputexturedimension).
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum TextureDimension {
/// 1D texture
#[cfg_attr(feature = "serde", serde(rename = "1d"))]
@@ -5329,7 +5340,8 @@ pub enum TextureDimension {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpuorigin2ddict).
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Origin2d {
///
@@ -5364,7 +5376,8 @@ impl std::fmt::Debug for Origin2d {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpuorigin3ddict).
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Origin3d {
/// X position of the origin
@@ -5406,7 +5419,8 @@ impl std::fmt::Debug for Origin3d {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpuextent3ddict).
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct Extent3d {
/// Width of the extent
@@ -5605,7 +5619,8 @@ fn test_max_mips() {
/// https://gpuweb.github.io/gpuweb/#dictdef-gputexturedescriptor).
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct TextureDescriptor<L, V> {
/// Debug label of the texture. This will show up in graphics debuggers for easy identification.
pub label: L,
@@ -5736,7 +5751,8 @@ impl<L, V> TextureDescriptor<L, V> {
/// https://gpuweb.github.io/gpuweb/#enumdef-gputextureaspect).
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum TextureAspect {
/// Depth, Stencil, and Color.
@@ -5760,7 +5776,8 @@ pub enum TextureAspect {
/// https://gpuweb.github.io/gpuweb/#enumdef-gpuaddressmode).
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum AddressMode {
/// Clamp the value to the edge of the texture
@@ -5793,7 +5810,8 @@ pub enum AddressMode {
/// https://gpuweb.github.io/gpuweb/#enumdef-gpufiltermode).
#[repr(C)]
#[derive(Copy, Clone, Debug, Default, Hash, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum FilterMode {
/// Nearest neighbor sampling.
@@ -5809,7 +5827,8 @@ pub enum FilterMode {
/// A range of push constant memory to pass to a shader stage.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct PushConstantRange {
/// Stage push constant range is visible from. Each stage can only be served by at most one range.
/// One range can serve multiple stages however.
@@ -5825,7 +5844,8 @@ pub struct PushConstantRange {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpucommandbufferdescriptor).
#[repr(C)]
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct CommandBufferDescriptor<L> {
/// Debug label of this command buffer.
pub label: L,
@@ -5846,7 +5866,8 @@ impl<L> CommandBufferDescriptor<L> {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundleencoderdescriptor).
#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct RenderBundleDepthStencil {
/// Format of the attachment.
pub format: TextureFormat,
@@ -5873,7 +5894,8 @@ pub struct RenderBundleDepthStencil {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpurenderbundledescriptor).
#[repr(C)]
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct RenderBundleDescriptor<L> {
/// Debug label of the render bundle encoder. This will show up in graphics debuggers for easy identification.
pub label: L,
@@ -5909,7 +5931,8 @@ impl<T> Default for RenderBundleDescriptor<Option<T>> {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagedatalayout).
#[repr(C)]
#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ImageDataLayout {
/// Offset into the buffer that is the start of the texture. Must be a multiple of texture block size.
/// For non-compressed textures, this is 1.
@@ -5949,7 +5972,8 @@ pub struct ImageDataLayout {
/// Corresponds to [WebGPU `GPUBufferBindingType`](
/// https://gpuweb.github.io/gpuweb/#enumdef-gpubufferbindingtype).
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum BufferBindingType {
/// A buffer for uniform values.
///
@@ -6014,7 +6038,8 @@ pub enum BufferBindingType {
/// Corresponds to [WebGPU `GPUTextureSampleType`](
/// https://gpuweb.github.io/gpuweb/#enumdef-gputexturesampletype).
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum TextureSampleType {
/// Sampling returns floats.
///
@@ -6096,7 +6121,8 @@ impl Default for TextureSampleType {
/// Corresponds to [WebGPU `GPUStorageTextureAccess`](
/// https://gpuweb.github.io/gpuweb/#enumdef-gpustoragetextureaccess).
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum StorageTextureAccess {
/// The texture can only be written in the shader and it:
@@ -6158,7 +6184,8 @@ pub enum StorageTextureAccess {
/// https://gpuweb.github.io/gpuweb/#enumdef-gpusamplerbindingtype).
#[repr(C)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum SamplerBindingType {
/// The sampling result is produced based on more than a single color sample from a texture,
@@ -6178,7 +6205,8 @@ pub enum SamplerBindingType {
/// Corresponds to WebGPU's mutually exclusive fields within [`GPUBindGroupLayoutEntry`](
/// https://gpuweb.github.io/gpuweb/#dictdef-gpubindgrouplayoutentry).
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub enum BindingType {
/// A buffer binding.
///
@@ -6194,7 +6222,7 @@ pub enum BindingType {
/// for each dynamic binding in increasing order of binding number.
///
/// [RPsbg]: ../wgpu/struct.RenderPass.html#method.set_bind_group
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))]
has_dynamic_offset: bool,
/// The minimum size for a [`BufferBinding`] matching this entry, in bytes.
@@ -6222,7 +6250,7 @@ pub enum BindingType {
/// [minimum buffer binding size]: https://www.w3.org/TR/webgpu/#minimum-buffer-binding-size
/// [`create_render_pipeline`]: ../wgpu/struct.Device.html#method.create_render_pipeline
/// [`create_compute_pipeline`]: ../wgpu/struct.Device.html#method.create_compute_pipeline
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))]
min_binding_size: Option<BufferSize>,
},
/// A sampler that can be used to sample a texture.
@@ -6327,7 +6355,8 @@ impl BindingType {
/// Corresponds to [WebGPU `GPUBindGroupLayoutEntry`](
/// https://gpuweb.github.io/gpuweb/#dictdef-gpubindgrouplayoutentry).
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "trace", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
pub struct BindGroupLayoutEntry {
/// Binding index. Must match shader index and be unique inside a BindGroupLayout. A binding
/// of index 1, would be described as `layout(set = 0, binding = 1) uniform` in shaders.
@@ -6341,7 +6370,7 @@ pub struct BindGroupLayoutEntry {
/// If this value is Some and `ty` is `BindingType::Texture`, [`Features::TEXTURE_BINDING_ARRAY`] must be supported.
///
/// If this value is Some and `ty` is any other variant, bind group creation will fail.
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))]
pub count: Option<NonZeroU32>,
}
@@ -6351,7 +6380,8 @@ pub struct BindGroupLayoutEntry {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopybuffer).
#[repr(C)]
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ImageCopyBuffer<B> {
/// The buffer to be copied to/from.
pub buffer: B,
@@ -6365,7 +6395,8 @@ pub struct ImageCopyBuffer<B> {
/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexture).
#[repr(C)]
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ImageCopyTexture<T> {
/// The texture to be copied to/from.
pub texture: T,
@@ -6374,10 +6405,10 @@ pub struct ImageCopyTexture<T> {
/// The base texel of the texture in the selected `mip_level`. Together
/// with the `copy_size` argument to copy functions, defines the
/// sub-region of the texture to copy.
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))]
pub origin: Origin3d,
/// The copy aspect.
#[cfg_attr(feature = "serde", serde(default))]
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(default))]
pub aspect: TextureAspect,
}
@@ -6497,7 +6528,8 @@ unsafe impl Sync for ExternalImageSource {}
/// Corresponds to [HTML Canvas `PredefinedColorSpace`](
/// https://html.spec.whatwg.org/multipage/canvas.html#predefinedcolorspace).
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
pub enum PredefinedColorSpace {
/// sRGB color space
@@ -6512,7 +6544,8 @@ pub enum PredefinedColorSpace {
/// Corresponds to [WebGPU `GPUImageCopyTextureTagged`](
/// https://gpuweb.github.io/gpuweb/#dictdef-gpuimagecopytexturetagged).
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ImageCopyTextureTagged<T> {
/// The texture to be copied to/from.
pub texture: T,
@@ -6543,7 +6576,8 @@ impl<T: Copy> ImageCopyTextureTagged<T> {
/// Subresource range within an image
#[repr(C)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))]
pub struct ImageSubresourceRange {
/// Aspect of the texture. Color textures must be [`TextureAspect::All`][TAA].
@@ -6644,7 +6678,8 @@ impl ImageSubresourceRange {
/// Color variation to use when sampler addressing mode is [`AddressMode::ClampToBorder`]
#[repr(C)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub enum SamplerBorderColor {
/// [0, 0, 0, 0]
TransparentBlack,
@@ -6666,7 +6701,8 @@ pub enum SamplerBorderColor {
/// Corresponds to [WebGPU `GPUQuerySetDescriptor`](
/// https://gpuweb.github.io/gpuweb/#dictdef-gpuquerysetdescriptor).
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct QuerySetDescriptor<L> {
/// Debug label for the query set.
pub label: L,
@@ -6693,7 +6729,8 @@ impl<L> QuerySetDescriptor<L> {
/// Corresponds to [WebGPU `GPUQueryType`](
/// https://gpuweb.github.io/gpuweb/#enumdef-gpuquerytype).
#[derive(Copy, Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub enum QueryType {
/// Query returns a single 64-bit number, serving as an occlusion boolean.
Occlusion,
@@ -6839,7 +6876,8 @@ impl DispatchIndirectArgs {
/// Describes how shader bound checks should be performed.
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
pub struct ShaderBoundChecks {
runtime_checks: bool,
}
@@ -7061,18 +7099,4 @@ pub enum DeviceLostReason {
Unknown = 0,
/// After Device::destroy
Destroyed = 1,
/// After Device::drop
///
/// WebGPU does not invoke the device lost callback when the device is
/// dropped to prevent garbage collection from being observable. In wgpu,
/// we invoke the callback on drop to help with managing memory owned by
/// the callback.
Dropped = 2,
/// After replacing the device_lost_callback
///
/// WebGPU does not have a concept of a device lost callback, but wgpu
/// does. wgpu guarantees that any supplied callback will be invoked
/// exactly once before it is dropped, which helps with managing the
/// memory owned by the callback.
ReplacedCallback = 3,
}