lib.rs (14442B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use crate::command::{RecordedComputePass, RecordedRenderPass}; 6 use wgc::id; 7 8 pub mod client; 9 pub mod command; 10 pub mod error; 11 pub mod server; 12 13 pub use wgc::command::ffi::Command as CommandEncoderAction; 14 15 use std::marker::PhantomData; 16 use std::{borrow::Cow, mem, slice}; 17 18 use nsstring::nsACString; 19 20 type RawString = *const std::os::raw::c_char; 21 22 fn cow_label(raw: &RawString) -> Option<Cow<'_, str>> { 23 if raw.is_null() { 24 None 25 } else { 26 let cstr = unsafe { std::ffi::CStr::from_ptr(*raw) }; 27 cstr.to_str().ok().map(Cow::Borrowed) 28 } 29 } 30 31 // Hides the repeated boilerplate of turning a `Option<&nsACString>` into a `Option<Cow<str>`. 32 pub fn wgpu_string(gecko_string: Option<&nsACString>) -> Option<Cow<'_, str>> { 33 gecko_string.map(|s| s.to_utf8()) 34 } 35 36 /// An equivalent of `&[T]` for ffi structures and function parameters. 37 #[repr(C)] 38 pub struct FfiSlice<'a, T> { 39 // `data` may be null. 40 pub data: *const T, 41 pub length: usize, 42 pub _marker: PhantomData<&'a T>, 43 } 44 45 impl<'a, T> FfiSlice<'a, T> { 46 pub fn from_slice(slice: &'a [T]) -> FfiSlice<'a, T> { 47 Self { 48 data: slice.as_ptr(), 49 length: slice.len(), 50 _marker: PhantomData, 51 } 52 } 53 54 pub unsafe fn as_slice(&self) -> &'a [T] { 55 if self.data.is_null() { 56 // It is invalid to construct a rust slice with a null pointer. 57 return &[]; 58 } 59 60 std::slice::from_raw_parts(self.data, self.length) 61 } 62 } 63 64 impl<'a, T> Copy for FfiSlice<'a, T> {} 65 impl<'a, T> Clone for FfiSlice<'a, T> { 66 fn clone(&self) -> Self { 67 *self 68 } 69 } 70 71 #[repr(C)] 72 pub struct ByteBuf { 73 data: *mut u8, 74 len: usize, 75 capacity: usize, 76 } 77 78 impl ByteBuf { 79 fn new() -> Self { 80 Self { 81 data: std::ptr::null_mut(), 82 len: 0, 83 capacity: 0, 84 } 85 } 86 87 fn is_empty(&self) -> bool { 88 self.len == 0 89 } 90 91 fn from_vec(mut vec: Vec<u8>) -> Self { 92 if vec.is_empty() { 93 ByteBuf::new() 94 } else { 95 let bb = ByteBuf { 96 data: vec.as_mut_ptr(), 97 len: vec.len(), 98 capacity: vec.capacity(), 99 }; 100 mem::forget(vec); 101 bb 102 } 103 } 104 105 unsafe fn as_slice(&self) -> &[u8] { 106 slice::from_raw_parts(self.data, self.len) 107 } 108 } 109 110 fn make_byte_buf<T: serde::Serialize>(data: &T) -> ByteBuf { 111 let vec = bincode::serialize(data).unwrap(); 112 ByteBuf::from_vec(vec) 113 } 114 115 #[repr(C)] 116 #[derive(serde::Serialize, serde::Deserialize)] 117 pub struct AdapterInformation<S> { 118 id: id::AdapterId, 119 limits: wgt::Limits, 120 features: wgt::FeaturesWebGPU, 121 name: S, 122 vendor: u32, 123 device: u32, 124 device_type: wgt::DeviceType, 125 driver: S, 126 driver_info: S, 127 backend: wgt::Backend, 128 support_use_shared_texture_in_swap_chain: bool, 129 transient_saves_memory: bool, 130 subgroup_min_size: u32, 131 subgroup_max_size: u32, 132 } 133 134 #[repr(C)] 135 pub struct TextureViewDescriptor<'a> { 136 label: Option<&'a nsACString>, 137 format: Option<&'a wgt::TextureFormat>, 138 dimension: Option<&'a wgt::TextureViewDimension>, 139 aspect: wgt::TextureAspect, 140 base_mip_level: u32, 141 mip_level_count: Option<&'a u32>, 142 base_array_layer: u32, 143 array_layer_count: Option<&'a u32>, 144 } 145 146 // Declare an ID type for referring to external texture sources, and allow 147 // them to be managed by IdentityHub just like built-in wgpu resource types. 148 #[derive(Debug)] 149 pub enum ExternalTextureSource {} 150 impl id::Marker for ExternalTextureSource {} 151 pub type ExternalTextureSourceId = id::Id<ExternalTextureSource>; 152 153 #[repr(C)] 154 #[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)] 155 pub enum PredefinedColorSpace { 156 Srgb, 157 DisplayP3, 158 } 159 160 // Descriptor for creating an external texture as used by the client side. 161 // Contains the fields of dom::GPUExternalTextureDescriptor, but with the 162 // source encoded as an ID. 163 #[repr(C)] 164 #[derive(serde::Serialize, serde::Deserialize)] 165 pub struct ExternalTextureDescriptor<L> { 166 label: L, 167 source: Option<crate::ExternalTextureSourceId>, 168 color_space: PredefinedColorSpace, 169 } 170 171 impl<L> ExternalTextureDescriptor<L> { 172 #[must_use] 173 pub fn map_label<K>(&self, fun: impl FnOnce(&L) -> K) -> ExternalTextureDescriptor<K> { 174 ExternalTextureDescriptor { 175 label: fun(&self.label), 176 source: self.source, 177 color_space: self.color_space, 178 } 179 } 180 } 181 182 // Descriptor for creating an external texture as used by the server side. This 183 // contains information that can only be provided from the server side via the 184 // `ExternalTextureSourceHost`. It will be combined with the 185 // `ExternalTextureDescriptor` provided by the client in order to create the 186 // descriptor that will be passed to wgpu. 187 #[repr(C)] 188 struct ExternalTextureDescriptorFromSource<'a> { 189 planes: FfiSlice<'a, id::TextureViewId>, 190 width: u32, 191 height: u32, 192 format: wgt::ExternalTextureFormat, 193 yuv_conversion_matrix: [f32; 16], 194 gamut_conversion_matrix: [f32; 9], 195 src_transfer_function: wgt::ExternalTextureTransferFunction, 196 dst_transfer_function: wgt::ExternalTextureTransferFunction, 197 sample_transform: [f32; 6], 198 load_transform: [f32; 6], 199 } 200 201 #[derive(serde::Serialize, serde::Deserialize)] 202 #[repr(transparent)] 203 pub struct SurfaceFormat(i8); 204 #[derive(serde::Serialize, serde::Deserialize)] 205 #[repr(transparent)] 206 pub struct RemoteTextureOwnerId(u64); 207 #[derive(serde::Serialize, serde::Deserialize)] 208 #[repr(transparent)] 209 pub struct RemoteTextureId(u64); 210 #[derive(serde::Serialize, serde::Deserialize)] 211 #[repr(transparent)] 212 pub struct RemoteTextureTxnType(u32); 213 #[derive(serde::Serialize, serde::Deserialize)] 214 #[repr(transparent)] 215 pub struct RemoteTextureTxnId(u64); 216 217 #[derive(serde::Serialize, serde::Deserialize)] 218 #[repr(C)] 219 #[derive(Copy, Clone, Debug)] 220 #[cfg(target_os = "windows")] 221 pub struct FfiLUID { 222 low_part: core::ffi::c_ulong, 223 high_part: core::ffi::c_long, 224 } 225 226 #[derive(serde::Serialize, serde::Deserialize)] 227 pub enum QueueWriteDataSource { 228 DataBuffer(usize), 229 Shmem(usize), 230 } 231 232 const MAX_SWAPCHAIN_BUFFER_COUNT: usize = 10; 233 234 #[derive(serde::Serialize, serde::Deserialize)] 235 enum Message<'a> { 236 RequestAdapter { 237 adapter_id: id::AdapterId, 238 power_preference: wgt::PowerPreference, 239 force_fallback_adapter: bool, 240 }, 241 RequestDevice { 242 adapter_id: id::AdapterId, 243 device_id: id::DeviceId, 244 queue_id: id::QueueId, 245 desc: wgc::device::DeviceDescriptor<'a>, 246 }, 247 Device(id::DeviceId, DeviceAction<'a>), 248 Texture(id::DeviceId, id::TextureId, TextureAction<'a>), 249 CommandEncoder(id::DeviceId, id::CommandEncoderId, CommandEncoderAction), 250 CommandEncoderFinish( 251 id::DeviceId, 252 id::CommandEncoderId, 253 id::CommandBufferId, 254 wgt::CommandBufferDescriptor<wgc::Label<'a>>, 255 ), 256 ReplayRenderPass(id::DeviceId, id::CommandEncoderId, RecordedRenderPass), 257 ReplayComputePass(id::DeviceId, id::CommandEncoderId, RecordedComputePass), 258 QueueWrite { 259 device_id: id::DeviceId, 260 queue_id: id::QueueId, 261 data_source: QueueWriteDataSource, 262 action: QueueWriteAction, 263 }, 264 BufferMap { 265 device_id: id::DeviceId, 266 buffer_id: id::BufferId, 267 mode: u32, 268 offset: u64, 269 size: u64, 270 }, 271 BufferUnmap(id::DeviceId, id::BufferId, bool), 272 QueueSubmit( 273 id::DeviceId, 274 id::QueueId, 275 Cow<'a, [id::CommandBufferId]>, 276 Cow<'a, [id::TextureId]>, 277 Cow<'a, [crate::ExternalTextureSourceId]>, 278 ), 279 QueueOnSubmittedWorkDone(id::QueueId), 280 281 CreateSwapChain { 282 device_id: id::DeviceId, 283 queue_id: id::QueueId, 284 width: i32, 285 height: i32, 286 format: SurfaceFormat, 287 buffer_ids: [id::BufferId; MAX_SWAPCHAIN_BUFFER_COUNT], 288 remote_texture_owner_id: RemoteTextureOwnerId, 289 use_shared_texture_in_swap_chain: bool, 290 }, 291 SwapChainPresent { 292 texture_id: id::TextureId, 293 command_encoder_id: id::CommandEncoderId, 294 command_buffer_id: id::CommandBufferId, 295 remote_texture_id: RemoteTextureId, 296 remote_texture_owner_id: RemoteTextureOwnerId, 297 }, 298 SwapChainDrop { 299 remote_texture_owner_id: RemoteTextureOwnerId, 300 txn_type: RemoteTextureTxnType, 301 txn_id: RemoteTextureTxnId, 302 }, 303 304 DestroyBuffer(id::BufferId), 305 DestroyTexture(id::TextureId), 306 DestroyExternalTexture(id::ExternalTextureId), 307 DestroyExternalTextureSource(crate::ExternalTextureSourceId), 308 DestroyDevice(id::DeviceId), 309 310 DropAdapter(id::AdapterId), 311 DropDevice(id::DeviceId), 312 DropQueue(id::QueueId), 313 DropBuffer(id::BufferId), 314 DropCommandEncoder(id::CommandEncoderId), 315 DropRenderPassEncoder(id::RenderPassEncoderId), 316 DropComputePassEncoder(id::ComputePassEncoderId), 317 DropRenderBundleEncoder(id::RenderBundleEncoderId), 318 DropCommandBuffer(id::CommandBufferId), 319 DropRenderBundle(id::RenderBundleId), 320 DropBindGroupLayout(id::BindGroupLayoutId), 321 DropPipelineLayout(id::PipelineLayoutId), 322 DropBindGroup(id::BindGroupId), 323 DropShaderModule(id::ShaderModuleId), 324 DropComputePipeline(id::ComputePipelineId), 325 DropRenderPipeline(id::RenderPipelineId), 326 DropTexture(id::TextureId), 327 DropTextureView(id::TextureViewId), 328 DropExternalTexture(id::ExternalTextureId), 329 DropExternalTextureSource(crate::ExternalTextureSourceId), 330 DropSampler(id::SamplerId), 331 DropQuerySet(id::QuerySetId), 332 } 333 334 #[derive(serde::Serialize, serde::Deserialize)] 335 enum DeviceAction<'a> { 336 CreateBuffer { 337 buffer_id: id::BufferId, 338 desc: wgc::resource::BufferDescriptor<'a>, 339 shmem_handle_index: usize, 340 }, 341 CreateTexture( 342 id::TextureId, 343 wgc::resource::TextureDescriptor<'a>, 344 Option<SwapChainId>, 345 ), 346 CreateExternalTexture( 347 id::ExternalTextureId, 348 crate::ExternalTextureDescriptor<wgc::Label<'a>>, 349 ), 350 CreateSampler(id::SamplerId, wgc::resource::SamplerDescriptor<'a>), 351 CreateBindGroupLayout( 352 id::BindGroupLayoutId, 353 wgc::binding_model::BindGroupLayoutDescriptor<'a>, 354 ), 355 RenderPipelineGetBindGroupLayout(id::RenderPipelineId, u32, id::BindGroupLayoutId), 356 ComputePipelineGetBindGroupLayout(id::ComputePipelineId, u32, id::BindGroupLayoutId), 357 CreatePipelineLayout( 358 id::PipelineLayoutId, 359 wgc::binding_model::PipelineLayoutDescriptor<'a>, 360 ), 361 CreateBindGroup(id::BindGroupId, wgc::binding_model::BindGroupDescriptor<'a>), 362 CreateShaderModule(id::ShaderModuleId, wgc::Label<'a>, Cow<'a, str>), 363 CreateComputePipeline( 364 id::ComputePipelineId, 365 wgc::pipeline::ComputePipelineDescriptor<'a>, 366 bool, 367 ), 368 CreateRenderPipeline( 369 id::RenderPipelineId, 370 wgc::pipeline::RenderPipelineDescriptor<'a>, 371 bool, 372 ), 373 CreateRenderBundle( 374 id::RenderBundleId, 375 wgc::command::RenderBundleEncoder, 376 wgc::command::RenderBundleDescriptor<'a>, 377 ), 378 CreateRenderBundleError(id::RenderBundleId, wgc::Label<'a>), 379 CreateQuerySet(id::QuerySetId, wgc::resource::QuerySetDescriptor<'a>), 380 CreateCommandEncoder( 381 id::CommandEncoderId, 382 wgt::CommandEncoderDescriptor<wgc::Label<'a>>, 383 ), 384 Error { 385 message: String, 386 r#type: wgt::error::ErrorType, 387 }, 388 PushErrorScope(u8 /* dom::GPUErrorFilter */), 389 PopErrorScope, 390 } 391 392 #[derive(serde::Serialize, serde::Deserialize)] 393 enum QueueWriteAction { 394 Buffer { 395 dst: id::BufferId, 396 offset: wgt::BufferAddress, 397 }, 398 Texture { 399 dst: wgt::TexelCopyTextureInfo<id::TextureId>, 400 layout: wgt::TexelCopyBufferLayout, 401 size: wgt::Extent3d, 402 }, 403 } 404 405 #[derive(serde::Serialize, serde::Deserialize)] 406 enum TextureAction<'a> { 407 CreateView(id::TextureViewId, wgc::resource::TextureViewDescriptor<'a>), 408 } 409 410 #[derive(serde::Serialize, serde::Deserialize)] 411 struct PipelineError { 412 is_validation_error: bool, 413 error: String, 414 } 415 416 #[derive(serde::Serialize, serde::Deserialize)] 417 pub struct ShaderModuleCompilationMessage { 418 pub line_number: u64, 419 pub line_pos: u64, 420 pub utf16_offset: u64, 421 pub utf16_length: u64, 422 pub message: String, 423 } 424 425 #[derive(serde::Serialize, serde::Deserialize)] 426 pub enum BufferMapResult<'a> { 427 Success { 428 is_writable: bool, 429 offset: u64, 430 size: u64, 431 }, 432 Error(Cow<'a, str>), 433 } 434 435 #[derive(serde::Serialize, serde::Deserialize)] 436 enum ServerMessage<'a> { 437 RequestAdapterResponse(id::AdapterId, Option<AdapterInformation<Cow<'a, str>>>), 438 RequestDeviceResponse(id::DeviceId, id::QueueId, Option<String>), 439 PopErrorScopeResponse( 440 id::DeviceId, 441 u8, /* PopErrorScopeResultType */ 442 Cow<'a, str>, 443 ), 444 CreateRenderPipelineResponse { 445 pipeline_id: id::RenderPipelineId, 446 error: Option<PipelineError>, 447 }, 448 CreateComputePipelineResponse { 449 pipeline_id: id::ComputePipelineId, 450 error: Option<PipelineError>, 451 }, 452 CreateShaderModuleResponse(id::ShaderModuleId, Vec<ShaderModuleCompilationMessage>), 453 BufferMapResponse(id::BufferId, BufferMapResult<'a>), 454 QueueOnSubmittedWorkDoneResponse(id::QueueId), 455 456 /// This message tells the client when we are done with swapchain readback buffers. 457 /// Freeing a swapchain buffer too early may result in an ID resolution panic or 458 /// an error submitting swapchain-related commands to the GPU. 459 FreeSwapChainBufferIds([id::BufferId; MAX_SWAPCHAIN_BUFFER_COUNT]), 460 } 461 462 #[repr(C)] 463 pub struct TexelCopyBufferLayout<'a> { 464 pub offset: wgt::BufferAddress, 465 pub bytes_per_row: Option<&'a u32>, 466 pub rows_per_image: Option<&'a u32>, 467 } 468 469 impl<'a> TexelCopyBufferLayout<'a> { 470 fn into_wgt(&self) -> wgt::TexelCopyBufferLayout { 471 wgt::TexelCopyBufferLayout { 472 offset: self.offset, 473 bytes_per_row: self.bytes_per_row.map(|bpr| *bpr), 474 rows_per_image: self.rows_per_image.map(|rpi| *rpi), 475 } 476 } 477 } 478 479 #[repr(C)] 480 #[derive(Copy, Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 481 pub struct SwapChainId(pub u64);