/
githubmirror
/
deno
Обзор
Документация
Войти
/
githubmirror
/
deno
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
ext/webgpu/queue.rs
263 строки
7 KB
Bartek Iwańczuk
chore: upgrade Rust toolchain to 1.95.0 (#33294)
07 май 2026, 09:44
Не верифицирован
07 май 2026, 09:44
269f316
Код
Авторство
О чём код?
// Copyright 2018-2026 the Deno authors. MIT license. use std::cell::RefCell; use std::rc::Rc; use std::time::Duration; use deno_core::GarbageCollected; use deno_core::WebIDL; use deno_core::cppgc::Ref; use deno_core::futures::channel::oneshot; use deno_core::op2; use deno_core::v8; use deno_error::JsErrorBox; use crate::Instance; use crate::buffer::GPUBuffer; use crate::command_buffer::GPUCommandBuffer; use crate::error::GPUGenericError; use crate::texture::GPUTexture; use crate::texture::GPUTextureAspect; use crate::webidl::GPUExtent3D; use crate::webidl::GPUOrigin3D; pub struct GPUQueue { pub instance: Instance, pub error_handler: super::error::ErrorHandler, pub label: String, pub id: wgpu_core::id::QueueId, pub device: wgpu_core::id::DeviceId, } impl Drop for GPUQueue { fn drop(&mut self) { self.instance.queue_drop(self.id); } } // SAFETY: we're sure this can be GCed unsafe impl GarbageCollected for GPUQueue { fn trace(&self, _visitor: &mut deno_core::v8::cppgc::Visitor) {} fn get_name(&self) -> &'static std::ffi::CStr { c"GPUQueue" } } #[op2] impl GPUQueue { #[constructor] #[cppgc] fn constructor(_: bool) -> Result<GPUQueue, GPUGenericError> { Err(GPUGenericError::InvalidConstructor) } #[getter] #[string] fn label(&self) -> String { self.label.clone() } #[setter] #[string] fn label(&self, #[webidl] _label: String) { // TODO(@crowlKats): no-op, needs wpgu to implement changing the label } #[required(1)] #[undefined] fn submit( &self, #[webidl] command_buffers: Vec<Ref<GPUCommandBuffer>>, ) -> Result<(), JsErrorBox> { let ids = command_buffers .into_iter() .map(|cb| cb.id) .collect::<Vec<_>>(); let err = self.instance.queue_submit(self.id, &ids).err(); if let Some((_, err)) = err { self.error_handler.push_error(Some(err)); } Ok(()) } // In the successful case, the promise should resolve to undefined, but // `#[undefined]` does not seem to work here. // https://github.com/denoland/deno/issues/29603 async fn on_submitted_work_done(&self) -> Result<(), JsErrorBox> { let (sender, receiver) = oneshot::channel::<()>(); let callback = Box::new(move || { sender.send(()).unwrap(); }); self .instance .queue_on_submitted_work_done(self.id, callback); let done = Rc::new(RefCell::new(false)); let done_ = done.clone(); let device_poll_fut = async move { while !*done.borrow() { { self .instance .device_poll(self.device, wgpu_types::PollType::wait_indefinitely()) .unwrap(); } tokio::time::sleep(Duration::from_millis(10)).await; } Ok::<(), JsErrorBox>(()) }; let receiver_fut = async move { receiver .await .map_err(|e| JsErrorBox::generic(e.to_string()))?; let mut done = done_.borrow_mut(); *done = true; Ok::<(), JsErrorBox>(()) }; tokio::try_join!(device_poll_fut, receiver_fut)?; Ok(()) } #[required(3)] #[undefined] fn write_buffer<'a>( &self, scope: &mut v8::PinScope<'a, '_>, #[webidl] buffer: Ref<GPUBuffer>, #[webidl(options(enforce_range = true))] buffer_offset: u64, data_arg: v8::Local<'a, v8::Value>, #[webidl(default = 0, options(enforce_range = true))] data_offset: u64, #[webidl(options(enforce_range = true))] size: Option<u64>, ) -> Result<(), JsErrorBox> { // Per the WebGPU spec, dataOffset and size are in elements (not bytes) // when data is a TypedArray, and in bytes otherwise. let (buf, bytes_per_element) = if let Ok(typed_array) = v8::Local::<v8::TypedArray>::try_from(data_arg) { let len = typed_array.length(); let bpe = (typed_array.byte_length()).checked_div(len).unwrap_or(1); let byte_offset = typed_array.byte_offset(); let byte_len = typed_array.byte_length(); let ab = typed_array.buffer(scope).unwrap(); // SAFETY: Pointer is non-null, and V8 guarantees that the // byte_offset is within the buffer backing store. let ptr = unsafe { ab.data().unwrap().as_ptr().add(byte_offset) }; let buf = // SAFETY: the slice is within the bounds of the backing store unsafe { std::slice::from_raw_parts(ptr as *const u8, byte_len) }; (buf, bpe) } else if let Ok(ab) = v8::Local::<v8::ArrayBuffer>::try_from(data_arg) { let byte_len = ab.byte_length(); let ptr = ab.data().unwrap().as_ptr(); let buf = // SAFETY: Pointer is non-null and byte_len is within the backing store. unsafe { std::slice::from_raw_parts(ptr as *const u8, byte_len) }; (buf, 1) } else if let Ok(view) = v8::Local::<v8::ArrayBufferView>::try_from(data_arg) { let byte_offset = view.byte_offset(); let byte_len = view.byte_length(); let ab = view.buffer(scope).unwrap(); // SAFETY: Pointer is non-null, and V8 guarantees that the // byte_offset is within the buffer backing store. let ptr = unsafe { ab.data().unwrap().as_ptr().add(byte_offset) }; // SAFETY: the slice is within the bounds of the backing store let buf = unsafe { std::slice::from_raw_parts(ptr as *const u8, byte_len) }; (buf, 1) } else { return Err(JsErrorBox::type_error( "data must be an ArrayBuffer or ArrayBufferView", )); }; let data_offset_bytes = data_offset as usize * bytes_per_element; let data = match size { Some(size) => { let size_bytes = size as usize * bytes_per_element; &buf[data_offset_bytes..(data_offset_bytes + size_bytes)] } None => &buf[data_offset_bytes..], }; let err = self .instance .queue_write_buffer(self.id, buffer.id, buffer_offset, data) .err(); self.error_handler.push_error(err); Ok(()) } #[required(4)] #[undefined] fn write_texture( &self, #[webidl] destination: GPUTexelCopyTextureInfo, #[anybuffer] buf: &[u8], #[webidl] data_layout: GPUTexelCopyBufferLayout, #[webidl] size: GPUExtent3D, ) { let destination = wgpu_types::TexelCopyTextureInfo { texture: destination.texture.id, mip_level: destination.mip_level, origin: destination.origin.into(), aspect: destination.aspect.into(), }; let data_layout = wgpu_types::TexelCopyBufferLayout { offset: data_layout.offset, bytes_per_row: data_layout.bytes_per_row, rows_per_image: data_layout.rows_per_image, }; let err = self .instance .queue_write_texture( self.id, &destination, buf, &data_layout, &size.into(), ) .err(); self.error_handler.push_error(err); } } #[derive(WebIDL)] #[webidl(dictionary)] pub(crate) struct GPUTexelCopyTextureInfo { pub texture: Ref<GPUTexture>, #[webidl(default = 0)] #[options(enforce_range = true)] pub mip_level: u32, #[webidl(default = Default::default())] pub origin: GPUOrigin3D, #[webidl(default = GPUTextureAspect::All)] pub aspect: GPUTextureAspect, } #[derive(WebIDL)] #[webidl(dictionary)] struct GPUTexelCopyBufferLayout { #[webidl(default = 0)] #[options(enforce_range = true)] offset: u64, #[options(enforce_range = true)] bytes_per_row: Option<u32>, #[options(enforce_range = true)] rows_per_image: Option<u32>, }