mirror of
https://github.com/denoland/deno.git
synced 2025-01-21 04:52:26 -05:00
fixes
This commit is contained in:
parent
a8f02b8bb6
commit
d4c6bf56c3
15 changed files with 346 additions and 279 deletions
|
@ -12,4 +12,3 @@
|
||||||
deno_core = { path = "../deno_core/core" }
|
deno_core = { path = "../deno_core/core" }
|
||||||
deno_ops = { path = "../deno_core/ops" }
|
deno_ops = { path = "../deno_core/ops" }
|
||||||
serde_v8 = { path = "../deno_core/serde_v8" }
|
serde_v8 = { path = "../deno_core/serde_v8" }
|
||||||
v8 = { path = "../rusty_v8" }
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#![cfg(not(target_arch = "wasm32"))]
|
#![cfg(not(target_arch = "wasm32"))]
|
||||||
#![warn(unsafe_op_in_unsafe_fn)]
|
#![warn(unsafe_op_in_unsafe_fn)]
|
||||||
|
|
||||||
|
use deno_core::GarbageCollected;
|
||||||
pub use wgpu_core;
|
pub use wgpu_core;
|
||||||
pub use wgpu_types;
|
pub use wgpu_types;
|
||||||
|
|
||||||
|
@ -16,14 +17,41 @@ pub type Instance = std::sync::Arc<wgpu_core::global::Global>;
|
||||||
deno_core::extension!(
|
deno_core::extension!(
|
||||||
deno_webgpu,
|
deno_webgpu,
|
||||||
deps = [deno_webidl, deno_web],
|
deps = [deno_webidl, deno_web],
|
||||||
/*ops = [
|
ops = [wrap::create_gpu],
|
||||||
// surface
|
objects = [
|
||||||
surface::op_webgpu_surface_configure,
|
wrap::GPU,
|
||||||
surface::op_webgpu_surface_get_current_texture,
|
wrap::adapter::GPUAdapter,
|
||||||
surface::op_webgpu_surface_present,
|
wrap::adapter::GPUAdapterInfo,
|
||||||
// byow
|
wrap::bind_group::GPUBindGroup,
|
||||||
byow::op_webgpu_surface_create,
|
wrap::bind_group_layout::GPUBindGroupLayout,
|
||||||
],*/
|
wrap::buffer::GPUBuffer,
|
||||||
esm = ["00_init.js" /* "02_surface.js"*/,],
|
wrap::command_buffer::GPUCommandBuffer,
|
||||||
|
wrap::command_encoder::GPUCommandEncoder,
|
||||||
|
wrap::compute_pass::GPUComputePassEncoder,
|
||||||
|
wrap::compute_pipeline::GPUComputePipeline,
|
||||||
|
wrap::device::GPUDevice,
|
||||||
|
wrap::device::GPUDeviceLostInfo,
|
||||||
|
wrap::pipeline_layout::GPUPipelineLayout,
|
||||||
|
wrap::query_set::GPUQuerySet,
|
||||||
|
wrap::queue::GPUQueue,
|
||||||
|
wrap::render_bundle::GPURenderBundle,
|
||||||
|
wrap::render_bundle::GPURenderBundleEncoder,
|
||||||
|
wrap::render_pass::GPURenderPassEncoder,
|
||||||
|
wrap::render_pipeline::GPURenderPipeline,
|
||||||
|
wrap::sampler::GPUSampler,
|
||||||
|
wrap::shader::GPUShaderModule,
|
||||||
|
GPUSupportedFeatures,
|
||||||
|
wrap::adapter::GPUSupportedLimits,
|
||||||
|
wrap::texture::GPUTexture,
|
||||||
|
wrap::texture::GPUTextureView,
|
||||||
|
],
|
||||||
|
esm = ["00_init.js"],
|
||||||
lazy_loaded_esm = ["01_webgpu.js"],
|
lazy_loaded_esm = ["01_webgpu.js"],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
struct GPUSupportedFeatures {}
|
||||||
|
|
||||||
|
impl GarbageCollected for GPUSupportedFeatures {}
|
||||||
|
|
||||||
|
#[deno_core::op2]
|
||||||
|
impl GPUSupportedFeatures {}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2018-2025 the Deno authors. MIT license.
|
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use deno_core::cppgc::SameObject;
|
use deno_core::cppgc::SameObject;
|
||||||
|
@ -47,7 +48,7 @@ pub struct GPUAdapter {
|
||||||
|
|
||||||
pub features: SameObject<GPUAdapter>,
|
pub features: SameObject<GPUAdapter>,
|
||||||
pub limits: SameObject<GPUSupportedLimits>,
|
pub limits: SameObject<GPUSupportedLimits>,
|
||||||
pub info: Arc<SameObject<GPUAdapterInfo>>,
|
pub info: Rc<SameObject<GPUAdapterInfo>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GarbageCollected for GPUAdapter {}
|
impl GarbageCollected for GPUAdapter {}
|
||||||
|
@ -71,18 +72,19 @@ impl GPUAdapter {
|
||||||
let features = features_to_feature_names(features);
|
let features = features_to_feature_names(features);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
function createGPUSupportedFeatures(features) {
|
#[symbol("[[set]]")]
|
||||||
/** @type {GPUSupportedFeatures} */
|
function createGPUSupportedFeatures(features) {
|
||||||
const supportedFeatures = webidl.createBranded(GPUSupportedFeatures);
|
/** @type {GPUSupportedFeatures} */
|
||||||
supportedFeatures[webidl.setlikeInner] = new SafeSet(features);
|
const supportedFeatures = webidl.createBranded(GPUSupportedFeatures);
|
||||||
webidl.setlike(
|
supportedFeatures[webidl.setlikeInner] = new SafeSet(features);
|
||||||
supportedFeatures,
|
webidl.setlike(
|
||||||
GPUSupportedFeaturesPrototype,
|
supportedFeatures,
|
||||||
true,
|
GPUSupportedFeaturesPrototype,
|
||||||
);
|
true,
|
||||||
return supportedFeatures;
|
);
|
||||||
}
|
return supportedFeatures;
|
||||||
*/
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
todo!()
|
todo!()
|
||||||
})
|
})
|
||||||
|
@ -156,6 +158,7 @@ impl GPUAdapter {
|
||||||
adapter: self.id,
|
adapter: self.id,
|
||||||
lost_receiver: receiver,
|
lost_receiver: receiver,
|
||||||
limits: SameObject::new(),
|
limits: SameObject::new(),
|
||||||
|
features: SameObject::new(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2018-2025 the Deno authors. MIT license.
|
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::ptr::NonNull;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
@ -12,6 +11,7 @@ use deno_core::webidl::WebIdlInterfaceConverter;
|
||||||
use deno_core::GarbageCollected;
|
use deno_core::GarbageCollected;
|
||||||
use deno_core::WebIDL;
|
use deno_core::WebIDL;
|
||||||
use deno_error::JsErrorBox;
|
use deno_error::JsErrorBox;
|
||||||
|
use wgpu_core::device::HostMap as MapMode;
|
||||||
use wgpu_core::resource::BufferMapCallback;
|
use wgpu_core::resource::BufferMapCallback;
|
||||||
|
|
||||||
use crate::Instance;
|
use crate::Instance;
|
||||||
|
@ -55,9 +55,9 @@ pub struct GPUBuffer {
|
||||||
pub usage: u32,
|
pub usage: u32,
|
||||||
|
|
||||||
pub map_state: RefCell<&'static str>,
|
pub map_state: RefCell<&'static str>,
|
||||||
|
pub map_mode: RefCell<Option<MapMode>>,
|
||||||
|
|
||||||
pub mapped_js_buffers:
|
pub mapped_js_buffers: RefCell<Vec<v8::Global<v8::ArrayBuffer>>>,
|
||||||
RefCell<Vec<(NonNull<u8>, usize, Option<v8::Global<v8::Uint8Array>>)>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WebIdlInterfaceConverter for GPUBuffer {
|
impl WebIdlInterfaceConverter for GPUBuffer {
|
||||||
|
@ -152,6 +152,13 @@ impl GPUBuffer {
|
||||||
*self.map_state.borrow_mut() = "pending";
|
*self.map_state.borrow_mut() = "pending";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mode = if read_mode {
|
||||||
|
MapMode::Read
|
||||||
|
} else {
|
||||||
|
assert!(write_mode);
|
||||||
|
MapMode::Write
|
||||||
|
};
|
||||||
|
|
||||||
let (sender, receiver) =
|
let (sender, receiver) =
|
||||||
oneshot::channel::<wgpu_core::resource::BufferAccessResult>();
|
oneshot::channel::<wgpu_core::resource::BufferAccessResult>();
|
||||||
|
|
||||||
|
@ -168,12 +175,7 @@ impl GPUBuffer {
|
||||||
offset,
|
offset,
|
||||||
Some(range_size),
|
Some(range_size),
|
||||||
wgpu_core::resource::BufferMapOperation {
|
wgpu_core::resource::BufferMapOperation {
|
||||||
host: if read_mode {
|
host: mode,
|
||||||
wgpu_core::device::HostMap::Read
|
|
||||||
} else {
|
|
||||||
assert!(write_mode);
|
|
||||||
wgpu_core::device::HostMap::Write
|
|
||||||
},
|
|
||||||
callback: Some(BufferMapCallback::from_rust(callback)),
|
callback: Some(BufferMapCallback::from_rust(callback)),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -216,17 +218,17 @@ impl GPUBuffer {
|
||||||
tokio::try_join!(device_poll_fut, receiver_fut)?;
|
tokio::try_join!(device_poll_fut, receiver_fut)?;
|
||||||
|
|
||||||
*self.map_state.borrow_mut() = "mapped";
|
*self.map_state.borrow_mut() = "mapped";
|
||||||
|
*self.map_mode.borrow_mut() = Some(mode);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[buffer]
|
fn get_mapped_range<'s>(
|
||||||
fn get_mapped_range(
|
|
||||||
&self,
|
&self,
|
||||||
scope: &mut v8::HandleScope,
|
scope: &mut v8::HandleScope<'s>,
|
||||||
#[webidl/*(default = 0)*/] offset: u64,
|
#[webidl/*(default = 0)*/] offset: u64,
|
||||||
#[webidl] size: Option<u64>,
|
#[webidl] size: Option<u64>,
|
||||||
) -> Result<Vec<u8>, BufferError> {
|
) -> Result<v8::Local<'s, v8::Uint8Array>, BufferError> {
|
||||||
let size = size.unwrap_or_else(|| self.size.saturating_sub(offset));
|
let size = size.unwrap_or_else(|| self.size.saturating_sub(offset));
|
||||||
|
|
||||||
let (slice_pointer, range_size) = self
|
let (slice_pointer, range_size) = self
|
||||||
|
@ -234,34 +236,50 @@ impl GPUBuffer {
|
||||||
.buffer_get_mapped_range(self.id, offset, Some(size))
|
.buffer_get_mapped_range(self.id, offset, Some(size))
|
||||||
.map_err(BufferError::Access)?;
|
.map_err(BufferError::Access)?;
|
||||||
|
|
||||||
let slice = unsafe {
|
let mode = self.map_mode.borrow();
|
||||||
std::slice::from_raw_parts(slice_pointer.as_ptr(), range_size as usize)
|
let mode = mode.as_ref().unwrap();
|
||||||
|
|
||||||
|
let bs = if mode == &MapMode::Write {
|
||||||
|
unsafe extern "C" fn noop_deleter_callback(
|
||||||
|
_data: *mut std::ffi::c_void,
|
||||||
|
_byte_length: usize,
|
||||||
|
_deleter_data: *mut std::ffi::c_void,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
v8::ArrayBuffer::new_backing_store_from_ptr(
|
||||||
|
slice_pointer.as_ptr() as _,
|
||||||
|
range_size as usize,
|
||||||
|
noop_deleter_callback,
|
||||||
|
std::ptr::null_mut(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let slice = unsafe {
|
||||||
|
std::slice::from_raw_parts(slice_pointer.as_ptr(), range_size as usize)
|
||||||
|
};
|
||||||
|
v8::ArrayBuffer::new_backing_store_from_vec(slice.to_vec())
|
||||||
};
|
};
|
||||||
let ab = v8::ArrayBuffer::new(scope, slice.len());
|
|
||||||
v8::Uint8Array::new(scope, ab, 0, slice.len());
|
|
||||||
|
|
||||||
// TODO: store buf
|
let shared_bs = bs.make_shared();
|
||||||
self
|
let ab = v8::ArrayBuffer::with_backing_store(scope, &shared_bs);
|
||||||
.mapped_js_buffers
|
|
||||||
.borrow_mut()
|
|
||||||
.push((slice_pointer, range_size as usize));
|
|
||||||
|
|
||||||
Ok(slice.to_vec())
|
if mode == &MapMode::Write {
|
||||||
|
self
|
||||||
|
.mapped_js_buffers
|
||||||
|
.borrow_mut()
|
||||||
|
.push(v8::Global::new(scope, ab));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(v8::Uint8Array::new(scope, ab, 0, range_size as usize).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[nofast]
|
#[nofast]
|
||||||
fn unmap(&self, scope: &mut v8::HandleScope) -> Result<(), BufferError> {
|
fn unmap(&self, scope: &mut v8::HandleScope) -> Result<(), BufferError> {
|
||||||
for (slice_pointer, range_size, buf) in
|
for ab in self.mapped_js_buffers.replace(vec![]) {
|
||||||
self.mapped_js_buffers.replace(vec![])
|
let ab = ab.open(scope);
|
||||||
{
|
ab.detach(None);
|
||||||
if let Some(buf) = buf {
|
|
||||||
let buf = buf.open(scope);
|
|
||||||
|
|
||||||
let slice = unsafe {
|
|
||||||
std::slice::from_raw_parts_mut(slice_pointer.as_ptr(), range_size)
|
|
||||||
};
|
|
||||||
buf.copy_contents(slice);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
|
|
|
@ -132,55 +132,70 @@ impl GPUComputePassEncoder {
|
||||||
) -> Result<(), WebIdlError> {
|
) -> Result<(), WebIdlError> {
|
||||||
const PREFIX: &str =
|
const PREFIX: &str =
|
||||||
"Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
|
"Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
|
||||||
let offsets =
|
let err = if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>()
|
||||||
if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>() {
|
{
|
||||||
let start = u64::convert(
|
let start = u64::convert(
|
||||||
scope,
|
scope,
|
||||||
dynamic_offsets,
|
dynamic_offsets_data_start,
|
||||||
Cow::Borrowed(PREFIX),
|
Cow::Borrowed(PREFIX),
|
||||||
(|| Cow::Borrowed("Argument 4")).into(),
|
(|| Cow::Borrowed("Argument 4")).into(),
|
||||||
&IntOptions {
|
&IntOptions {
|
||||||
clamp: false,
|
clamp: false,
|
||||||
enforce_range: true,
|
enforce_range: true,
|
||||||
},
|
},
|
||||||
)?;
|
)? as usize;
|
||||||
let len = u32::convert(
|
let len = u32::convert(
|
||||||
scope,
|
scope,
|
||||||
dynamic_offsets,
|
dynamic_offsets_data_length,
|
||||||
Cow::Borrowed(PREFIX),
|
Cow::Borrowed(PREFIX),
|
||||||
(|| Cow::Borrowed("Argument 5")).into(),
|
(|| Cow::Borrowed("Argument 5")).into(),
|
||||||
&IntOptions {
|
&IntOptions {
|
||||||
clamp: false,
|
clamp: false,
|
||||||
enforce_range: true,
|
enforce_range: true,
|
||||||
},
|
},
|
||||||
)?;
|
)? as usize;
|
||||||
|
|
||||||
// TODO
|
let ab = uint_32.buffer(scope).unwrap();
|
||||||
|
let ptr = ab.data().unwrap();
|
||||||
|
let ab_len = ab.byte_length() / 4;
|
||||||
|
|
||||||
vec![]
|
let data =
|
||||||
} else {
|
unsafe { std::slice::from_raw_parts(ptr.as_ptr() as _, ab_len) };
|
||||||
<Option<Vec<u32>>>::convert(
|
|
||||||
scope,
|
|
||||||
dynamic_offsets,
|
|
||||||
Cow::Borrowed(PREFIX),
|
|
||||||
(|| Cow::Borrowed("Argument 3")).into(),
|
|
||||||
&IntOptions {
|
|
||||||
clamp: false,
|
|
||||||
enforce_range: true,
|
|
||||||
},
|
|
||||||
)?
|
|
||||||
.unwrap_or_default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let err = self
|
let offsets = &data[start..(start + len)];
|
||||||
.instance
|
|
||||||
.compute_pass_set_bind_group(
|
self
|
||||||
&mut self.compute_pass.borrow_mut(),
|
.instance
|
||||||
index,
|
.compute_pass_set_bind_group(
|
||||||
bind_group.into_option().map(|bind_group| bind_group.id),
|
&mut self.compute_pass.borrow_mut(),
|
||||||
&offsets,
|
index,
|
||||||
)
|
bind_group.into_option().map(|bind_group| bind_group.id),
|
||||||
.err();
|
offsets,
|
||||||
|
)
|
||||||
|
.err()
|
||||||
|
} else {
|
||||||
|
let offsets = <Option<Vec<u32>>>::convert(
|
||||||
|
scope,
|
||||||
|
dynamic_offsets,
|
||||||
|
Cow::Borrowed(PREFIX),
|
||||||
|
(|| Cow::Borrowed("Argument 3")).into(),
|
||||||
|
&IntOptions {
|
||||||
|
clamp: false,
|
||||||
|
enforce_range: true,
|
||||||
|
},
|
||||||
|
)?
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
self
|
||||||
|
.instance
|
||||||
|
.compute_pass_set_bind_group(
|
||||||
|
&mut self.compute_pass.borrow_mut(),
|
||||||
|
index,
|
||||||
|
bind_group.into_option().map(|bind_group| bind_group.id),
|
||||||
|
&offsets,
|
||||||
|
)
|
||||||
|
.err()
|
||||||
|
};
|
||||||
|
|
||||||
self.error_handler.push_error(err);
|
self.error_handler.push_error(err);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
use std::sync::Arc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use deno_core::cppgc::SameObject;
|
use deno_core::cppgc::SameObject;
|
||||||
use deno_core::op2;
|
use deno_core::op2;
|
||||||
|
@ -40,7 +40,7 @@ pub struct GPUDevice {
|
||||||
|
|
||||||
pub features: SameObject<GPUDevice>,
|
pub features: SameObject<GPUDevice>,
|
||||||
pub limits: SameObject<GPUSupportedLimits>,
|
pub limits: SameObject<GPUSupportedLimits>,
|
||||||
pub adapter_info: Arc<SameObject<GPUAdapterInfo>>,
|
pub adapter_info: Rc<SameObject<GPUAdapterInfo>>,
|
||||||
|
|
||||||
pub queue_obj: SameObject<GPUQueue>,
|
pub queue_obj: SameObject<GPUQueue>,
|
||||||
|
|
||||||
|
@ -132,6 +132,7 @@ impl GPUDevice {
|
||||||
} else {
|
} else {
|
||||||
"unmapped"
|
"unmapped"
|
||||||
}),
|
}),
|
||||||
|
map_mode: RefCell::new(None),
|
||||||
mapped_js_buffers: RefCell::new(vec![]),
|
mapped_js_buffers: RefCell::new(vec![]),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -517,7 +518,7 @@ impl GPUDevice {
|
||||||
GPURenderBundleEncoder {
|
GPURenderBundleEncoder {
|
||||||
instance: self.instance.clone(),
|
instance: self.instance.clone(),
|
||||||
error_handler: self.error_handler.clone(),
|
error_handler: self.error_handler.clone(),
|
||||||
encoder: RefCell::new(encoder),
|
encoder: RefCell::new(Some(encoder)),
|
||||||
label: descriptor.label,
|
label: descriptor.label,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -549,13 +550,14 @@ impl GPUDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: return same promise
|
||||||
#[async_method]
|
#[async_method]
|
||||||
#[getter]
|
#[getter]
|
||||||
#[cppgc]
|
#[cppgc]
|
||||||
async fn lost(&self) -> GPUDeviceLostInfo {
|
async fn lost(&self) -> GPUDeviceLostInfo {
|
||||||
self.lost_receiver.await.unwrap();
|
// TODO: self.lost_receiver.await.unwrap();
|
||||||
|
|
||||||
GPUDeviceLostInfo {}
|
GPUDeviceLostInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
#[required(1)]
|
#[required(1)]
|
||||||
|
@ -570,9 +572,9 @@ impl GPUDevice {
|
||||||
#[async_method]
|
#[async_method]
|
||||||
async fn pop_error_scope<'a>(
|
async fn pop_error_scope<'a>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut v8::HandleScope<'a>,
|
//scope: &mut v8::HandleScope<'a>,
|
||||||
) -> Result<v8::Local<'a, v8::Value>, JsErrorBox> {
|
) -> Result<v8::Local<'a, v8::Value>, JsErrorBox> {
|
||||||
if self.error_handler.is_lost.get().is_some() {
|
/* if self.error_handler.is_lost.get().is_some() {
|
||||||
return Ok(v8::null(scope).into());
|
return Ok(v8::null(scope).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,7 +589,12 @@ impl GPUDevice {
|
||||||
Ok(deno_core::error::to_v8_error(scope, &err))
|
Ok(deno_core::error::to_v8_error(scope, &err))
|
||||||
} else {
|
} else {
|
||||||
Ok(v8::null(scope).into())
|
Ok(v8::null(scope).into())
|
||||||
}
|
}*/
|
||||||
|
|
||||||
|
Err(JsErrorBox::new(
|
||||||
|
"DOMExceptionOperationError",
|
||||||
|
"There are no error scopes on the error scope stack",
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,7 +815,7 @@ impl GPUDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GPUDeviceLostInfo {}
|
pub struct GPUDeviceLostInfo;
|
||||||
|
|
||||||
impl GarbageCollected for GPUDeviceLostInfo {}
|
impl GarbageCollected for GPUDeviceLostInfo {}
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ pub enum GPUErrorFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, deno_error::JsError)]
|
#[derive(Debug, deno_error::JsError)]
|
||||||
enum GPUError {
|
pub enum GPUError {
|
||||||
#[class("UNREACHABLE")] // TODO
|
#[class("UNREACHABLE")] // TODO
|
||||||
Lost,
|
Lost,
|
||||||
#[class("GPUValidationError")]
|
#[class("GPUValidationError")]
|
||||||
|
|
|
@ -12,69 +12,34 @@ use wgpu_types::PowerPreference;
|
||||||
|
|
||||||
use crate::Instance;
|
use crate::Instance;
|
||||||
|
|
||||||
mod adapter;
|
pub mod adapter;
|
||||||
mod bind_group;
|
pub mod bind_group;
|
||||||
mod bind_group_layout;
|
pub mod bind_group_layout;
|
||||||
mod buffer;
|
pub mod buffer;
|
||||||
mod command_buffer;
|
pub mod command_buffer;
|
||||||
mod command_encoder;
|
pub mod command_encoder;
|
||||||
mod compute_pass;
|
pub mod compute_pass;
|
||||||
mod compute_pipeline;
|
pub mod compute_pipeline;
|
||||||
mod device;
|
pub mod device;
|
||||||
mod error;
|
pub mod error;
|
||||||
mod pipeline_layout;
|
pub mod pipeline_layout;
|
||||||
mod query_set;
|
pub mod query_set;
|
||||||
mod queue;
|
pub mod queue;
|
||||||
mod render_bundle;
|
pub mod render_bundle;
|
||||||
mod render_pass;
|
pub mod render_pass;
|
||||||
mod render_pipeline;
|
pub mod render_pipeline;
|
||||||
mod sampler;
|
pub mod sampler;
|
||||||
mod shader;
|
pub mod shader;
|
||||||
mod texture;
|
pub mod texture;
|
||||||
mod webidl;
|
pub mod webidl;
|
||||||
|
|
||||||
deno_core::extension!(
|
|
||||||
deno_webgpu,
|
|
||||||
deps = [deno_webidl, deno_web],
|
|
||||||
ops = [create_gpu],
|
|
||||||
objects = [
|
|
||||||
GPU,
|
|
||||||
adapter::GPUAdapter,
|
|
||||||
adapter::GPUAdapterInfo,
|
|
||||||
bind_group::GPUBindGroup,
|
|
||||||
bind_group_layout::GPUBindGroupLayout,
|
|
||||||
buffer::GPUBuffer,
|
|
||||||
command_buffer::GPUCommandBuffer,
|
|
||||||
command_encoder::GPUCommandEncoder,
|
|
||||||
compute_pass::GPUComputePassEncoder,
|
|
||||||
compute_pipeline::GPUComputePipeline,
|
|
||||||
device::GPUDevice,
|
|
||||||
device::GPUDeviceLostInfo,
|
|
||||||
pipeline_layout::GPUPipelineLayout,
|
|
||||||
query_set::GPUQuerySet,
|
|
||||||
queue::GPUQueue,
|
|
||||||
render_bundle::GPURenderBundle,
|
|
||||||
render_bundle::GPURenderBundleEncoder,
|
|
||||||
render_pass::GPURenderPassEncoder,
|
|
||||||
render_pipeline::GPURenderPipeline,
|
|
||||||
sampler::GPUSampler,
|
|
||||||
shader::GPUShaderModule,
|
|
||||||
//adapter::GPUSupportedFeatures,
|
|
||||||
adapter::GPUSupportedLimits,
|
|
||||||
texture::GPUTexture,
|
|
||||||
texture::GPUTextureView,
|
|
||||||
],
|
|
||||||
esm = ["00_init.js", "02_surface.js"],
|
|
||||||
lazy_loaded_esm = ["01_webgpu.js"],
|
|
||||||
);
|
|
||||||
|
|
||||||
#[op2]
|
#[op2]
|
||||||
#[cppgc]
|
#[cppgc]
|
||||||
fn create_gpu() -> GPU {
|
pub fn create_gpu() -> GPU {
|
||||||
GPU
|
GPU
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GPU;
|
pub struct GPU;
|
||||||
|
|
||||||
impl GarbageCollected for GPU {}
|
impl GarbageCollected for GPU {}
|
||||||
|
|
||||||
|
@ -127,7 +92,7 @@ impl GPU {
|
||||||
instance: instance.clone(),
|
instance: instance.clone(),
|
||||||
features: SameObject::new(),
|
features: SameObject::new(),
|
||||||
limits: SameObject::new(),
|
limits: SameObject::new(),
|
||||||
info: Arc::new(SameObject::new()),
|
info: Rc::new(SameObject::new()),
|
||||||
id,
|
id,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -158,5 +123,3 @@ macro_rules! with_label {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use with_label;
|
|
||||||
|
|
|
@ -54,13 +54,15 @@ impl GPUQueue {
|
||||||
&self,
|
&self,
|
||||||
#[webidl] buffer: Ptr<GPUBuffer>,
|
#[webidl] buffer: Ptr<GPUBuffer>,
|
||||||
#[webidl/*(options(enforce_range = true))*/] buffer_offset: u64,
|
#[webidl/*(options(enforce_range = true))*/] buffer_offset: u64,
|
||||||
#[serde] data: (), // TODO: AllowSharedBufferSource
|
#[anybuffer] buf: &[u8], // TODO: AllowSharedBufferSource
|
||||||
#[webidl/*(default = 0, options(enforce_range = true))*/] data_offset: u64,
|
#[webidl/*(default = 0, options(enforce_range = true))*/] data_offset: u64,
|
||||||
#[webidl/*(options(enforce_range = true))*/] size: Option<u64>,
|
#[webidl/*(options(enforce_range = true))*/] size: Option<u64>,
|
||||||
) {
|
) {
|
||||||
let data = match size {
|
let data = match size {
|
||||||
Some(size) => &buf[data_offset..(data_offset + size)],
|
Some(size) => {
|
||||||
None => &buf[data_offset..],
|
&buf[(data_offset as usize)..((data_offset + size) as usize)]
|
||||||
|
}
|
||||||
|
None => &buf[(data_offset as usize)..],
|
||||||
};
|
};
|
||||||
|
|
||||||
let err = self
|
let err = self
|
||||||
|
@ -75,7 +77,7 @@ impl GPUQueue {
|
||||||
fn write_texture(
|
fn write_texture(
|
||||||
&self,
|
&self,
|
||||||
#[webidl] destination: GPUTexelCopyTextureInfo,
|
#[webidl] destination: GPUTexelCopyTextureInfo,
|
||||||
#[serde] data: (), // TODO: AllowSharedBufferSource
|
#[anybuffer] buf: &[u8], // TODO: AllowSharedBufferSource
|
||||||
#[webidl] data_layout: GPUTexelCopyBufferLayout,
|
#[webidl] data_layout: GPUTexelCopyBufferLayout,
|
||||||
#[webidl] size: GPUExtent3D,
|
#[webidl] size: GPUExtent3D,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -116,62 +116,77 @@ impl GPURenderBundleEncoder {
|
||||||
dynamic_offsets_data_start: v8::Local<'a, v8::Value>,
|
dynamic_offsets_data_start: v8::Local<'a, v8::Value>,
|
||||||
dynamic_offsets_data_length: v8::Local<'a, v8::Value>,
|
dynamic_offsets_data_length: v8::Local<'a, v8::Value>,
|
||||||
) -> Result<(), SetBindGroupError> {
|
) -> Result<(), SetBindGroupError> {
|
||||||
const PREFIX: &str =
|
|
||||||
"Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
|
|
||||||
let offsets =
|
|
||||||
if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>() {
|
|
||||||
let start = u64::convert(
|
|
||||||
scope,
|
|
||||||
dynamic_offsets,
|
|
||||||
Cow::Borrowed(PREFIX),
|
|
||||||
(|| Cow::Borrowed("Argument 4")).into(),
|
|
||||||
&IntOptions {
|
|
||||||
clamp: false,
|
|
||||||
enforce_range: true,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
let len = u32::convert(
|
|
||||||
scope,
|
|
||||||
dynamic_offsets,
|
|
||||||
Cow::Borrowed(PREFIX),
|
|
||||||
(|| Cow::Borrowed("Argument 5")).into(),
|
|
||||||
&IntOptions {
|
|
||||||
clamp: false,
|
|
||||||
enforce_range: true,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// TODO
|
|
||||||
|
|
||||||
vec![]
|
|
||||||
} else {
|
|
||||||
<Option<Vec<u32>>>::convert(
|
|
||||||
scope,
|
|
||||||
dynamic_offsets,
|
|
||||||
Cow::Borrowed(PREFIX),
|
|
||||||
(|| Cow::Borrowed("Argument 3")).into(),
|
|
||||||
&IntOptions {
|
|
||||||
clamp: false,
|
|
||||||
enforce_range: true,
|
|
||||||
},
|
|
||||||
)?
|
|
||||||
.unwrap_or_default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut encoder = self.encoder.borrow_mut();
|
let mut encoder = self.encoder.borrow_mut();
|
||||||
let encoder = encoder.as_mut().ok_or_else(|| {
|
let encoder = encoder.as_mut().ok_or_else(|| {
|
||||||
JsErrorBox::generic("Encoder has already been finished")
|
JsErrorBox::generic("Encoder has already been finished")
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
unsafe {
|
const PREFIX: &str =
|
||||||
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group(
|
"Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
|
||||||
encoder,
|
if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>() {
|
||||||
index,
|
let start = u64::convert(
|
||||||
bind_group.into_option().map(|bind_group| bind_group.id),
|
scope,
|
||||||
offsets.as_ptr(),
|
dynamic_offsets_data_start,
|
||||||
offsets.len(),
|
Cow::Borrowed(PREFIX),
|
||||||
);
|
(|| Cow::Borrowed("Argument 4")).into(),
|
||||||
|
&IntOptions {
|
||||||
|
clamp: false,
|
||||||
|
enforce_range: true,
|
||||||
|
},
|
||||||
|
)? as usize;
|
||||||
|
let len = u32::convert(
|
||||||
|
scope,
|
||||||
|
dynamic_offsets_data_length,
|
||||||
|
Cow::Borrowed(PREFIX),
|
||||||
|
(|| Cow::Borrowed("Argument 5")).into(),
|
||||||
|
&IntOptions {
|
||||||
|
clamp: false,
|
||||||
|
enforce_range: true,
|
||||||
|
},
|
||||||
|
)? as usize;
|
||||||
|
|
||||||
|
let ab = uint_32.buffer(scope).unwrap();
|
||||||
|
let ptr = ab.data().unwrap();
|
||||||
|
let ab_len = ab.byte_length() / 4;
|
||||||
|
|
||||||
|
let data =
|
||||||
|
unsafe { std::slice::from_raw_parts(ptr.as_ptr() as _, ab_len) };
|
||||||
|
|
||||||
|
let offsets = &data[start..(start + len)];
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group(
|
||||||
|
encoder,
|
||||||
|
index,
|
||||||
|
bind_group.into_option().map(|bind_group| bind_group.id),
|
||||||
|
offsets.as_ptr(),
|
||||||
|
offsets.len(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let offsets = <Option<Vec<u32>>>::convert(
|
||||||
|
scope,
|
||||||
|
dynamic_offsets,
|
||||||
|
Cow::Borrowed(PREFIX),
|
||||||
|
(|| Cow::Borrowed("Argument 3")).into(),
|
||||||
|
&IntOptions {
|
||||||
|
clamp: false,
|
||||||
|
enforce_range: true,
|
||||||
|
},
|
||||||
|
)?
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
wgpu_core::command::bundle_ffi::wgpu_render_bundle_set_bind_group(
|
||||||
|
encoder,
|
||||||
|
index,
|
||||||
|
bind_group.into_option().map(|bind_group| bind_group.id),
|
||||||
|
offsets.as_ptr(),
|
||||||
|
offsets.len(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -199,55 +199,72 @@ impl GPURenderPassEncoder {
|
||||||
) -> Result<(), WebIdlError> {
|
) -> Result<(), WebIdlError> {
|
||||||
const PREFIX: &str =
|
const PREFIX: &str =
|
||||||
"Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
|
"Failed to execute 'setBindGroup' on 'GPUComputePassEncoder'";
|
||||||
let offsets =
|
|
||||||
if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>() {
|
|
||||||
let start = u64::convert(
|
|
||||||
scope,
|
|
||||||
dynamic_offsets,
|
|
||||||
Cow::Borrowed(PREFIX),
|
|
||||||
(|| Cow::Borrowed("Argument 4")).into(),
|
|
||||||
&IntOptions {
|
|
||||||
clamp: false,
|
|
||||||
enforce_range: true,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
let len = u32::convert(
|
|
||||||
scope,
|
|
||||||
dynamic_offsets,
|
|
||||||
Cow::Borrowed(PREFIX),
|
|
||||||
(|| Cow::Borrowed("Argument 5")).into(),
|
|
||||||
&IntOptions {
|
|
||||||
clamp: false,
|
|
||||||
enforce_range: true,
|
|
||||||
},
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// TODO
|
let err = if let Ok(uint_32) = dynamic_offsets.try_cast::<v8::Uint32Array>()
|
||||||
|
{
|
||||||
|
let start = u64::convert(
|
||||||
|
scope,
|
||||||
|
dynamic_offsets_data_start,
|
||||||
|
Cow::Borrowed(PREFIX),
|
||||||
|
(|| Cow::Borrowed("Argument 4")).into(),
|
||||||
|
&IntOptions {
|
||||||
|
clamp: false,
|
||||||
|
enforce_range: true,
|
||||||
|
},
|
||||||
|
)? as usize;
|
||||||
|
let len = u32::convert(
|
||||||
|
scope,
|
||||||
|
dynamic_offsets_data_length,
|
||||||
|
Cow::Borrowed(PREFIX),
|
||||||
|
(|| Cow::Borrowed("Argument 5")).into(),
|
||||||
|
&IntOptions {
|
||||||
|
clamp: false,
|
||||||
|
enforce_range: true,
|
||||||
|
},
|
||||||
|
)? as usize;
|
||||||
|
|
||||||
vec![]
|
let ab = uint_32.buffer(scope).unwrap();
|
||||||
} else {
|
let ptr = ab.data().unwrap();
|
||||||
<Option<Vec<u32>>>::convert(
|
let ab_len = ab.byte_length() / 4;
|
||||||
scope,
|
|
||||||
dynamic_offsets,
|
let data =
|
||||||
Cow::Borrowed(PREFIX),
|
unsafe { std::slice::from_raw_parts(ptr.as_ptr() as _, ab_len) };
|
||||||
(|| Cow::Borrowed("Argument 3")).into(),
|
|
||||||
&IntOptions {
|
let offsets = &data[start..(start + len)];
|
||||||
clamp: false,
|
|
||||||
enforce_range: true,
|
self
|
||||||
},
|
.instance
|
||||||
)?
|
.render_pass_set_bind_group(
|
||||||
.unwrap_or_default()
|
&mut self.render_pass.borrow_mut(),
|
||||||
};
|
index,
|
||||||
|
bind_group.into_option().map(|bind_group| bind_group.id),
|
||||||
|
offsets,
|
||||||
|
)
|
||||||
|
.err()
|
||||||
|
} else {
|
||||||
|
let offsets = <Option<Vec<u32>>>::convert(
|
||||||
|
scope,
|
||||||
|
dynamic_offsets,
|
||||||
|
Cow::Borrowed(PREFIX),
|
||||||
|
(|| Cow::Borrowed("Argument 3")).into(),
|
||||||
|
&IntOptions {
|
||||||
|
clamp: false,
|
||||||
|
enforce_range: true,
|
||||||
|
},
|
||||||
|
)?
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
self
|
||||||
|
.instance
|
||||||
|
.render_pass_set_bind_group(
|
||||||
|
&mut self.render_pass.borrow_mut(),
|
||||||
|
index,
|
||||||
|
bind_group.into_option().map(|bind_group| bind_group.id),
|
||||||
|
&offsets,
|
||||||
|
)
|
||||||
|
.err()
|
||||||
|
};
|
||||||
|
|
||||||
let err = self
|
|
||||||
.instance
|
|
||||||
.render_pass_set_bind_group(
|
|
||||||
&mut self.render_pass.borrow_mut(),
|
|
||||||
index,
|
|
||||||
bind_group.into_option().map(|bind_group| bind_group.id),
|
|
||||||
&offsets,
|
|
||||||
)
|
|
||||||
.err();
|
|
||||||
self.error_handler.push_error(err);
|
self.error_handler.push_error(err);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -38,6 +38,7 @@ const {
|
||||||
MathRound,
|
MathRound,
|
||||||
MathTrunc,
|
MathTrunc,
|
||||||
Number,
|
Number,
|
||||||
|
SymbolFor,
|
||||||
NumberIsFinite,
|
NumberIsFinite,
|
||||||
NumberIsNaN,
|
NumberIsNaN,
|
||||||
NumberMAX_SAFE_INTEGER,
|
NumberMAX_SAFE_INTEGER,
|
||||||
|
@ -1311,7 +1312,7 @@ function configureProperties(obj) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const setlikeInner = Symbol("[[set]]");
|
const setlikeInner = SymbolFor("[[set]]");
|
||||||
|
|
||||||
// Ref: https://webidl.spec.whatwg.org/#es-setlike
|
// Ref: https://webidl.spec.whatwg.org/#es-setlike
|
||||||
function setlike(obj, objPrototype, readonly) {
|
function setlike(obj, objPrototype, readonly) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ import * as signals from "ext:runtime/40_signals.js";
|
||||||
import * as tty from "ext:runtime/40_tty.js";
|
import * as tty from "ext:runtime/40_tty.js";
|
||||||
import * as kv from "ext:deno_kv/01_db.ts";
|
import * as kv from "ext:deno_kv/01_db.ts";
|
||||||
import * as cron from "ext:deno_cron/01_cron.ts";
|
import * as cron from "ext:deno_cron/01_cron.ts";
|
||||||
import * as webgpuSurface from "ext:deno_webgpu/02_surface.js";
|
//import * as webgpuSurface from "ext:deno_webgpu/02_surface.js";
|
||||||
import * as telemetry from "ext:deno_telemetry/telemetry.ts";
|
import * as telemetry from "ext:deno_telemetry/telemetry.ts";
|
||||||
|
|
||||||
const { ObjectDefineProperties } = primordials;
|
const { ObjectDefineProperties } = primordials;
|
||||||
|
@ -203,7 +203,7 @@ ObjectDefineProperties(denoNsUnstableById[unstableIds.net], {
|
||||||
// denoNsUnstableById[unstableIds.unsafeProto] = { __proto__: null }
|
// denoNsUnstableById[unstableIds.unsafeProto] = { __proto__: null }
|
||||||
|
|
||||||
denoNsUnstableById[unstableIds.webgpu] = {
|
denoNsUnstableById[unstableIds.webgpu] = {
|
||||||
UnsafeWindowSurface: webgpuSurface.UnsafeWindowSurface,
|
//UnsafeWindowSurface: webgpuSurface.UnsafeWindowSurface,
|
||||||
};
|
};
|
||||||
|
|
||||||
// denoNsUnstableById[unstableIds.workerOptions] = { __proto__: null }
|
// denoNsUnstableById[unstableIds.workerOptions] = { __proto__: null }
|
||||||
|
|
|
@ -35,7 +35,7 @@ import process from "node:process";
|
||||||
import { Buffer } from "node:buffer";
|
import { Buffer } from "node:buffer";
|
||||||
import { clearImmediate, setImmediate } from "node:timers";
|
import { clearImmediate, setImmediate } from "node:timers";
|
||||||
import { loadWebGPU } from "ext:deno_webgpu/00_init.js";
|
import { loadWebGPU } from "ext:deno_webgpu/00_init.js";
|
||||||
import * as webgpuSurface from "ext:deno_webgpu/02_surface.js";
|
//import * as webgpuSurface from "ext:deno_webgpu/02_surface.js";
|
||||||
import { unstableIds } from "ext:runtime/90_deno_ns.js";
|
import { unstableIds } from "ext:runtime/90_deno_ns.js";
|
||||||
|
|
||||||
const loadImage = core.createLazyLoader("ext:deno_canvas/01_image.js");
|
const loadImage = core.createLazyLoader("ext:deno_canvas/01_image.js");
|
||||||
|
@ -164,7 +164,7 @@ const windowOrWorkerGlobalScope = {
|
||||||
(webgpu) => webgpu.GPUBufferUsage,
|
(webgpu) => webgpu.GPUBufferUsage,
|
||||||
loadWebGPU,
|
loadWebGPU,
|
||||||
),
|
),
|
||||||
GPUCanvasContext: core.propNonEnumerable(webgpuSurface.GPUCanvasContext),
|
//GPUCanvasContext: core.propNonEnumerable(webgpuSurface.GPUCanvasContext),
|
||||||
GPUColorWrite: core.propNonEnumerableLazyLoaded(
|
GPUColorWrite: core.propNonEnumerableLazyLoaded(
|
||||||
(webgpu) => webgpu.GPUColorWrite,
|
(webgpu) => webgpu.GPUColorWrite,
|
||||||
loadWebGPU,
|
loadWebGPU,
|
||||||
|
|
|
@ -17,7 +17,6 @@ import * as console from "ext:deno_console/01_console.js";
|
||||||
import * as webidl from "ext:deno_webidl/00_webidl.js";
|
import * as webidl from "ext:deno_webidl/00_webidl.js";
|
||||||
import * as globalInterfaces from "ext:deno_web/04_global_interfaces.js";
|
import * as globalInterfaces from "ext:deno_web/04_global_interfaces.js";
|
||||||
import { loadWebGPU } from "ext:deno_webgpu/00_init.js";
|
import { loadWebGPU } from "ext:deno_webgpu/00_init.js";
|
||||||
import { initGPU } from "../../ext/webgpu/01_webgpu";
|
|
||||||
|
|
||||||
function memoizeLazy(f) {
|
function memoizeLazy(f) {
|
||||||
let v_ = null;
|
let v_ = null;
|
||||||
|
|
Loading…
Add table
Reference in a new issue