fn add_marker(&mutself, marker: &str) -> Range<u32> { let start = self.data_bytes.len() as u32; self.data_bytes.extend(marker.as_bytes());
start..self.data_bytes.len() as u32
}
fn add_immediates_data(&mutself, data: &[u32]) -> Range<u32> { let data_raw = bytemuck::cast_slice(data); let start = self.data_bytes.len();
assert!(start < u32::MAX as usize); self.data_bytes.extend_from_slice(data_raw); let end = self.data_bytes.len();
assert!(end < u32::MAX as usize);
(start as u32)..(end as u32)
}
}
impl Drop for super::CommandEncoder {
fn drop(&mutself) { usecrate::CommandEncoder; unsafe { self.discard_encoding() } self.counters.command_encoders.sub(1);
}
}
fn rebind_sampler_states(&mutself, dirty_textures: u32, dirty_samplers: u32) {
for (texture_index, slot) in self.state.texture_slots.iter().enumerate() { if dirty_textures & (1 << texture_index) != 0
|| slot
.sampler_index
.is_some_and(|si| dirty_samplers & (1 << si) != 0)
{ let sampler = slot
.sampler_index
.and_then(|si| self.state.samplers[si as usize]); self.cmd_buffer
.commands
.push(C::BindSampler(texture_index as u32, sampler));
}
}
}
fn prepare_draw(&mutself, first_instance: u32) { // If we support fully featured instancing, we want to bind everything as normal // and let the draw call sort it out. let emulated_first_instance_value = ifself
.private_caps
.contains(super::PrivateCapabilities::FULLY_FEATURED_INSTANCING)
{ 0
} else {
first_instance
};
if emulated_first_instance_value != self.state.active_first_instance { // rebind all per-instance buffers on first-instance change self.state.dirty_vbuf_mask |= self.state.instance_vbuf_mask; self.state.active_first_instance = emulated_first_instance_value;
} ifself.state.dirty_vbuf_mask != 0 { self.rebind_vertex_data(emulated_first_instance_value);
}
}
letmut combined_usage = wgt::TextureUses::empty();
for bar in barriers { // GLES only synchronizes storage -> anything explicitly // if shader writes to a texture then barriers should be placed if !bar.usage.from.intersects(
wgt::TextureUses::STORAGE_READ_WRITE | wgt::TextureUses::STORAGE_WRITE_ONLY,
) { continue;
} // unlike buffers, there is no need for a concrete texture // object to be bound anywhere for a barrier
combined_usage |= bar.usage.to;
}
if !combined_usage.is_empty() { self.cmd_buffer
.commands
.push(C::TextureBarrier(combined_usage));
}
}
if rendering_to_external_framebuffer && desc.color_attachments.len() != 1 {
panic!("Multiple render attachments with external framebuffers are not supported.");
}
// `COLOR_ATTACHMENT0` to `COLOR_ATTACHMENT31` gives 32 possible color attachments.
assert!(desc.color_attachments.len() <= 32);
for (i, cat) in desc.color_attachments.iter().enumerate() { iflet Some(cat) = cat.as_ref() { let attachment = glow::COLOR_ATTACHMENT0 + i as u32; // Try to use the multisampled render-to-texture extension to avoid resolving iflet Some(ref rat) = cat.resolve_target { if matches!(rat.view.inner, super::TextureInner::Texture { .. })
&& self.private_caps.contains( super::PrivateCapabilities::MULTISAMPLED_RENDER_TO_TEXTURE,
)
&& !cat.ops.contains(crate::AttachmentOps::STORE) // Extension specifies that only COLOR_ATTACHMENT0 is valid
&& i == 0
{ self.cmd_buffer.commands.push(C::BindAttachment {
attachment,
view: rat.view.clone(),
depth_slice: None,
sample_count: desc.sample_count,
}); continue;
}
} self.cmd_buffer.commands.push(C::BindAttachment {
attachment,
view: cat.target.view.clone(),
depth_slice: cat.depth_slice,
sample_count: 1,
}); iflet Some(ref rat) = cat.resolve_target { self.state
.resolve_attachments
.push((attachment, rat.view.clone()));
} if cat.ops.contains(crate::AttachmentOps::STORE_DISCARD) { self.state.invalidate_attachments.push(attachment);
}
}
} iflet Some(ref dsat) = desc.depth_stencil_attachment { let aspects = dsat.target.view.aspects; let attachment = match aspects { crate::FormatAspects::DEPTH => glow::DEPTH_ATTACHMENT, crate::FormatAspects::STENCIL => glow::STENCIL_ATTACHMENT,
_ => glow::DEPTH_STENCIL_ATTACHMENT,
}; self.cmd_buffer.commands.push(C::BindAttachment {
attachment,
view: dsat.target.view.clone(),
depth_slice: None,
sample_count: 1,
}); if aspects.contains(crate::FormatAspects::DEPTH)
&& dsat.depth_ops.contains(crate::AttachmentOps::STORE_DISCARD)
{ self.state
.invalidate_attachments
.push(glow::DEPTH_ATTACHMENT);
} if aspects.contains(crate::FormatAspects::STENCIL)
&& dsat
.stencil_ops
.contains(crate::AttachmentOps::STORE_DISCARD)
{ self.state
.invalidate_attachments
.push(glow::STENCIL_ATTACHMENT);
}
}
}
}
let rect = crate::Rect {
x: 0,
y: 0,
w: desc.extent.width as i32,
h: desc.extent.height as i32,
}; self.cmd_buffer.commands.push(C::SetScissor(rect.clone())); self.cmd_buffer.commands.push(C::SetViewport {
rect,
depth: 0.0..1.0,
});
if !rendering_to_external_framebuffer { // set the draw buffers and states self.cmd_buffer
.commands
.push(C::SetDrawColorBuffers(desc.color_attachments.len() as u8));
}
// issue the clears
for (i, cat) in desc
.color_attachments
.iter()
.filter_map(|at| at.as_ref())
.enumerate()
{ if cat.ops.contains(crate::AttachmentOps::LOAD_CLEAR) { let c = &cat.clear_value; self.cmd_buffer.commands.push( match cat.target.view.format.sample_type(None, None).unwrap() {
wgt::TextureSampleType::Float { .. } => C::ClearColorF {
draw_buffer: i as u32,
color: [c.r as f32, c.g as f32, c.b as f32, c.a as f32],
is_srgb: cat.target.view.format.is_srgb(),
},
wgt::TextureSampleType::Uint => C::ClearColorU(
i as u32,
[c.r as u32, c.g as u32, c.b as u32, c.a as u32],
),
wgt::TextureSampleType::Sint => C::ClearColorI(
i as u32,
[c.r as i32, c.g as i32, c.b as i32, c.a as i32],
),
wgt::TextureSampleType::Depth => unreachable!(),
},
);
}
}
iflet Some(ref dsat) = desc.depth_stencil_attachment { let clear_depth = dsat.depth_ops.contains(crate::AttachmentOps::LOAD_CLEAR); let clear_stencil = dsat.stencil_ops.contains(crate::AttachmentOps::LOAD_CLEAR);
unsafe fn set_immediates(
&mutself,
_layout: &super::PipelineLayout,
offset_bytes: u32,
data: &[u32],
) { // There is nothing preventing the user from trying to update a single value within // a vector or matrix in the set_immediates call, as to the user, all of this is // just memory. However OpenGL does not allow partial uniform updates. // // As such, we locally keep a copy of the current state of the immediate data memory // block. If the user tries to update a single value, we have the data to update the entirety // of the uniform. let start_words = offset_bytes / 4; let end_words = start_words + data.len() as u32; self.state.current_immediates_data[start_words as usize..end_words as usize]
.copy_from_slice(data);
// We iterate over the uniform list as there may be multiple uniforms that need // updating from the same immediate data memory (one for each shader stage). // // Additionally, any statically unused uniform descs will have been removed from this list // by OpenGL, so the uniform list is not contiguous.
for uniform in self.state.immediates_descs.iter().cloned() { let uniform_size_words = uniform.size_bytes / 4; let uniform_start_words = uniform.offset / 4; let uniform_end_words = uniform_start_words + uniform_size_words;
// Is true if any word within the uniform binding was updated let needs_updating =
start_words < uniform_end_words || uniform_start_words <= end_words;
if needs_updating { let uniform_data = &self.state.current_immediates_data
[uniform_start_words as usize..uniform_end_words as usize];
let range = self.cmd_buffer.add_immediates_data(uniform_data);
ifself
.private_caps
.contains(super::PrivateCapabilities::VERTEX_BUFFER_LAYOUT)
{
for vat in pipeline.vertex_attributes.iter() { let vb = pipeline.vertex_buffers[vat.buffer_index as usize]
.as_ref()
.unwrap(); // set the layout self.cmd_buffer.commands.push(C::SetVertexAttribute {
buffer: None,
buffer_desc: vb.clone(),
attribute_desc: vat.clone(),
});
}
} else {
for vat in &self.state.vertex_attributes { self.cmd_buffer
.commands
.push(C::UnsetVertexAttribute(vat.location));
} self.state.vertex_attributes.clear();
self.state.dirty_vbuf_mask = 0; // copy vertex attributes
for vat in pipeline.vertex_attributes.iter() { //Note: we can invalidate more carefully here. self.state.dirty_vbuf_mask |= 1 << vat.buffer_index; self.state.vertex_attributes.push(vat.clone());
}
}
self.state.instance_vbuf_mask = 0; // copy vertex state
for (index, (&mut (refmut state_desc, _), pipe_desc)) in self
.state
.vertex_buffers
.iter_mut()
.zip(pipeline.vertex_buffers.iter())
.enumerate()
{ let Some(pipe_desc) = pipe_desc else { continue;
}; if pipe_desc.step == wgt::VertexStepMode::Instance { self.state.instance_vbuf_mask |= 1 << index;
} if state_desc.as_ref() != Some(pipe_desc) { self.state.dirty_vbuf_mask |= 1 << index;
*state_desc = Some(pipe_desc.clone());
}
}
self.set_pipeline_inner(&pipeline.inner);
// set primitive state let prim_state = conv::map_primitive_state(&pipeline.primitive); if prim_state != self.state.primitive { self.cmd_buffer
.commands
.push(C::SetPrimitive(prim_state.clone())); self.state.primitive = prim_state;
}
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.