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)
}
}
fn rebind_sampler_states(&mutself, dirty_textures: u32, dirty_samplers: u32) { for (texture_index, slot) inself.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);
}
}
implcrate::CommandEncoder forsuper::CommandEncoder { type A = super::Api;
unsafefn begin_encoding(&mutself, label: crate::Label) -> Result<(), crate::DeviceError> { self.state = State::default(); self.cmd_buffer.label = label.map(String::from);
Ok(())
} unsafefn discard_encoding(&mutself) { self.cmd_buffer.clear();
} unsafefn end_encoding(&mutself) -> Result<super::CommandBuffer, crate::DeviceError> {
Ok(mem::take(&mutself.cmd_buffer))
} unsafefn reset_all<I>(&mutself, _command_buffers: I) { //TODO: could re-use the allocations in all these command buffers
}
unsafefn transition_buffers<'a, T>(&mut self, barriers: T) where
T: Iterator<Item = crate::BufferBarrier<'a, super::Buffer>>,
{ if !self
.private_caps
.contains(super::PrivateCapabilities::MEMORY_BARRIERS)
{ return;
} for bar in barriers { // GLES only synchronizes storage -> anything explicitly if !bar.usage.from.contains(wgt::BufferUses::STORAGE_READ_WRITE) { continue;
} self.cmd_buffer
.commands
.push(C::BufferBarrier(bar.buffer.raw.unwrap(), bar.usage.to));
}
}
unsafefn transition_textures<'a, T>(&mut self, barriers: T) where
T: Iterator<Item = crate::TextureBarrier<'a, super::Texture>>,
{ if !self
.private_caps
.contains(super::PrivateCapabilities::MEMORY_BARRIERS)
{ return;
}
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);
unsafefn 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 inself.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);
// 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.