mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[rs] Merge #690
690: Add `RenderEncoder` r=kvark a=0x182d4454fb211940
It seems like `RenderPass` and `RenderBundleEncoder` share many methods in common (`set_pipeline`, `draw_indexed`, etc). By creating a shared trait, it allows more reusable code. For instance:
```rust
impl RedCircle {
fn new(...) -> Self { .. }
fn draw<'a>(&'a self, encoder: &mut impl RenderEncoder<'a>) { .. }
}
```
This code would then work for both structs.
Moving the previous methods from their `impl`s to the trait's would break previous code, as to use these methods code would now have to import `RenderEncoder`. To avoid this, it is implemented by calling the direct methods.
It may be worth considering moving this to `wgpu::util`.
Co-authored-by: 0x182d4454fb211940 <nathanwoodformal@gmail.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
### unreleased
|
||||
- introduce `ShaderModuleDescriptor`
|
||||
- introduce `RenderEncoder`
|
||||
|
||||
### v0.6.2 (2020-11-24)
|
||||
- don't panic in the staging belt if the channel is dropped
|
||||
|
||||
223
wgpu/src/util/encoder.rs
Normal file
223
wgpu/src/util/encoder.rs
Normal file
@@ -0,0 +1,223 @@
|
||||
use std::ops::Range;
|
||||
|
||||
use wgt::{BufferAddress, DynamicOffset, IndexFormat};
|
||||
|
||||
use crate::{BindGroup, Buffer, BufferSlice, RenderBundleEncoder, RenderPass, RenderPipeline};
|
||||
|
||||
/// Methods shared by `RenderPass` and `RenderBundleEncoder`
|
||||
pub trait RenderEncoder<'a> {
|
||||
/// Sets the active bind group for a given bind group index. The bind group layout
|
||||
/// in the active pipeline when any `draw()` function is called must match the layout of this bind group.
|
||||
///
|
||||
/// If the bind group have dynamic offsets, provide them in order of their declaration.
|
||||
fn set_bind_group(&mut self, index: u32, bind_group: &'a BindGroup, offsets: &[DynamicOffset]);
|
||||
|
||||
/// Sets the active render pipeline.
|
||||
///
|
||||
/// Subsequent draw calls will exhibit the behavior defined by `pipeline`.
|
||||
fn set_pipeline(&mut self, pipeline: &'a RenderPipeline);
|
||||
|
||||
/// Sets the active index buffer.
|
||||
///
|
||||
/// Subsequent calls to [`draw_indexed`](RenderBundleEncoder::draw_indexed) on this [`RenderBundleEncoder`] will
|
||||
/// use `buffer` as the source index buffer.
|
||||
fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>, index_format: IndexFormat);
|
||||
|
||||
/// Assign a vertex buffer to a slot.
|
||||
///
|
||||
/// Subsequent calls to [`draw`] and [`draw_indexed`] on this
|
||||
/// [`RenderBundleEncoder`] will use `buffer` as one of the source vertex buffers.
|
||||
///
|
||||
/// The `slot` refers to the index of the matching descriptor in
|
||||
/// [`VertexStateDescriptor::vertex_buffers`].
|
||||
///
|
||||
/// [`draw`]: RenderBundleEncoder::draw
|
||||
/// [`draw_indexed`]: RenderBundleEncoder::draw_indexed
|
||||
fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'a>);
|
||||
|
||||
/// Draws primitives from the active vertex buffer(s).
|
||||
///
|
||||
/// The active vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
|
||||
fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>);
|
||||
|
||||
/// Draws indexed primitives using the active index buffer and the active vertex buffers.
|
||||
///
|
||||
/// The active index buffer can be set with [`RenderBundleEncoder::set_index_buffer`], while the active
|
||||
/// vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
|
||||
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>);
|
||||
|
||||
/// Draws primitives from the active vertex buffer(s) based on the contents of the `indirect_buffer`.
|
||||
///
|
||||
/// The active vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
|
||||
///
|
||||
/// The structure expected in `indirect_buffer` is the following:
|
||||
///
|
||||
/// ```rust
|
||||
/// #[repr(C)]
|
||||
/// struct DrawIndirect {
|
||||
/// vertex_count: u32, // The number of vertices to draw.
|
||||
/// instance_count: u32, // The number of instances to draw.
|
||||
/// base_vertex: u32, // The Index of the first vertex to draw.
|
||||
/// base_instance: u32, // The instance ID of the first instance to draw.
|
||||
/// }
|
||||
/// ```
|
||||
fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: BufferAddress);
|
||||
|
||||
/// Draws indexed primitives using the active index buffer and the active vertex buffers,
|
||||
/// based on the contents of the `indirect_buffer`.
|
||||
///
|
||||
/// The active index buffer can be set with [`RenderBundleEncoder::set_index_buffer`], while the active
|
||||
/// vertex buffers can be set with [`RenderBundleEncoder::set_vertex_buffer`].
|
||||
///
|
||||
/// The structure expected in `indirect_buffer` is the following:
|
||||
///
|
||||
/// ```rust
|
||||
/// #[repr(C)]
|
||||
/// struct DrawIndexedIndirect {
|
||||
/// vertex_count: u32, // The number of vertices to draw.
|
||||
/// instance_count: u32, // The number of instances to draw.
|
||||
/// base_index: u32, // The base index within the index buffer.
|
||||
/// vertex_offset: i32, // The value added to the vertex index before indexing into the vertex buffer.
|
||||
/// base_instance: u32, // The instance ID of the first instance to draw.
|
||||
/// }
|
||||
/// ```
|
||||
fn draw_indexed_indirect(
|
||||
&mut self,
|
||||
indirect_buffer: &'a Buffer,
|
||||
indirect_offset: BufferAddress,
|
||||
);
|
||||
|
||||
/// [`Features::PUSH_CONSTANTS`] must be enabled on the device in order to call this function.
|
||||
///
|
||||
/// Set push constant data.
|
||||
///
|
||||
/// Offset is measured in bytes, but must be a multiple of [`PUSH_CONSTANT_ALIGNMENT`].
|
||||
///
|
||||
/// Data size must be a multiple of 4 and must be aligned to the 4s, so we take an array of u32.
|
||||
/// For example, with an offset of 4 and an array of `[u32; 3]`, that will write to the range
|
||||
/// of 4..16.
|
||||
///
|
||||
/// For each byte in the range of push constant data written, the union of the stages of all push constant
|
||||
/// ranges that covers that byte must be exactly `stages`. There's no good way of explaining this simply,
|
||||
/// so here are some examples:
|
||||
///
|
||||
/// ```text
|
||||
/// For the given ranges:
|
||||
/// - 0..4 Vertex
|
||||
/// - 4..8 Fragment
|
||||
/// ```
|
||||
///
|
||||
/// You would need to upload this in two set_push_constants calls. First for the `Vertex` range, second for the `Fragment` range.
|
||||
///
|
||||
/// ```text
|
||||
/// For the given ranges:
|
||||
/// - 0..8 Vertex
|
||||
/// - 4..12 Fragment
|
||||
/// ```
|
||||
///
|
||||
/// You would need to upload this in three set_push_constants calls. First for the `Vertex` only range 0..4, second
|
||||
/// for the `Vertex | Fragment` range 4..8, third for the `Fragment` range 8..12.
|
||||
fn set_push_constants(&mut self, stages: wgt::ShaderStage, offset: u32, data: &[u8]);
|
||||
}
|
||||
|
||||
impl<'a> RenderEncoder<'a> for RenderPass<'a> {
|
||||
#[inline(always)]
|
||||
fn set_bind_group(&mut self, index: u32, bind_group: &'a BindGroup, offsets: &[DynamicOffset]) {
|
||||
Self::set_bind_group(self, index, bind_group, offsets);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) {
|
||||
Self::set_pipeline(self, pipeline);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>, index_format: IndexFormat) {
|
||||
Self::set_index_buffer(self, buffer_slice, index_format);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'a>) {
|
||||
Self::set_vertex_buffer(self, slot, buffer_slice);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
|
||||
Self::draw(self, vertices, instances);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
|
||||
Self::draw_indexed(self, indices, base_vertex, instances);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: BufferAddress) {
|
||||
Self::draw_indirect(self, indirect_buffer, indirect_offset);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn draw_indexed_indirect(
|
||||
&mut self,
|
||||
indirect_buffer: &'a Buffer,
|
||||
indirect_offset: BufferAddress,
|
||||
) {
|
||||
Self::draw_indexed_indirect(self, indirect_buffer, indirect_offset);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_push_constants(&mut self, stages: wgt::ShaderStage, offset: u32, data: &[u8]) {
|
||||
Self::set_push_constants(self, stages, offset, data);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> RenderEncoder<'a> for RenderBundleEncoder<'a> {
|
||||
#[inline(always)]
|
||||
fn set_bind_group(&mut self, index: u32, bind_group: &'a BindGroup, offsets: &[DynamicOffset]) {
|
||||
Self::set_bind_group(self, index, bind_group, offsets);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_pipeline(&mut self, pipeline: &'a RenderPipeline) {
|
||||
Self::set_pipeline(self, pipeline);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_index_buffer(&mut self, buffer_slice: BufferSlice<'a>, index_format: IndexFormat) {
|
||||
Self::set_index_buffer(self, buffer_slice, index_format);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_vertex_buffer(&mut self, slot: u32, buffer_slice: BufferSlice<'a>) {
|
||||
Self::set_vertex_buffer(self, slot, buffer_slice);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn draw(&mut self, vertices: Range<u32>, instances: Range<u32>) {
|
||||
Self::draw(self, vertices, instances);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn draw_indexed(&mut self, indices: Range<u32>, base_vertex: i32, instances: Range<u32>) {
|
||||
Self::draw_indexed(self, indices, base_vertex, instances);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn draw_indirect(&mut self, indirect_buffer: &'a Buffer, indirect_offset: BufferAddress) {
|
||||
Self::draw_indirect(self, indirect_buffer, indirect_offset);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn draw_indexed_indirect(
|
||||
&mut self,
|
||||
indirect_buffer: &'a Buffer,
|
||||
indirect_offset: BufferAddress,
|
||||
) {
|
||||
Self::draw_indexed_indirect(self, indirect_buffer, indirect_offset);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn set_push_constants(&mut self, stages: wgt::ShaderStage, offset: u32, data: &[u8]) {
|
||||
Self::set_push_constants(self, stages, offset, data);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
mod belt;
|
||||
mod device;
|
||||
mod encoder;
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
@@ -11,6 +12,7 @@ use std::{
|
||||
|
||||
pub use belt::StagingBelt;
|
||||
pub use device::{BufferInitDescriptor, DeviceExt};
|
||||
pub use encoder::RenderEncoder;
|
||||
|
||||
/// Treat the given byte slice as a SPIR-V module.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user