web/web_gpu/
mod.rs

1use crate::{add_to_array, console_error, create_array, EventHandlerFuture};
2use js::*;
3
4pub struct WebGPU;
5
6#[no_mangle]
7pub extern "C" fn web_extern_ref_callback(id: i64, value: i64) {
8    EventHandlerFuture::<ExternRef>::wake_future_with_state_id(id, ExternRef { value });
9}
10
11impl WebGPU {
12    pub fn is_available() -> bool {
13        js!(r#"
14        function(element){
15            return (typeof navigator !== "undefined" && navigator.gpu);
16        }"#)
17        .invoke_and_return_bool(&[])
18    }
19
20    pub async fn request_adapter() -> GPUAdapter {
21        let (future, state_id) = EventHandlerFuture::<ExternRef>::create_future_with_state_id();
22        js!(r#"
23            async function(state_id){
24                const a = await navigator.gpu.requestAdapter();
25                const ref = this.storeObject(a);
26                this.module.instance.exports.web_extern_ref_callback(state_id, ref);
27            }"#)
28        .invoke(&[state_id.into()]);
29        let adapter_ref = future.await;
30        GPUAdapter(adapter_ref)
31    }
32
33    pub fn get_preferred_canvas_format() -> GPUTextureFormat {
34        let f = js!(r#"
35            function(){
36                return navigator.gpu.getPreferredCanvasFormat();
37            }"#)
38        .invoke_and_return_string(&[]);
39        GPUTextureFormat::from_str(&f).unwrap()
40    }
41}
42
43pub struct GPUAdapter(ExternRef);
44
45impl GPUAdapter {
46    pub async fn request_device(&self) -> GPUDevice {
47        let (future, state_id) = EventHandlerFuture::<ExternRef>::create_future_with_state_id();
48        js!(r#"
49            async function(adapter, state_id){
50                const d = await adapter.requestDevice();
51                const ref = this.storeObject(d);
52                this.module.instance.exports.web_extern_ref_callback(state_id, ref);
53            }"#)
54        .invoke(&[(&(self.0)).into(), state_id.into()]);
55        let device_ref = future.await;
56        GPUDevice(device_ref)
57    }
58}
59
60pub struct GPUDevice(ExternRef);
61pub struct GPUShaderModule(ExternRef);
62pub struct GPUPipelineLayout(ExternRef);
63pub struct GPUQueue(ExternRef);
64pub struct GPUCommandEncoder(ExternRef);
65pub struct GPURenderPipeline(ExternRef);
66
67impl GPUQueue {
68    pub fn submit(&self, command_buffers: &[GPUCommandBuffer]) {
69        let command_buffers_ref = create_array();
70        command_buffers.iter().for_each(|command_buffer| {
71            add_to_array(&command_buffers_ref, &command_buffer.0);
72        });
73        let submit = js!(r#"
74            function(queue, commandBuffers){
75                queue.submit(commandBuffers);
76            }"#);
77        submit.invoke(&[(&(self.0)).into(), (&command_buffers_ref).into()]);
78    }
79}
80
81impl GPUDevice {
82    pub fn create_buffer(&self, descriptor: &GPUBufferDescriptor) -> GPUBuffer {
83        let create_buffer = js!(r#"
84            function(device, size, usage, mappedAtCreation){
85                return device.createBuffer({
86                    size,
87                    usage,
88                    mappedAtCreation
89                });
90            }"#);
91        let buffer_ref = create_buffer.invoke_and_return_object(&[
92            (&(self.0)).into(),
93            (descriptor.size).into(),
94            (descriptor.usage).into(),
95            (descriptor.mapped_at_creation).into(),
96        ]);
97        GPUBuffer(buffer_ref)
98    }
99
100    pub fn create_shader_module_from_source(&self, source: &str) -> GPUShaderModule {
101        let create_shader_module = js!(r#"
102            function(device, source){
103                return device.createShaderModule({code: source});
104            }"#);
105        let shader_module_ref =
106            create_shader_module.invoke_and_return_object(&[(&(self.0)).into(), source.into()]);
107        GPUShaderModule(shader_module_ref)
108    }
109
110    pub fn create_pipeline_layout(
111        &self,
112        descriptor: &GPUPipelineLayoutDescriptor,
113    ) -> GPUPipelineLayout {
114        let create_pipeline_layout = js!(r#"
115            function(device, bindGroupLayouts){
116                return device.createPipelineLayout({
117                    bindGroupLayouts:[]
118                });
119            }"#);
120        if descriptor.bind_group_layouts.len() > 0 {
121            console_error("bind_group_layouts not supported yet");
122            panic!("bind_group_layouts not supported yet");
123        }
124        let pipeline_layout_ref =
125            create_pipeline_layout.invoke_and_return_object(&[(&(self.0)).into()]);
126        GPUPipelineLayout(pipeline_layout_ref)
127    }
128
129    pub fn get_queue(&self) -> GPUQueue {
130        let get_queue = js!(r#"
131            function(device){
132                return device.queue;
133            }"#);
134        let queue_ref = get_queue.invoke_and_return_object(&[(&(self.0)).into()]);
135        GPUQueue(queue_ref)
136    }
137
138    pub fn create_command_encoder(&self) -> GPUCommandEncoder {
139        let create_command_encoder = js!(r#"
140            function(device){
141                return device.createCommandEncoder();
142            }"#);
143        let command_encoder_ref =
144            create_command_encoder.invoke_and_return_object(&[(&(self.0)).into()]);
145        GPUCommandEncoder(command_encoder_ref)
146    }
147
148    pub fn create_render_pipeline(
149        &self,
150        descriptor: &GPURenderPipelineDescriptor,
151    ) -> GPURenderPipeline {
152        let fragment_state_ref = {
153            let fragment_state = &descriptor.fragment;
154            let targets_ref = create_array();
155            descriptor.fragment.targets.iter().for_each(|target| {
156                let format = target.format;
157                let target_ref = js!(r#"
158                function(format){
159                    return {
160                        format
161                    };
162                }"#)
163                .invoke_and_return_object(&[format.as_str().into()]);
164                add_to_array(&targets_ref, &target_ref);
165            });
166
167            js!(r#"
168                function(module, entryPoint, targets){
169                    return {
170                        module,
171                        entryPoint,
172                        targets
173                    };
174                }"#)
175            .invoke_and_return_object(&[
176                (&(fragment_state.module.0)).into(),
177                fragment_state.entry_point.into(),
178                (&targets_ref).into(),
179            ])
180        };
181        let vertex_state_ref = {
182            let vertex_state = &descriptor.vertex;
183            let vertex_buffers_ref = create_array();
184            vertex_state.buffers.iter().for_each(|buffer| {
185                let attributes_ref = create_array();
186                buffer.attributes.iter().for_each(|attribute| {
187                    let attribute_ref = js!(r#"
188                    function(shaderLocation, offset, format){
189                        return {
190                            shaderLocation,
191                            offset,
192                            format
193                        };
194                    }"#)
195                    .invoke_and_return_object(&[
196                        attribute.shader_location.into(),
197                        attribute.offset.into(),
198                        attribute.format.as_str().into(),
199                    ]);
200                    add_to_array(&attributes_ref, &attribute_ref);
201                });
202                let buffer_ref = js!(r#"
203                    function(arrayStride, stepMode, attributes){
204                        return {
205                            arrayStride,
206                            stepMode,
207                            attributes
208                        };
209                    }"#)
210                .invoke_and_return_object(&[
211                    buffer.array_stride.into(),
212                    buffer.step_mode.as_str().into(),
213                    (&attributes_ref).into(),
214                ]);
215                add_to_array(&vertex_buffers_ref, &buffer_ref);
216            });
217            js!(r#"
218                function(module, entryPoint, buffers){
219                    return {
220                        module,
221                        entryPoint,
222                        buffers
223                    };
224                }"#)
225            .invoke_and_return_object(&[
226                (&(vertex_state.module.0)).into(),
227                vertex_state.entry_point.into(),
228                (&vertex_buffers_ref).into(),
229            ])
230        };
231        let primitive_state_ref = js!(r#"
232            function(topology, cullMode, frontFace){
233                return {
234                    topology,
235                    cullMode,
236                    frontFace
237                };
238            }"#)
239        .invoke_and_return_object(&[
240            descriptor.primitive.topology.as_str().into(),
241            descriptor.primitive.cull_mode.as_str().into(),
242            descriptor.primitive.front_face.as_str().into(),
243        ]);
244
245        let pipeline_ref = js!(r#"
246            function(device, layout, fragment, vertex, primitive){
247                let config = {
248                    layout,
249                    fragment,
250                    vertex,
251                    primitive
252                };
253                return device.createRenderPipeline(config);
254            }"#)
255        .invoke_and_return_object(&[
256            (&(self.0)).into(),
257            (&(descriptor.layout.0)).into(),
258            (&fragment_state_ref).into(),
259            (&vertex_state_ref).into(),
260            (&primitive_state_ref).into(),
261        ]);
262        GPURenderPipeline(pipeline_ref)
263    }
264}
265
266pub struct GPUCanvasContext(ExternRef);
267pub struct GPUTexture(ExternRef);
268
269impl GPUTexture {
270    pub fn create_view(&self) -> GPUTextureView {
271        let create_view = js!(r#"
272            function(texture){
273                return texture.createView();
274            }"#);
275        let view_ref = create_view.invoke_and_return_object(&[(&(self.0)).into()]);
276        GPUTextureView(view_ref)
277    }
278}
279
280pub struct GPUTextureView(ExternRef);
281
282impl GPUCanvasContext {
283    pub fn from_element(element: &ExternRef) -> Self {
284        let get_context = js!(r#"
285            function(element){
286                return element.getContext("webgpu");
287            }"#);
288        let ctx_ref = get_context.invoke_and_return_object(&[element.into()]);
289        GPUCanvasContext(ctx_ref)
290    }
291
292    pub fn configure(&self, config: &GpuCanvasConfiguration) {
293        js!(r#"
294            function(ctx, device, format, alphaMode){
295                ctx.configure({
296                    device: device,
297                    format: format,
298                    alphaMode: alphaMode,
299                });
300            }"#)
301        .invoke(&[
302            (&(self.0)).into(),
303            (&(config.device.0)).into(),
304            config.format.as_str().into(),
305            config.alpha_mode.as_str().into(),
306        ]);
307    }
308
309    pub fn get_current_texture(&self) -> GPUTexture {
310        let texture_ref = js!(r#"
311            function(ctx){
312                return ctx.getCurrentTexture();
313            }"#)
314        .invoke_and_return_object(&[(&(self.0)).into()]);
315        GPUTexture(texture_ref)
316    }
317}
318
319pub struct GpuCanvasConfiguration<'a> {
320    pub device: &'a GPUDevice,
321    pub format: GPUTextureFormat,
322    pub alpha_mode: GPUCanvasAlphaMode,
323}
324
325#[derive(Clone, Copy)]
326pub enum GPUCanvasAlphaMode {
327    Premultiplied,
328    Opaque,
329}
330
331impl GPUCanvasAlphaMode {
332    fn as_str(&self) -> &'static str {
333        match self {
334            GPUCanvasAlphaMode::Premultiplied => "premultiplied",
335            GPUCanvasAlphaMode::Opaque => "opaque",
336        }
337    }
338}
339
340pub struct GPUBufferDescriptor {
341    pub size: usize,
342    pub usage: usize,
343    pub mapped_at_creation: bool,
344}
345
346pub const GPU_BUFFER_USAGE_MAP_READ: usize = 0x0001;
347pub const GPU_BUFFER_USAGE_MAP_WRITE: usize = 0x0002;
348pub const GPU_BUFFER_USAGE_COPY_SRC: usize = 0x0004;
349pub const GPU_BUFFER_USAGE_COPY_DST: usize = 0x0008;
350pub const GPU_BUFFER_USAGE_INDEX: usize = 0x0010;
351pub const GPU_BUFFER_USAGE_VERTEX: usize = 0x0020;
352pub const GPU_BUFFER_USAGE_UNIFORM: usize = 0x0040;
353pub const GPU_BUFFER_USAGE_STORAGE: usize = 0x0080;
354pub const GPU_BUFFER_USAGE_INDIRECT: usize = 0x0100;
355pub const GPU_BUFFER_USAGE_QUERY_RESOLVE: usize = 0x0200;
356
357pub struct GPUBuffer(ExternRef);
358
359impl GPUBuffer {
360    pub fn set_from_f32_array(&self, data: &[f32]) {
361        js!(r#"
362            function(buffer, data){
363                new Float32Array(buffer.getMappedRange()).set(data);
364            }"#)
365        .invoke(&[(&(self.0)).into(), data.into()]);
366    }
367
368    pub fn set_from_u32_array(&self, data: &[u32]) {
369        js!(r#"
370            function(buffer, data){
371                new Uint32Array(buffer.getMappedRange()).set(data);
372            }"#)
373        .invoke(&[(&(self.0)).into(), data.into()]);
374    }
375
376    pub fn unmap(&self) {
377        js!(r#"
378            function(buffer){
379                buffer.unmap();
380            }"#)
381        .invoke(&[(&(self.0)).into()]);
382    }
383}
384
385pub struct BindGroupLayout;
386pub struct GPUPipelineLayoutDescriptor {
387    pub bind_group_layouts: Vec<BindGroupLayout>,
388}
389
390#[derive(Clone, Copy)]
391pub enum GPUTextureFormat {
392    BGRA8Unorm,
393}
394
395impl GPUTextureFormat {
396    pub fn as_str(&self) -> &'static str {
397        match self {
398            GPUTextureFormat::BGRA8Unorm => "bgra8unorm",
399        }
400    }
401
402    pub fn from_str(s: &str) -> Option<GPUTextureFormat> {
403        match s {
404            "bgra8unorm" => Some(GPUTextureFormat::BGRA8Unorm),
405            _ => None,
406        }
407    }
408}
409
410pub struct GPUColorTargetState {
411    pub format: GPUTextureFormat,
412}
413
414pub struct GPUFragmentState<'a> {
415    pub module: &'a GPUShaderModule,
416    pub entry_point: &'a str,
417    pub targets: Vec<GPUColorTargetState>,
418}
419
420#[derive(Clone, Copy)]
421pub enum GPUPrimitiveTopology {
422    PointList,
423    LineList,
424    LineStrip,
425    TriangleList,
426    TriangleStrip,
427}
428
429impl GPUPrimitiveTopology {
430    pub fn as_str(&self) -> &'static str {
431        match self {
432            GPUPrimitiveTopology::PointList => "point-list",
433            GPUPrimitiveTopology::LineList => "line-list",
434            GPUPrimitiveTopology::LineStrip => "line-strip",
435            GPUPrimitiveTopology::TriangleList => "triangle-list",
436            GPUPrimitiveTopology::TriangleStrip => "triangle-strip",
437        }
438    }
439}
440
441#[derive(Clone, Copy)]
442pub enum GPUCullMode {
443    None,
444    Front,
445    Back,
446}
447
448impl GPUCullMode {
449    pub fn as_str(&self) -> &'static str {
450        match self {
451            GPUCullMode::None => "none",
452            GPUCullMode::Front => "front",
453            GPUCullMode::Back => "back",
454        }
455    }
456}
457
458#[derive(Clone, Copy)]
459pub enum GPUFrontFace {
460    CCW,
461    CW,
462}
463
464impl GPUFrontFace {
465    pub fn as_str(&self) -> &'static str {
466        match self {
467            GPUFrontFace::CCW => "ccw",
468            GPUFrontFace::CW => "cw",
469        }
470    }
471}
472
473pub struct GPUPrimitiveState {
474    pub topology: GPUPrimitiveTopology,
475    pub cull_mode: GPUCullMode,
476    pub front_face: GPUFrontFace,
477}
478
479pub struct GPURenderPipelineDescriptor<'a> {
480    pub layout: &'a GPUPipelineLayout,
481    pub primitive: GPUPrimitiveState,
482    pub vertex: GPUVertexState<'a>,
483    pub fragment: GPUFragmentState<'a>,
484}
485
486pub struct GPUVertexAttribute {
487    pub format: GPUVertexFormat,
488    pub offset: usize,
489    pub shader_location: usize,
490}
491
492#[derive(Clone, Copy)]
493pub enum GPUVertexFormat {
494    Uint8x2,
495    Uint8x4,
496    Sint8x2,
497    Sint8x4,
498    Unorm8x2,
499    Unorm8x4,
500    Snorm8x2,
501    Snorm8x4,
502    Uint16x2,
503    Uint16x4,
504    Sint16x2,
505    Sint16x4,
506    Unorm16x2,
507    Unorm16x4,
508    Snorm16x2,
509    Snorm16x4,
510    Float16x2,
511    Float16x4,
512    Float32,
513    Float32x2,
514    Float32x3,
515    Float32x4,
516    Uint32,
517    Uint32x2,
518    Uint32x3,
519    Uint32x4,
520    Sint32,
521    Sint32x2,
522    Sint32x3,
523    Sint32x4,
524}
525
526impl GPUVertexFormat {
527    pub fn as_str(&self) -> &'static str {
528        match self {
529            GPUVertexFormat::Uint8x2 => "uint8x2",
530            GPUVertexFormat::Uint8x4 => "uint8x4",
531            GPUVertexFormat::Sint8x2 => "sint8x2",
532            GPUVertexFormat::Sint8x4 => "sint8x4",
533            GPUVertexFormat::Unorm8x2 => "unorm8x2",
534            GPUVertexFormat::Unorm8x4 => "unorm8x4",
535            GPUVertexFormat::Snorm8x2 => "snorm8x2",
536            GPUVertexFormat::Snorm8x4 => "snorm8x4",
537            GPUVertexFormat::Uint16x2 => "uint16x2",
538            GPUVertexFormat::Uint16x4 => "uint16x4",
539            GPUVertexFormat::Sint16x2 => "sint16x2",
540            GPUVertexFormat::Sint16x4 => "sint16x4",
541            GPUVertexFormat::Unorm16x2 => "unorm16x2",
542            GPUVertexFormat::Unorm16x4 => "unorm16x4",
543            GPUVertexFormat::Snorm16x2 => "snorm16x2",
544            GPUVertexFormat::Snorm16x4 => "snorm16x4",
545            GPUVertexFormat::Float16x2 => "float16x2",
546            GPUVertexFormat::Float16x4 => "float16x4",
547            GPUVertexFormat::Float32 => "float32",
548            GPUVertexFormat::Float32x2 => "float32x2",
549            GPUVertexFormat::Float32x3 => "float32x3",
550            GPUVertexFormat::Float32x4 => "float32x4",
551            GPUVertexFormat::Uint32 => "uint32",
552            GPUVertexFormat::Uint32x2 => "uint32x2",
553            GPUVertexFormat::Uint32x3 => "uint32x3",
554            GPUVertexFormat::Uint32x4 => "uint32x4",
555            GPUVertexFormat::Sint32 => "sint32",
556            GPUVertexFormat::Sint32x2 => "sint32x2",
557            GPUVertexFormat::Sint32x3 => "sint32x3",
558            GPUVertexFormat::Sint32x4 => "sint32x4",
559        }
560    }
561}
562
563#[derive(Clone, Copy)]
564pub enum GPUVertexStepMode {
565    Vertex,
566    Instance,
567}
568
569impl GPUVertexStepMode {
570    pub fn as_str(&self) -> &'static str {
571        match self {
572            GPUVertexStepMode::Vertex => "vertex",
573            GPUVertexStepMode::Instance => "instance",
574        }
575    }
576}
577
578pub struct GPUVertexBufferLayout {
579    pub array_stride: usize,
580    pub step_mode: GPUInputStepMode,
581    pub attributes: Vec<GPUVertexAttribute>,
582}
583
584pub struct GPUVertexState<'a> {
585    pub module: &'a GPUShaderModule,
586    pub entry_point: &'a str,
587    pub buffers: Vec<GPUVertexBufferLayout>,
588}
589
590#[derive(Clone, Copy)]
591pub enum GPUInputStepMode {
592    Vertex,
593    Instance,
594}
595
596impl GPUInputStepMode {
597    pub fn as_str(&self) -> &'static str {
598        match self {
599            GPUInputStepMode::Vertex => "vertex",
600            GPUInputStepMode::Instance => "instance",
601        }
602    }
603}
604
605pub struct GPURenderPassDescriptor<'a> {
606    pub color_attachments: Vec<GPURenderPassColorAttachment<'a>>,
607}
608
609pub struct GPUColor {
610    pub r: f64,
611    pub g: f64,
612    pub b: f64,
613    pub a: f64,
614}
615
616#[derive(Clone, Copy)]
617pub enum GPULoadOp {
618    Load,
619    Clear,
620}
621
622impl GPULoadOp {
623    pub fn as_str(&self) -> &'static str {
624        match self {
625            GPULoadOp::Load => "load",
626            GPULoadOp::Clear => "clear",
627        }
628    }
629}
630
631#[derive(Clone, Copy)]
632pub enum GPUStoreOp {
633    Store,
634    Discard,
635}
636
637impl GPUStoreOp {
638    pub fn as_str(&self) -> &'static str {
639        match self {
640            GPUStoreOp::Store => "store",
641            GPUStoreOp::Discard => "discard",
642        }
643    }
644}
645
646pub struct GPURenderPassColorAttachment<'a> {
647    pub view: &'a GPUTextureView,
648    pub load_op: GPULoadOp,
649    pub store_op: GPUStoreOp,
650    pub clear_value: GPUColor,
651}
652
653pub struct GPURenderPass(ExternRef);
654
655impl GPUCommandEncoder {
656    pub fn begin_render_pass(&self, descriptor: &GPURenderPassDescriptor) -> GPURenderPass {
657        let color_attachments_ref = create_array();
658        for attachment in &descriptor.color_attachments {
659            let clear_value = js!(r#"
660            function(r, g, b, a){
661                return {r, g, b, a};
662            }
663            "#)
664            .invoke_and_return_object(&[
665                attachment.clear_value.r.into(),
666                attachment.clear_value.g.into(),
667                attachment.clear_value.b.into(),
668                attachment.clear_value.a.into(),
669            ]);
670            let attachment_ref = js!(r#"
671                function(view, loadOp, storeOp, clearValue){
672                    return {
673                        view,
674                        loadOp,
675                        storeOp,
676                        clearValue
677                    };
678                }
679                "#)
680            .invoke_and_return_object(&[
681                (&attachment.view.0).into(),
682                attachment.load_op.as_str().into(),
683                attachment.store_op.as_str().into(),
684                (&clear_value).into(),
685            ]);
686            add_to_array(&color_attachments_ref, &attachment_ref);
687        }
688
689        let render_pass_ref = js!(r#"
690        function(encoder, colorAttachments){
691            return encoder.beginRenderPass({
692                colorAttachments
693            });
694        }
695        "#)
696        .invoke_and_return_object(&[(&self.0).into(), (&color_attachments_ref).into()]);
697        GPURenderPass(render_pass_ref)
698    }
699
700    pub fn finish(&self) -> GPUCommandBuffer {
701        let command_buffer_ref = js!(r#"
702        function(encoder){
703            return encoder.finish();
704        }
705        "#)
706        .invoke_and_return_object(&[(&self.0).into()])
707        .into();
708        GPUCommandBuffer(command_buffer_ref)
709    }
710}
711
712pub struct GPUCommandBuffer(ExternRef);
713
714impl GPURenderPass {
715    pub fn set_pipeline(&self, pipeline: &GPURenderPipeline) {
716        js!(r#"
717        function(encoder, pipeline){
718            encoder.setPipeline(pipeline);
719        }
720        "#)
721        .invoke(&[(&self.0).into(), (&pipeline.0).into()]);
722    }
723
724    pub fn set_viewport(
725        &self,
726        x: f64,
727        y: f64,
728        width: f64,
729        height: f64,
730        min_depth: f64,
731        max_depth: f64,
732    ) {
733        js!(r#"
734        function(encoder, x, y, width, height, minDepth, maxDepth){
735            encoder.setViewport(x, y, width, height, minDepth, maxDepth);
736        }
737        "#)
738        .invoke(&[
739            (&self.0).into(),
740            x.into(),
741            y.into(),
742            width.into(),
743            height.into(),
744            min_depth.into(),
745            max_depth.into(),
746        ]);
747    }
748
749    pub fn set_scissor_rect(&self, x: f64, y: f64, width: f64, height: f64) {
750        js!(r#"
751        function(encoder, x, y, width, height){
752            encoder.setScissorRect(x, y, width, height);
753        }
754        "#)
755        .invoke(&[
756            (&self.0).into(),
757            x.into(),
758            y.into(),
759            width.into(),
760            height.into(),
761        ]);
762    }
763
764    pub fn set_vertex_buffer(&self, slot: usize, buffer: &GPUBuffer) {
765        js!(r#"
766        function(encoder, slot, buffer){
767            encoder.setVertexBuffer(slot, buffer);
768        }
769        "#)
770        .invoke(&[(&self.0).into(), slot.into(), (&buffer.0).into()]);
771    }
772
773    pub fn set_index_buffer(&self, buffer: &GPUBuffer, index_format: &str) {
774        js!(r#"
775        function(encoder, buffer, indexFormat){
776            encoder.setIndexBuffer(buffer, indexFormat);
777        }
778        "#)
779        .invoke(&[(&self.0).into(), (&buffer.0).into(), index_format.into()]);
780    }
781
782    pub fn draw_indexed(&self, index_count: usize) {
783        js!(r#"
784        function(encoder, indexCount){
785            encoder.drawIndexed(indexCount);
786        }
787        "#)
788        .invoke(&[(&self.0).into(), index_count.into()]);
789    }
790
791    pub fn end(&self) {
792        js!(r#"
793        function(encoder){
794            encoder.end();
795        }
796        "#)
797        .invoke(&[(&self.0).into()]);
798    }
799}