1use dom_struct::dom_struct;
6use webgpu_traits::{RenderCommand, WebGPU, WebGPURenderPass, WebGPURequest};
7
8use crate::conversions::TryConvert;
9use crate::dom::bindings::cell::DomRefCell;
10use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
11 GPUColor, GPUIndexFormat, GPURenderPassEncoderMethods,
12};
13use crate::dom::bindings::error::Fallible;
14use crate::dom::bindings::num::Finite;
15use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
16use crate::dom::bindings::root::{Dom, DomRoot};
17use crate::dom::bindings::str::USVString;
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::webgpu::gpubindgroup::GPUBindGroup;
20use crate::dom::webgpu::gpubuffer::GPUBuffer;
21use crate::dom::webgpu::gpucommandencoder::GPUCommandEncoder;
22use crate::dom::webgpu::gpurenderbundle::GPURenderBundle;
23use crate::dom::webgpu::gpurenderpipeline::GPURenderPipeline;
24use crate::script_runtime::CanGc;
25
26#[dom_struct]
27pub(crate) struct GPURenderPassEncoder {
28 reflector_: Reflector,
29 #[no_trace]
30 channel: WebGPU,
31 label: DomRefCell<USVString>,
32 #[no_trace]
33 render_pass: WebGPURenderPass,
34 command_encoder: Dom<GPUCommandEncoder>,
35}
36
37impl GPURenderPassEncoder {
38 fn new_inherited(
39 channel: WebGPU,
40 render_pass: WebGPURenderPass,
41 parent: &GPUCommandEncoder,
42 label: USVString,
43 ) -> Self {
44 Self {
45 channel,
46 reflector_: Reflector::new(),
47 label: DomRefCell::new(label),
48 render_pass,
49 command_encoder: Dom::from_ref(parent),
50 }
51 }
52
53 pub(crate) fn new(
54 global: &GlobalScope,
55 channel: WebGPU,
56 render_pass: WebGPURenderPass,
57 parent: &GPUCommandEncoder,
58 label: USVString,
59 can_gc: CanGc,
60 ) -> DomRoot<Self> {
61 reflect_dom_object(
62 Box::new(GPURenderPassEncoder::new_inherited(
63 channel,
64 render_pass,
65 parent,
66 label,
67 )),
68 global,
69 can_gc,
70 )
71 }
72
73 fn send_render_command(&self, render_command: RenderCommand) {
74 if let Err(e) = self.channel.0.send(WebGPURequest::RenderPassCommand {
75 render_pass_id: self.render_pass.0,
76 render_command,
77 device_id: self.command_encoder.device_id().0,
78 }) {
79 warn!("Error sending WebGPURequest::RenderPassCommand: {e:?}")
80 }
81 }
82}
83
84impl GPURenderPassEncoderMethods<crate::DomTypeHolder> for GPURenderPassEncoder {
85 fn Label(&self) -> USVString {
87 self.label.borrow().clone()
88 }
89
90 fn SetLabel(&self, value: USVString) {
92 *self.label.borrow_mut() = value;
93 }
94
95 fn SetBindGroup(&self, index: u32, bind_group: &GPUBindGroup, offsets: Vec<u32>) {
97 self.send_render_command(RenderCommand::SetBindGroup {
98 index,
99 bind_group_id: bind_group.id().0,
100 offsets,
101 })
102 }
103
104 fn SetViewport(
106 &self,
107 x: Finite<f32>,
108 y: Finite<f32>,
109 width: Finite<f32>,
110 height: Finite<f32>,
111 min_depth: Finite<f32>,
112 max_depth: Finite<f32>,
113 ) {
114 self.send_render_command(RenderCommand::SetViewport {
115 x: *x,
116 y: *y,
117 width: *width,
118 height: *height,
119 min_depth: *min_depth,
120 max_depth: *max_depth,
121 })
122 }
123
124 fn SetScissorRect(&self, x: u32, y: u32, width: u32, height: u32) {
126 self.send_render_command(RenderCommand::SetScissorRect {
127 x,
128 y,
129 width,
130 height,
131 })
132 }
133
134 fn SetBlendConstant(&self, color: GPUColor) -> Fallible<()> {
136 self.send_render_command(RenderCommand::SetBlendConstant((&color).try_convert()?));
137 Ok(())
138 }
139
140 fn SetStencilReference(&self, reference: u32) {
142 self.send_render_command(RenderCommand::SetStencilReference(reference))
143 }
144
145 fn End(&self) {
147 if let Err(e) = self.channel.0.send(WebGPURequest::EndRenderPass {
148 render_pass_id: self.render_pass.0,
149 device_id: self.command_encoder.device_id().0,
150 command_encoder_id: self.command_encoder.id().0,
151 }) {
152 warn!("Failed to send WebGPURequest::EndRenderPass: {e:?}");
153 }
154 }
155
156 fn SetPipeline(&self, pipeline: &GPURenderPipeline) {
158 self.send_render_command(RenderCommand::SetPipeline(pipeline.id().0))
159 }
160
161 fn SetIndexBuffer(
163 &self,
164 buffer: &GPUBuffer,
165 index_format: GPUIndexFormat,
166 offset: u64,
167 size: u64,
168 ) {
169 self.send_render_command(RenderCommand::SetIndexBuffer {
170 buffer_id: buffer.id().0,
171 index_format: match index_format {
172 GPUIndexFormat::Uint16 => wgpu_types::IndexFormat::Uint16,
173 GPUIndexFormat::Uint32 => wgpu_types::IndexFormat::Uint32,
174 },
175 offset,
176 size: wgpu_types::BufferSize::new(size),
177 })
178 }
179
180 fn SetVertexBuffer(&self, slot: u32, buffer: &GPUBuffer, offset: u64, size: u64) {
182 self.send_render_command(RenderCommand::SetVertexBuffer {
183 slot,
184 buffer_id: buffer.id().0,
185 offset,
186 size: wgpu_types::BufferSize::new(size),
187 })
188 }
189
190 fn Draw(&self, vertex_count: u32, instance_count: u32, first_vertex: u32, first_instance: u32) {
192 self.send_render_command(RenderCommand::Draw {
193 vertex_count,
194 instance_count,
195 first_vertex,
196 first_instance,
197 })
198 }
199
200 fn DrawIndexed(
202 &self,
203 index_count: u32,
204 instance_count: u32,
205 first_index: u32,
206 base_vertex: i32,
207 first_instance: u32,
208 ) {
209 self.send_render_command(RenderCommand::DrawIndexed {
210 index_count,
211 instance_count,
212 first_index,
213 base_vertex,
214 first_instance,
215 })
216 }
217
218 fn DrawIndirect(&self, buffer: &GPUBuffer, offset: u64) {
220 self.send_render_command(RenderCommand::DrawIndirect {
221 buffer_id: buffer.id().0,
222 offset,
223 })
224 }
225
226 fn DrawIndexedIndirect(&self, buffer: &GPUBuffer, offset: u64) {
228 self.send_render_command(RenderCommand::DrawIndexedIndirect {
229 buffer_id: buffer.id().0,
230 offset,
231 })
232 }
233
234 fn ExecuteBundles(&self, bundles: Vec<DomRoot<GPURenderBundle>>) {
236 let bundle_ids: Vec<_> = bundles.iter().map(|b| b.id().0).collect();
237 self.send_render_command(RenderCommand::ExecuteBundles(bundle_ids))
238 }
239}
240
241impl Drop for GPURenderPassEncoder {
242 fn drop(&mut self) {
243 if let Err(e) = self
244 .channel
245 .0
246 .send(WebGPURequest::DropRenderPass(self.render_pass.0))
247 {
248 warn!("Failed to send WebGPURequest::DropRenderPass with {e:?}");
249 }
250 }
251}