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}