usesuper::{conv::is_layered_target, Command as C, PrivateCapabilities}; use arrayvec::ArrayVec; use glow::HasContext; use std::{
mem::size_of,
slice,
sync::{atomic::Ordering, Arc},
};
const DEBUG_ID: u32 = 0;
fn extract_marker<'a>(data: &'a [u8], range: &std::ops::Range<u32>) -> &'a str {
std::str::from_utf8(&data[range.start as usize..range.end as usize]).unwrap()
}
implsuper::Queue { /// Performs a manual shader clear, used as a workaround for a clearing bug on mesa unsafefn perform_shader_clear(&self, gl: &glow::Context, draw_buffer: u32, color: [f32; 4]) { let shader_clear = self
.shader_clear_program
.as_ref()
.expect("shader_clear_program should always be set if the workaround is enabled"); unsafe { gl.use_program(Some(shader_clear.program)) }; unsafe {
gl.uniform_4_f32(
Some(&shader_clear.color_uniform_location),
color[0],
color[1],
color[2],
color[3],
)
}; unsafe { gl.disable(glow::DEPTH_TEST) }; unsafe { gl.disable(glow::STENCIL_TEST) }; unsafe { gl.disable(glow::SCISSOR_TEST) }; unsafe { gl.disable(glow::BLEND) }; unsafe { gl.disable(glow::CULL_FACE) }; unsafe { gl.draw_buffers(&[glow::COLOR_ATTACHMENT0 + draw_buffer]) }; unsafe { gl.draw_arrays(glow::TRIANGLES, 0, 3) };
let draw_buffer_count = self.draw_buffer_count.load(Ordering::Relaxed); if draw_buffer_count != 0 { // Reset the draw buffers to what they were before the clear let indices = (0..draw_buffer_count as u32)
.map(|i| glow::COLOR_ATTACHMENT0 + i)
.collect::<ArrayVec<_, { crate::MAX_COLOR_ATTACHMENTS }>>(); unsafe { gl.draw_buffers(&indices) };
}
}
if supports_full_instancing { unsafe {
gl.draw_arrays_instanced_base_instance(
topology,
first_vertex as i32,
vertex_count as i32,
instance_count as i32,
first_instance,
)
}
} else { unsafe {
gl.uniform_1_u32(first_instance_location.as_ref(), first_instance);
}
// Don't use `gl.draw_arrays` for `instance_count == 1`. // Angle has a bug where it doesn't consider the instance divisor when `DYNAMIC_DRAW` is used in `draw_arrays`. // See https://github.com/gfx-rs/wgpu/issues/3578 unsafe {
gl.draw_arrays_instanced(
topology,
first_vertex as i32,
vertex_count as i32,
instance_count as i32,
)
}
};
}
C::DrawIndexed {
topology,
index_type,
index_count,
index_offset,
base_vertex,
first_instance,
instance_count, ref first_instance_location,
} => { let supports_full_instancing = self
.shared
.private_caps
.contains(PrivateCapabilities::FULLY_FEATURED_INSTANCING);
if supports_full_instancing { unsafe {
gl.draw_elements_instanced_base_vertex_base_instance(
topology,
index_count as i32,
index_type,
index_offset as i32,
instance_count as i32,
base_vertex,
first_instance,
)
}
} else { unsafe { gl.uniform_1_u32(first_instance_location.as_ref(), first_instance) };
if base_vertex == 0 { unsafe { // Don't use `gl.draw_elements`/`gl.draw_elements_base_vertex` for `instance_count == 1`. // Angle has a bug where it doesn't consider the instance divisor when `DYNAMIC_DRAW` is used in `gl.draw_elements`/`gl.draw_elements_base_vertex`. // See https://github.com/gfx-rs/wgpu/issues/3578
gl.draw_elements_instanced(
topology,
index_count as i32,
index_type,
index_offset as i32,
instance_count as i32,
)
}
} else { // If we've gotten here, wgpu-core has already validated that this function exists via the DownlevelFlags::BASE_VERTEX feature. unsafe {
gl.draw_elements_instanced_base_vertex(
topology,
index_count as _,
index_type,
index_offset as i32,
instance_count as i32,
base_vertex,
)
}
}
}
}
C::DrawIndirect {
topology,
indirect_buf,
indirect_offset, ref first_instance_location,
} => { unsafe { gl.uniform_1_u32(first_instance_location.as_ref(), 0) };
unsafe { gl.bind_buffer(glow::DRAW_INDIRECT_BUFFER, Some(indirect_buf)) }; unsafe {
gl.draw_elements_indirect_offset(topology, index_type, indirect_offset as i32)
};
}
C::Dispatch(group_counts) => { unsafe { gl.dispatch_compute(group_counts[0], group_counts[1], group_counts[2]) };
}
C::DispatchIndirect {
indirect_buf,
indirect_offset,
} => { unsafe { gl.bind_buffer(glow::DISPATCH_INDIRECT_BUFFER, Some(indirect_buf)) }; unsafe { gl.dispatch_compute_indirect(indirect_offset as i32) };
}
C::ClearBuffer { ref dst,
dst_target, ref range,
} => match dst.raw {
Some(buffer) => { // When `INDEX_BUFFER_ROLE_CHANGE` isn't available, we can't copy into the // index buffer from the zero buffer. This would fail in Chrome with the // following message: // // > Cannot copy into an element buffer destination from a non-element buffer // > source // // Instead, we'll upload zeroes into the buffer. let can_use_zero_buffer = self
.shared
.private_caps
.contains(PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE)
|| dst_target != glow::ELEMENT_ARRAY_BUFFER;
if can_use_zero_buffer { unsafe { gl.bind_buffer(glow::COPY_READ_BUFFER, Some(self.zero_buffer)) }; unsafe { gl.bind_buffer(dst_target, Some(buffer)) }; letmut dst_offset = range.start; while dst_offset < range.end { let size = (range.end - dst_offset).min(super::ZERO_BUFFER_SIZE as u64); unsafe {
gl.copy_buffer_sub_data(
glow::COPY_READ_BUFFER,
dst_target, 0,
dst_offset as i32,
size as i32,
)
};
dst_offset += size;
}
} else { unsafe { gl.bind_buffer(dst_target, Some(buffer)) }; let zeroes = vec![0u8; (range.end - range.start) as usize]; unsafe {
gl.buffer_sub_data_u8_slice(dst_target, range.start as i32, &zeroes)
};
}
}
None => {
dst.data.as_ref().unwrap().lock().unwrap().as_mut_slice()
[range.start as usize..range.end as usize]
.fill(0);
}
},
C::CopyBufferToBuffer { ref src,
src_target, ref dst,
dst_target,
copy,
} => { let copy_src_target = glow::COPY_READ_BUFFER; let is_index_buffer_only_element_dst = !self
.shared
.private_caps
.contains(PrivateCapabilities::INDEX_BUFFER_ROLE_CHANGE)
&& dst_target == glow::ELEMENT_ARRAY_BUFFER
|| src_target == glow::ELEMENT_ARRAY_BUFFER;
// WebGL not allowed to copy data from other targets to element buffer and can't copy element data to other buffers let copy_dst_target = if is_index_buffer_only_element_dst {
glow::ELEMENT_ARRAY_BUFFER
} else {
glow::COPY_WRITE_BUFFER
}; let size = copy.size.get() as usize; match (src.raw, dst.raw) {
(Some(ref src), Some(ref dst)) => { unsafe { gl.bind_buffer(copy_src_target, Some(*src)) }; unsafe { gl.bind_buffer(copy_dst_target, Some(*dst)) }; unsafe {
gl.copy_buffer_sub_data(
copy_src_target,
copy_dst_target,
copy.src_offset as _,
copy.dst_offset as _,
copy.size.get() as _,
)
};
}
(Some(src), None) => { letmut data = dst.data.as_ref().unwrap().lock().unwrap(); let dst_data = &mut data.as_mut_slice()
[copy.dst_offset as usize..copy.dst_offset as usize + size];
match src.source {
wgt::ExternalImageSource::ImageBitmap(ref b) => unsafe {
gl.tex_sub_image_3d_with_image_bitmap(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
z_offset as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth as i32,
format_desc.external,
format_desc.data_type,
b,
);
},
wgt::ExternalImageSource::HTMLImageElement(ref i) => unsafe {
gl.tex_sub_image_3d_with_html_image_element(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
z_offset as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth as i32,
format_desc.external,
format_desc.data_type,
i,
);
},
wgt::ExternalImageSource::HTMLVideoElement(ref v) => unsafe {
gl.tex_sub_image_3d_with_html_video_element(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
z_offset as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth as i32,
format_desc.external,
format_desc.data_type,
v,
);
}, #[cfg(web_sys_unstable_apis)]
wgt::ExternalImageSource::VideoFrame(ref v) => unsafe {
gl.tex_sub_image_3d_with_video_frame(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
z_offset as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth as i32,
format_desc.external,
format_desc.data_type,
v,
)
},
wgt::ExternalImageSource::ImageData(ref i) => unsafe {
gl.tex_sub_image_3d_with_image_data(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
z_offset as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth as i32,
format_desc.external,
format_desc.data_type,
i,
);
},
wgt::ExternalImageSource::HTMLCanvasElement(ref c) => unsafe {
gl.tex_sub_image_3d_with_html_canvas_element(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
z_offset as i32,
copy.size.width as i32,
copy.size.height as i32,
copy.size.depth as i32,
format_desc.external,
format_desc.data_type,
c,
);
},
wgt::ExternalImageSource::OffscreenCanvas(_) => unreachable!(),
}
} else { let dst_target = get_2d_target(dst_target, copy.dst_base.array_layer);
match src.source {
wgt::ExternalImageSource::ImageBitmap(ref b) => unsafe {
gl.tex_sub_image_2d_with_image_bitmap_and_width_and_height(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
format_desc.external,
format_desc.data_type,
b,
);
},
wgt::ExternalImageSource::HTMLImageElement(ref i) => unsafe {
gl.tex_sub_image_2d_with_html_image_and_width_and_height(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
format_desc.external,
format_desc.data_type,
i,
)
},
wgt::ExternalImageSource::HTMLVideoElement(ref v) => unsafe {
gl.tex_sub_image_2d_with_html_video_and_width_and_height(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
format_desc.external,
format_desc.data_type,
v,
)
}, #[cfg(web_sys_unstable_apis)]
wgt::ExternalImageSource::VideoFrame(ref v) => unsafe {
gl.tex_sub_image_2d_with_video_frame_and_width_and_height(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
format_desc.external,
format_desc.data_type,
v,
)
},
wgt::ExternalImageSource::ImageData(ref i) => unsafe {
gl.tex_sub_image_2d_with_image_data_and_width_and_height(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
format_desc.external,
format_desc.data_type,
i,
);
},
wgt::ExternalImageSource::HTMLCanvasElement(ref c) => unsafe {
gl.tex_sub_image_2d_with_html_canvas_and_width_and_height(
dst_target,
copy.dst_base.mip_level as i32,
copy.dst_base.origin.x as i32,
copy.dst_base.origin.y as i32,
copy.size.width as i32,
copy.size.height as i32,
format_desc.external,
format_desc.data_type,
c,
)
},
wgt::ExternalImageSource::OffscreenCanvas(_) => unreachable!(),
}
}
unsafe { if src.flip_y {
gl.pixel_store_bool(UNPACK_FLIP_Y_WEBGL, false);
} if dst_premultiplication {
gl.pixel_store_bool(UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
}
}
}
C::CopyTextureToTexture {
src,
src_target,
dst,
dst_target, ref copy,
} => { //TODO: handle 3D copies unsafe { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(self.copy_fbo)) }; if is_layered_target(src_target) { //TODO: handle GLES without framebuffer_texture_3d unsafe {
gl.framebuffer_texture_layer(
glow::READ_FRAMEBUFFER,
glow::COLOR_ATTACHMENT0,
Some(src),
copy.src_base.mip_level as i32,
copy.src_base.array_layer as i32,
)
};
} else { unsafe {
gl.framebuffer_texture_2d(
glow::READ_FRAMEBUFFER,
glow::COLOR_ATTACHMENT0,
src_target,
Some(src),
copy.src_base.mip_level as i32,
)
};
}
implcrate::Queue forsuper::Queue { type A = super::Api;
unsafefn submit(
&self,
command_buffers: &[&super::CommandBuffer],
_surface_textures: &[&super::Texture],
(signal_fence, signal_value): (&mutsuper::Fence, crate::FenceValue),
) -> Result<(), crate::DeviceError> { let shared = Arc::clone(&self.shared); let gl = &shared.context.lock(); for cmd_buf in command_buffers.iter() { // The command encoder assumes a default state when encoding the command buffer. // Always reset the state between command_buffers to reflect this assumption. Do // this at the beginning of the loop in case something outside of wgpu modified // this state prior to commit. unsafe { self.reset_state(gl) }; iflet Some(ref label) = cmd_buf.label { ifself
.shared
.private_caps
.contains(PrivateCapabilities::DEBUG_FNS)
{ unsafe { gl.push_debug_group(glow::DEBUG_SOURCE_APPLICATION, DEBUG_ID, label) };
}
}
for command in cmd_buf.commands.iter() { unsafe { self.process(gl, command, &cmd_buf.data_bytes, &cmd_buf.queries) };
}
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.59Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-06-18)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.