// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. use super::WebGpuResult; use deno_core::error::AnyError; use deno_core::include_js_files; use deno_core::op; use deno_core::Extension; use deno_core::OpState; use deno_core::Resource; use deno_core::ResourceId; use serde::Deserialize; use std::borrow::Cow; use wgpu_types::SurfaceStatus; pub fn init_surface(unstable: bool) -> Extension { Extension::builder("deno_webgpu_surface") .dependencies(vec!["deno_webidl", "deno_web", "deno_webgpu"]) .esm(include_js_files!( "03_surface.js", "04_surface_idl_types.js", )) .ops(vec![ op_webgpu_surface_configure::decl(), op_webgpu_surface_get_current_texture::decl(), op_webgpu_surface_present::decl(), ]) .state(move |state| { // TODO: check & possibly streamline this // Unstable might be able to be OpMiddleware // let unstable_checker = state.borrow::(); // let unstable = unstable_checker.unstable; state.put(super::Unstable(unstable)); }) .build() } pub struct WebGpuSurface(pub wgpu_core::id::SurfaceId); impl Resource for WebGpuSurface { fn name(&self) -> Cow { "webGPUSurface".into() } } #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub struct SurfaceConfigureArgs { surface_rid: ResourceId, device_rid: ResourceId, format: wgpu_types::TextureFormat, usage: u32, width: u32, height: u32, present_mode: Option, alpha_mode: wgpu_types::CompositeAlphaMode, view_formats: Vec, } #[op] pub fn op_webgpu_surface_configure( state: &mut OpState, args: SurfaceConfigureArgs, ) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table .get::(args.device_rid)?; let device = device_resource.0; let surface_resource = state .resource_table .get::(args.surface_rid)?; let surface = surface_resource.0; let conf = wgpu_types::SurfaceConfiguration::> { usage: wgpu_types::TextureUsages::from_bits_truncate(args.usage), format: args.format, width: args.width, height: args.height, present_mode: args.present_mode.unwrap_or_default(), alpha_mode: args.alpha_mode, view_formats: args.view_formats, }; let err = gfx_select!(device => instance.surface_configure(surface, device, &conf)); Ok(WebGpuResult::maybe_err(err)) } #[op] pub fn op_webgpu_surface_get_current_texture( state: &mut OpState, device_rid: ResourceId, surface_rid: ResourceId, ) -> Result { let instance = state.borrow::(); let device_resource = state .resource_table .get::(device_rid)?; let device = device_resource.0; let surface_resource = state.resource_table.get::(surface_rid)?; let surface = surface_resource.0; let output = gfx_select!(device => instance.surface_get_current_texture(surface, ()))?; match output.status { SurfaceStatus::Good | SurfaceStatus::Suboptimal => { let id = output.texture_id.unwrap(); let rid = state.resource_table.add(crate::texture::WebGpuTexture(id)); Ok(WebGpuResult::rid(rid)) } _ => Err(AnyError::msg("Invalid Surface Status")), } } #[op] pub fn op_webgpu_surface_present( state: &mut OpState, device_rid: ResourceId, surface_rid: ResourceId, ) -> Result<(), AnyError> { let instance = state.borrow::(); let device_resource = state .resource_table .get::(device_rid)?; let device = device_resource.0; let surface_resource = state.resource_table.get::(surface_rid)?; let surface = surface_resource.0; let _ = gfx_select!(device => instance.surface_present(surface))?; Ok(()) }