mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-22 06:44:14 +00:00
Remove peek-poke.
There was a lot of highly unsafe use of serialization based on peek-poke that we weren't entirely happy with. It's replaced by just serializing the passes now. Also, switch BufferSize to Option<NonZero>.
This commit is contained in:
parent
c8a1734044
commit
365f4e8786
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -76,13 +76,13 @@ jobs:
|
||||
name: Ubuntu Nightly
|
||||
channel: nightly
|
||||
build_command: cargo test
|
||||
additional_core_features:
|
||||
additional_core_features: serial-pass
|
||||
additional_player_features: winit
|
||||
- os: windows-2019
|
||||
name: Windows Stable
|
||||
channel: stable
|
||||
build_command: rustup default stable-msvc; cargo clippy
|
||||
additional_core_features: trace
|
||||
additional_core_features: trace,serial-pass
|
||||
additional_player_features: renderdoc
|
||||
- os: windows-2019
|
||||
name: Windows Nightly
|
||||
|
39
Cargo.lock
generated
39
Cargo.lock
generated
@ -43,6 +43,9 @@ name = "arrayvec"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ash"
|
||||
@ -908,28 +911,6 @@ dependencies = [
|
||||
"winapi 0.3.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peek-poke"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d93fd6a575ebf1ac2668d08443c97a22872cfb463fd8b7ddd141e9f6be59af2f"
|
||||
dependencies = [
|
||||
"peek-poke-derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peek-poke-derive"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fb44a25c5bba983be0fc8592dfaf3e6d0935ce8be0c6b15b2a39507af34a926"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.18",
|
||||
"quote 1.0.7",
|
||||
"syn",
|
||||
"synstructure",
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.1.0"
|
||||
@ -1242,18 +1223,6 @@ dependencies = [
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.18",
|
||||
"quote 1.0.7",
|
||||
"syn",
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.0"
|
||||
@ -1467,7 +1436,6 @@ dependencies = [
|
||||
"loom",
|
||||
"naga",
|
||||
"parking_lot",
|
||||
"peek-poke",
|
||||
"raw-window-handle",
|
||||
"ron",
|
||||
"serde",
|
||||
@ -1482,7 +1450,6 @@ name = "wgpu-types"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"peek-poke",
|
||||
"serde",
|
||||
]
|
||||
|
||||
|
@ -13,4 +13,4 @@ publish = false
|
||||
path = "../wgpu-core"
|
||||
package = "wgpu-core"
|
||||
version = "0.5"
|
||||
features = ["battery", "trace"]
|
||||
features = ["battery", "serial-pass", "trace"]
|
||||
|
@ -139,33 +139,21 @@ impl GlobalExt for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
trace::Command::CopyTextureToTexture { src, dst, size } => {
|
||||
self.command_encoder_copy_texture_to_texture::<B>(encoder, &src, &dst, &size)
|
||||
}
|
||||
trace::Command::RunComputePass {
|
||||
commands,
|
||||
dynamic_offsets,
|
||||
} => unsafe {
|
||||
let mut pass = wgc::command::RawPass::new_compute(encoder);
|
||||
pass.fill_compute_commands(&commands, &dynamic_offsets);
|
||||
let (data, _) = pass.finish_compute();
|
||||
self.command_encoder_run_compute_pass::<B>(encoder, &data);
|
||||
},
|
||||
trace::Command::RunComputePass { base } => {
|
||||
self.command_encoder_run_compute_pass_impl::<B>(encoder, base.as_ref());
|
||||
}
|
||||
trace::Command::RunRenderPass {
|
||||
base,
|
||||
target_colors,
|
||||
target_depth_stencil,
|
||||
commands,
|
||||
dynamic_offsets,
|
||||
} => unsafe {
|
||||
let mut pass = wgc::command::RawPass::new_render(
|
||||
} => {
|
||||
self.command_encoder_run_render_pass_impl::<B>(
|
||||
encoder,
|
||||
&wgc::command::RenderPassDescriptor {
|
||||
color_attachments: target_colors.as_ptr(),
|
||||
color_attachments_length: target_colors.len(),
|
||||
depth_stencil_attachment: target_depth_stencil.as_ref(),
|
||||
},
|
||||
base.as_ref(),
|
||||
&target_colors,
|
||||
target_depth_stencil.as_ref(),
|
||||
);
|
||||
pass.fill_render_commands(&commands, &dynamic_offsets);
|
||||
let (data, _) = pass.finish_render();
|
||||
self.command_encoder_run_render_pass::<B>(encoder, &data);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
self.command_encoder_finish::<B>(encoder, &wgt::CommandBufferDescriptor { todo: 0 })
|
||||
@ -385,14 +373,9 @@ impl GlobalExt for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
A::DestroyRenderPipeline(id) => {
|
||||
self.render_pipeline_destroy::<B>(id);
|
||||
}
|
||||
A::CreateRenderBundle {
|
||||
id,
|
||||
desc,
|
||||
commands,
|
||||
dynamic_offsets,
|
||||
} => {
|
||||
A::CreateRenderBundle { id, desc, base } => {
|
||||
let label = Label::new(&desc.label);
|
||||
let mut bundle_encoder = wgc::command::RenderBundleEncoder::new(
|
||||
let bundle = wgc::command::RenderBundleEncoder::new(
|
||||
&wgt::RenderBundleEncoderDescriptor {
|
||||
label: None,
|
||||
color_formats: &desc.color_formats,
|
||||
@ -400,10 +383,10 @@ impl GlobalExt for wgc::hub::Global<IdentityPassThroughFactory> {
|
||||
sample_count: desc.sample_count,
|
||||
},
|
||||
device,
|
||||
Some(base),
|
||||
);
|
||||
bundle_encoder.fill_commands(&commands, &dynamic_offsets);
|
||||
self.render_bundle_encoder_finish::<B>(
|
||||
bundle_encoder,
|
||||
bundle,
|
||||
&wgt::RenderBundleDescriptor {
|
||||
label: label.as_ptr(),
|
||||
},
|
||||
|
@ -13,8 +13,12 @@ license = "MPL-2.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
# Enable API tracing
|
||||
trace = ["ron", "serde", "wgt/trace"]
|
||||
# Enable API replaying
|
||||
replay = ["serde", "wgt/replay"]
|
||||
# Enable serializable compute/render passes, and bundle encoders.
|
||||
serial-pass = ["serde", "wgt/serde", "arrayvec/serde"]
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.5"
|
||||
@ -25,7 +29,6 @@ log = "0.4"
|
||||
hal = { package = "gfx-hal", version = "0.5.2" }
|
||||
gfx-backend-empty = "0.5"
|
||||
parking_lot = "0.10"
|
||||
peek-poke = "0.2"
|
||||
raw-window-handle = { version = "0.3", optional = true }
|
||||
ron = { version = "0.5", optional = true }
|
||||
serde = { version = "1.0", features = ["serde_derive"], optional = true }
|
||||
@ -49,7 +52,6 @@ rev = "438353c3f75368c12024ad2fc03cbeb15f351fd9"
|
||||
path = "../wgpu-types"
|
||||
package = "wgpu-types"
|
||||
version = "0.5"
|
||||
features = ["peek-poke"]
|
||||
|
||||
[target.'cfg(any(target_os = "ios", target_os = "macos"))'.dependencies]
|
||||
gfx-backend-metal = { version = "0.5.4" }
|
||||
|
@ -67,7 +67,7 @@ pub struct PipelineLayout<B: hal::Backend> {
|
||||
pub struct BufferBinding {
|
||||
pub buffer_id: BufferId,
|
||||
pub offset: wgt::BufferAddress,
|
||||
pub size: wgt::BufferSize,
|
||||
pub size: Option<wgt::BufferSize>,
|
||||
}
|
||||
|
||||
// Note: Duplicated in wgpu-rs as BindingResource
|
||||
|
@ -37,7 +37,7 @@
|
||||
!*/
|
||||
|
||||
use crate::{
|
||||
command::{PhantomSlice, RawPass, RenderCommand},
|
||||
command::{BasePass, RenderCommand},
|
||||
conv,
|
||||
device::{AttachmentData, Label, RenderPassContext, MAX_VERTEX_BUFFERS},
|
||||
hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Input, Storage, Token},
|
||||
@ -47,19 +47,24 @@ use crate::{
|
||||
LifeGuard, RefCount, Stored, MAX_BIND_GROUPS,
|
||||
};
|
||||
use arrayvec::ArrayVec;
|
||||
use peek_poke::{Peek, Poke};
|
||||
use std::{borrow::Borrow, iter, marker::PhantomData, ops::Range};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct RenderBundleEncoder {
|
||||
raw: RawPass<id::DeviceId>,
|
||||
base: BasePass<RenderCommand>,
|
||||
parent_id: id::DeviceId,
|
||||
pub(crate) context: RenderPassContext,
|
||||
}
|
||||
|
||||
impl RenderBundleEncoder {
|
||||
pub fn new(desc: &wgt::RenderBundleEncoderDescriptor, device_id: id::DeviceId) -> Self {
|
||||
pub fn new(
|
||||
desc: &wgt::RenderBundleEncoderDescriptor,
|
||||
parent_id: id::DeviceId,
|
||||
base: Option<BasePass<RenderCommand>>,
|
||||
) -> Self {
|
||||
RenderBundleEncoder {
|
||||
raw: RawPass::new::<RenderCommand>(device_id),
|
||||
base: base.unwrap_or_else(BasePass::new),
|
||||
parent_id,
|
||||
context: RenderPassContext {
|
||||
attachments: AttachmentData {
|
||||
colors: desc.color_formats.iter().cloned().collect(),
|
||||
@ -76,15 +81,7 @@ impl RenderBundleEncoder {
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> id::DeviceId {
|
||||
self.raw.parent
|
||||
}
|
||||
|
||||
pub fn fill_commands(&mut self, commands: &[RenderCommand], offsets: &[wgt::DynamicOffset]) {
|
||||
unsafe { self.raw.fill_render_commands(commands, offsets) }
|
||||
}
|
||||
|
||||
pub fn destroy(mut self) {
|
||||
unsafe { self.raw.invalidate() };
|
||||
self.parent_id
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,8 +92,7 @@ impl RenderBundleEncoder {
|
||||
pub struct RenderBundle {
|
||||
// Normalized command stream. It can be executed verbatim,
|
||||
// without re-binding anything on the pipeline change.
|
||||
commands: Vec<RenderCommand>,
|
||||
dynamic_offsets: Vec<wgt::DynamicOffset>,
|
||||
base: BasePass<RenderCommand>,
|
||||
pub(crate) device_id: Stored<id::DeviceId>,
|
||||
pub(crate) used: TrackerSet,
|
||||
pub(crate) context: RenderPassContext,
|
||||
@ -125,17 +121,16 @@ impl RenderBundle {
|
||||
) {
|
||||
use hal::command::CommandBuffer as _;
|
||||
|
||||
let mut offsets = self.dynamic_offsets.as_slice();
|
||||
let mut offsets = self.base.dynamic_offsets.as_slice();
|
||||
let mut index_type = hal::IndexType::U16;
|
||||
let mut pipeline_layout_id = None::<id::PipelineLayoutId>;
|
||||
|
||||
for command in self.commands.iter() {
|
||||
for command in self.base.commands.iter() {
|
||||
match *command {
|
||||
RenderCommand::SetBindGroup {
|
||||
index,
|
||||
num_dynamic_offsets,
|
||||
bind_group_id,
|
||||
phantom_offsets: _,
|
||||
} => {
|
||||
let bind_group = &bind_group_guard[bind_group_id];
|
||||
comb.bind_graphics_descriptor_sets(
|
||||
@ -162,11 +157,7 @@ impl RenderBundle {
|
||||
buffer: &buffer.raw,
|
||||
range: hal::buffer::SubRange {
|
||||
offset,
|
||||
size: if size != wgt::BufferSize::WHOLE {
|
||||
Some(size.0)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
size: size.map(|s| s.get()),
|
||||
},
|
||||
index_type,
|
||||
};
|
||||
@ -182,11 +173,7 @@ impl RenderBundle {
|
||||
let buffer = &buffer_guard[buffer_id];
|
||||
let range = hal::buffer::SubRange {
|
||||
offset,
|
||||
size: if size != wgt::BufferSize::WHOLE {
|
||||
Some(size.0)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
size: size.map(|s| s.get()),
|
||||
};
|
||||
comb.bind_vertex_buffers(slot, iter::once((&buffer.raw, range)));
|
||||
}
|
||||
@ -222,23 +209,14 @@ impl RenderBundle {
|
||||
let buffer = &buffer_guard[buffer_id];
|
||||
comb.draw_indexed_indirect(&buffer.raw, offset, 1, 0);
|
||||
}
|
||||
RenderCommand::PushDebugGroup {
|
||||
color: _,
|
||||
len: _,
|
||||
phantom_marker: _,
|
||||
} => unimplemented!(),
|
||||
RenderCommand::InsertDebugMarker {
|
||||
color: _,
|
||||
len: _,
|
||||
phantom_marker: _,
|
||||
} => unimplemented!(),
|
||||
RenderCommand::PushDebugGroup { color: _, len: _ } => unimplemented!(),
|
||||
RenderCommand::InsertDebugMarker { color: _, len: _ } => unimplemented!(),
|
||||
RenderCommand::PopDebugGroup => unimplemented!(),
|
||||
RenderCommand::ExecuteBundle(_)
|
||||
| RenderCommand::SetBlendColor(_)
|
||||
| RenderCommand::SetStencilReference(_)
|
||||
| RenderCommand::SetViewport { .. }
|
||||
| RenderCommand::SetScissor(_)
|
||||
| RenderCommand::End => unreachable!(),
|
||||
| RenderCommand::SetScissor(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -283,7 +261,7 @@ impl IndexState {
|
||||
Some(RenderCommand::SetIndexBuffer {
|
||||
buffer_id: self.buffer.unwrap(),
|
||||
offset: self.range.start,
|
||||
size: wgt::BufferSize(self.range.end - self.range.start),
|
||||
size: wgt::BufferSize::new(self.range.end - self.range.start),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@ -337,7 +315,7 @@ impl VertexState {
|
||||
slot,
|
||||
buffer_id: self.buffer.unwrap(),
|
||||
offset: self.range.start,
|
||||
size: wgt::BufferSize(self.range.end - self.range.start),
|
||||
size: wgt::BufferSize::new(self.range.end - self.range.start),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@ -488,7 +466,6 @@ impl State {
|
||||
bind_group_id: bs.bind_group.unwrap().0,
|
||||
num_dynamic_offsets: (bs.dynamic_offsets.end - bs.dynamic_offsets.start)
|
||||
as u8,
|
||||
phantom_offsets: PhantomSlice::default(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@ -508,8 +485,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let mut token = Token::root();
|
||||
let (device_guard, mut token) = hub.devices.read(&mut token);
|
||||
|
||||
let (data, device_id) = unsafe { bundle_encoder.raw.finish_render() };
|
||||
let device = &device_guard[device_id];
|
||||
let device = &device_guard[bundle_encoder.parent_id];
|
||||
let render_bundle = {
|
||||
let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token);
|
||||
let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token);
|
||||
@ -517,7 +493,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let (buffer_guard, _) = hub.buffers.read(&mut token);
|
||||
|
||||
let mut state = State {
|
||||
trackers: TrackerSet::new(device_id.backend()),
|
||||
trackers: TrackerSet::new(bundle_encoder.parent_id.backend()),
|
||||
index: IndexState::new(),
|
||||
vertex: (0..MAX_VERTEX_BUFFERS)
|
||||
.map(|_| VertexState::new())
|
||||
@ -528,38 +504,18 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
used_bind_groups: 0,
|
||||
};
|
||||
let mut commands = Vec::new();
|
||||
let mut base = bundle_encoder.base.as_ref();
|
||||
|
||||
let mut peeker = data.as_ptr();
|
||||
let raw_data_end = unsafe { data.as_ptr().offset(data.len() as isize) };
|
||||
let mut command = RenderCommand::Draw {
|
||||
vertex_count: 0,
|
||||
instance_count: 0,
|
||||
first_vertex: 0,
|
||||
first_instance: 0,
|
||||
};
|
||||
loop {
|
||||
assert!(
|
||||
unsafe { peeker.add(RenderCommand::max_size()) <= raw_data_end },
|
||||
"RenderCommand (size {}) is too big to fit within raw_data",
|
||||
RenderCommand::max_size(),
|
||||
);
|
||||
peeker = unsafe { RenderCommand::peek_from(peeker, &mut command) };
|
||||
|
||||
for &command in base.commands {
|
||||
match command {
|
||||
RenderCommand::SetBindGroup {
|
||||
index,
|
||||
num_dynamic_offsets,
|
||||
bind_group_id,
|
||||
phantom_offsets,
|
||||
} => {
|
||||
let (new_peeker, offsets) = unsafe {
|
||||
phantom_offsets.decode_unaligned(
|
||||
peeker,
|
||||
num_dynamic_offsets as usize,
|
||||
raw_data_end,
|
||||
)
|
||||
};
|
||||
peeker = new_peeker;
|
||||
let offsets = &base.dynamic_offsets[..num_dynamic_offsets as usize];
|
||||
base.dynamic_offsets =
|
||||
&base.dynamic_offsets[num_dynamic_offsets as usize..];
|
||||
for off in offsets {
|
||||
assert_eq!(
|
||||
*off as wgt::BufferAddress % wgt::BIND_BUFFER_ALIGNMENT,
|
||||
@ -614,10 +570,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
.unwrap();
|
||||
assert!(buffer.usage.contains(wgt::BufferUsage::INDEX), "An invalid setIndexBuffer call has been made. The buffer usage is {:?} which does not contain required usage INDEX", buffer.usage);
|
||||
|
||||
let end = if size != wgt::BufferSize::WHOLE {
|
||||
offset + size.0
|
||||
} else {
|
||||
buffer.size
|
||||
let end = match size {
|
||||
Some(s) => offset + s.get(),
|
||||
None => buffer.size,
|
||||
};
|
||||
state.index.set_buffer(buffer_id, offset..end);
|
||||
}
|
||||
@ -638,10 +593,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
buffer.usage
|
||||
);
|
||||
|
||||
let end = if size != wgt::BufferSize::WHOLE {
|
||||
offset + size.0
|
||||
} else {
|
||||
buffer.size
|
||||
let end = match size {
|
||||
Some(s) => offset + s.get(),
|
||||
None => buffer.size,
|
||||
};
|
||||
state.vertex[slot as usize].set_buffer(buffer_id, offset..end);
|
||||
}
|
||||
@ -734,17 +688,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
commands.extend(state.flush_binds());
|
||||
commands.push(command);
|
||||
}
|
||||
RenderCommand::End => break,
|
||||
RenderCommand::PushDebugGroup {
|
||||
color: _,
|
||||
len: _,
|
||||
phantom_marker: _,
|
||||
} => unimplemented!(),
|
||||
RenderCommand::InsertDebugMarker {
|
||||
color: _,
|
||||
len: _,
|
||||
phantom_marker: _,
|
||||
} => unimplemented!(),
|
||||
RenderCommand::PushDebugGroup { color: _, len: _ } => unimplemented!(),
|
||||
RenderCommand::InsertDebugMarker { color: _, len: _ } => unimplemented!(),
|
||||
RenderCommand::PopDebugGroup => unimplemented!(),
|
||||
RenderCommand::ExecuteBundle(_)
|
||||
| RenderCommand::SetBlendColor(_)
|
||||
@ -760,10 +705,13 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let _ = desc.label; //TODO: actually use
|
||||
//TODO: check if the device is still alive
|
||||
RenderBundle {
|
||||
commands,
|
||||
dynamic_offsets: state.flat_dynamic_offsets,
|
||||
base: BasePass {
|
||||
commands,
|
||||
dynamic_offsets: state.flat_dynamic_offsets,
|
||||
string_data: Vec::new(),
|
||||
},
|
||||
device_id: Stored {
|
||||
value: device_id,
|
||||
value: bundle_encoder.parent_id,
|
||||
ref_count: device.life_guard.add_ref(),
|
||||
},
|
||||
used: state.trackers,
|
||||
@ -786,8 +734,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
trace.lock().add(trace::Action::CreateRenderBundle {
|
||||
id,
|
||||
desc: trace::RenderBundleDescriptor::new(desc.label, &bundle.context),
|
||||
commands: bundle.commands.clone(),
|
||||
dynamic_offsets: bundle.dynamic_offsets.clone(),
|
||||
base: BasePass::from_ref(bundle.base.as_ref()),
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
@ -804,7 +751,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
|
||||
pub mod bundle_ffi {
|
||||
use super::{super::PhantomSlice, RenderBundleEncoder, RenderCommand};
|
||||
use super::{RenderBundleEncoder, RenderCommand};
|
||||
use crate::{id, RawString};
|
||||
use std::{convert::TryInto, slice};
|
||||
use wgt::{BufferAddress, BufferSize, DynamicOffset};
|
||||
@ -817,41 +764,42 @@ pub mod bundle_ffi {
|
||||
// `RawPass::encode` and `RawPass::encode_slice`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_bundle_set_bind_group(
|
||||
bundle_encoder: &mut RenderBundleEncoder,
|
||||
bundle: &mut RenderBundleEncoder,
|
||||
index: u32,
|
||||
bind_group_id: id::BindGroupId,
|
||||
offsets: *const DynamicOffset,
|
||||
offset_length: usize,
|
||||
) {
|
||||
bundle_encoder.raw.encode(&RenderCommand::SetBindGroup {
|
||||
bundle.base.commands.push(RenderCommand::SetBindGroup {
|
||||
index: index.try_into().unwrap(),
|
||||
num_dynamic_offsets: offset_length.try_into().unwrap(),
|
||||
bind_group_id,
|
||||
phantom_offsets: PhantomSlice::default(),
|
||||
});
|
||||
bundle_encoder
|
||||
.raw
|
||||
.encode_slice(slice::from_raw_parts(offsets, offset_length));
|
||||
bundle
|
||||
.base
|
||||
.dynamic_offsets
|
||||
.extend_from_slice(slice::from_raw_parts(offsets, offset_length));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_bundle_set_pipeline(
|
||||
bundle_encoder: &mut RenderBundleEncoder,
|
||||
pub extern "C" fn wgpu_render_bundle_set_pipeline(
|
||||
bundle: &mut RenderBundleEncoder,
|
||||
pipeline_id: id::RenderPipelineId,
|
||||
) {
|
||||
bundle_encoder
|
||||
.raw
|
||||
.encode(&RenderCommand::SetPipeline(pipeline_id));
|
||||
bundle
|
||||
.base
|
||||
.commands
|
||||
.push(RenderCommand::SetPipeline(pipeline_id));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_bundle_set_index_buffer(
|
||||
bundle_encoder: &mut RenderBundleEncoder,
|
||||
pub extern "C" fn wgpu_render_bundle_set_index_buffer(
|
||||
bundle: &mut RenderBundleEncoder,
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
size: BufferSize,
|
||||
size: Option<BufferSize>,
|
||||
) {
|
||||
bundle_encoder.raw.encode(&RenderCommand::SetIndexBuffer {
|
||||
bundle.base.commands.push(RenderCommand::SetIndexBuffer {
|
||||
buffer_id,
|
||||
offset,
|
||||
size,
|
||||
@ -859,14 +807,14 @@ pub mod bundle_ffi {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_bundle_set_vertex_buffer(
|
||||
bundle_encoder: &mut RenderBundleEncoder,
|
||||
pub extern "C" fn wgpu_render_bundle_set_vertex_buffer(
|
||||
bundle: &mut RenderBundleEncoder,
|
||||
slot: u32,
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
size: BufferSize,
|
||||
size: Option<BufferSize>,
|
||||
) {
|
||||
bundle_encoder.raw.encode(&RenderCommand::SetVertexBuffer {
|
||||
bundle.base.commands.push(RenderCommand::SetVertexBuffer {
|
||||
slot,
|
||||
buffer_id,
|
||||
offset,
|
||||
@ -875,14 +823,14 @@ pub mod bundle_ffi {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_bundle_draw(
|
||||
bundle_encoder: &mut RenderBundleEncoder,
|
||||
pub extern "C" fn wgpu_render_bundle_draw(
|
||||
bundle: &mut RenderBundleEncoder,
|
||||
vertex_count: u32,
|
||||
instance_count: u32,
|
||||
first_vertex: u32,
|
||||
first_instance: u32,
|
||||
) {
|
||||
bundle_encoder.raw.encode(&RenderCommand::Draw {
|
||||
bundle.base.commands.push(RenderCommand::Draw {
|
||||
vertex_count,
|
||||
instance_count,
|
||||
first_vertex,
|
||||
@ -891,15 +839,15 @@ pub mod bundle_ffi {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_bundle_draw_indexed(
|
||||
bundle_encoder: &mut RenderBundleEncoder,
|
||||
pub extern "C" fn wgpu_render_bundle_draw_indexed(
|
||||
bundle: &mut RenderBundleEncoder,
|
||||
index_count: u32,
|
||||
instance_count: u32,
|
||||
first_index: u32,
|
||||
base_vertex: i32,
|
||||
first_instance: u32,
|
||||
) {
|
||||
bundle_encoder.raw.encode(&RenderCommand::DrawIndexed {
|
||||
bundle.base.commands.push(RenderCommand::DrawIndexed {
|
||||
index_count,
|
||||
instance_count,
|
||||
first_index,
|
||||
@ -909,45 +857,45 @@ pub mod bundle_ffi {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_bundle_draw_indirect(
|
||||
bundle_encoder: &mut RenderBundleEncoder,
|
||||
pub extern "C" fn wgpu_render_bundle_draw_indirect(
|
||||
bundle: &mut RenderBundleEncoder,
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
) {
|
||||
bundle_encoder
|
||||
.raw
|
||||
.encode(&RenderCommand::DrawIndirect { buffer_id, offset });
|
||||
bundle
|
||||
.base
|
||||
.commands
|
||||
.push(RenderCommand::DrawIndirect { buffer_id, offset });
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_bundle_indexed_indirect(
|
||||
bundle_encoder: &mut RenderBundleEncoder,
|
||||
pub extern "C" fn wgpu_render_pass_bundle_indexed_indirect(
|
||||
bundle: &mut RenderBundleEncoder,
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
) {
|
||||
bundle_encoder
|
||||
.raw
|
||||
.encode(&RenderCommand::DrawIndexedIndirect { buffer_id, offset });
|
||||
bundle
|
||||
.base
|
||||
.commands
|
||||
.push(RenderCommand::DrawIndexedIndirect { buffer_id, offset });
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_render_bundle_push_debug_group(
|
||||
_bundle_encoder: &mut RenderBundleEncoder,
|
||||
pub unsafe extern "C" fn wgpu_render_bundle_push_debug_group(
|
||||
_bundle: &mut RenderBundleEncoder,
|
||||
_label: RawString,
|
||||
) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_render_bundle_pop_debug_group(
|
||||
_bundle_encoder: &mut RenderBundleEncoder,
|
||||
) {
|
||||
pub unsafe extern "C" fn wgpu_render_bundle_pop_debug_group(_bundle: &mut RenderBundleEncoder) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_render_bundle_insert_debug_marker(
|
||||
_bundle_encoder: &mut RenderBundleEncoder,
|
||||
pub unsafe extern "C" fn wgpu_render_bundle_insert_debug_marker(
|
||||
_bundle: &mut RenderBundleEncoder,
|
||||
_label: RawString,
|
||||
) {
|
||||
//TODO
|
||||
|
@ -5,7 +5,7 @@
|
||||
use crate::{
|
||||
command::{
|
||||
bind::{Binder, LayoutChange},
|
||||
CommandBuffer, PhantomSlice,
|
||||
BasePass, BasePassRef, CommandBuffer,
|
||||
},
|
||||
device::all_buffer_stages,
|
||||
hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Token},
|
||||
@ -14,27 +14,25 @@ use crate::{
|
||||
};
|
||||
|
||||
use hal::command::CommandBuffer as _;
|
||||
use peek_poke::{Peek, PeekPoke, Poke};
|
||||
use wgt::{BufferAddress, BufferUsage, DynamicOffset, BIND_BUFFER_ALIGNMENT};
|
||||
use wgt::{BufferAddress, BufferUsage, BIND_BUFFER_ALIGNMENT};
|
||||
|
||||
use std::{iter, str};
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum PipelineState {
|
||||
Required,
|
||||
Set,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PeekPoke)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
#[doc(hidden)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(
|
||||
any(feature = "serial-pass", feature = "trace"),
|
||||
derive(serde::Serialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "serial-pass", feature = "replay"),
|
||||
derive(serde::Deserialize)
|
||||
)]
|
||||
pub enum ComputeCommand {
|
||||
SetBindGroup {
|
||||
index: u8,
|
||||
num_dynamic_offsets: u8,
|
||||
bind_group_id: id::BindGroupId,
|
||||
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(skip))]
|
||||
phantom_offsets: PhantomSlice<DynamicOffset>,
|
||||
},
|
||||
SetPipeline(id::ComputePipelineId),
|
||||
Dispatch([u32; 3]),
|
||||
@ -45,57 +43,30 @@ pub enum ComputeCommand {
|
||||
PushDebugGroup {
|
||||
color: u32,
|
||||
len: usize,
|
||||
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(skip))]
|
||||
phantom_marker: PhantomSlice<u8>,
|
||||
},
|
||||
PopDebugGroup,
|
||||
InsertDebugMarker {
|
||||
color: u32,
|
||||
len: usize,
|
||||
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(skip))]
|
||||
phantom_marker: PhantomSlice<u8>,
|
||||
},
|
||||
End,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct State {
|
||||
binder: Binder,
|
||||
debug_scope_depth: u32,
|
||||
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct ComputePass {
|
||||
base: BasePass<ComputeCommand>,
|
||||
parent_id: id::CommandEncoderId,
|
||||
}
|
||||
|
||||
impl Default for ComputeCommand {
|
||||
fn default() -> Self {
|
||||
ComputeCommand::End
|
||||
}
|
||||
}
|
||||
|
||||
impl super::RawPass<id::CommandEncoderId> {
|
||||
pub unsafe fn new_compute(parent: id::CommandEncoderId) -> Self {
|
||||
Self::new::<ComputeCommand>(parent)
|
||||
}
|
||||
|
||||
pub unsafe fn fill_compute_commands(
|
||||
&mut self,
|
||||
commands: &[ComputeCommand],
|
||||
mut offsets: &[DynamicOffset],
|
||||
) {
|
||||
for com in commands {
|
||||
self.encode(com);
|
||||
if let ComputeCommand::SetBindGroup {
|
||||
num_dynamic_offsets,
|
||||
..
|
||||
} = *com
|
||||
{
|
||||
self.encode_slice(&offsets[..num_dynamic_offsets as usize]);
|
||||
offsets = &offsets[num_dynamic_offsets as usize..];
|
||||
}
|
||||
impl ComputePass {
|
||||
pub fn new(parent_id: id::CommandEncoderId) -> Self {
|
||||
ComputePass {
|
||||
base: BasePass::new(),
|
||||
parent_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn finish_compute(mut self) -> (Vec<u8>, id::CommandEncoderId) {
|
||||
self.finish(ComputeCommand::End);
|
||||
self.into_vec()
|
||||
pub fn parent_id(&self) -> id::CommandEncoderId {
|
||||
self.parent_id
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,13 +76,35 @@ pub struct ComputePassDescriptor {
|
||||
pub todo: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum PipelineState {
|
||||
Required,
|
||||
Set,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct State {
|
||||
binder: Binder,
|
||||
pipeline: PipelineState,
|
||||
debug_scope_depth: u32,
|
||||
}
|
||||
|
||||
// Common routines between render/compute
|
||||
|
||||
impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
pub fn command_encoder_run_compute_pass<B: GfxBackend>(
|
||||
&self,
|
||||
encoder_id: id::CommandEncoderId,
|
||||
raw_data: &[u8],
|
||||
pass: &ComputePass,
|
||||
) {
|
||||
self.command_encoder_run_compute_pass_impl::<B>(encoder_id, pass.base.as_ref())
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn command_encoder_run_compute_pass_impl<B: GfxBackend>(
|
||||
&self,
|
||||
encoder_id: id::CommandEncoderId,
|
||||
mut base: BasePassRef<ComputeCommand>,
|
||||
) {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
@ -120,6 +113,16 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let cmb = &mut cmb_guard[encoder_id];
|
||||
let raw = cmb.raw.last_mut().unwrap();
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
match cmb.commands {
|
||||
Some(ref mut list) => {
|
||||
list.push(crate::device::trace::Command::RunComputePass {
|
||||
base: BasePass::from_ref(base),
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
let (_, mut token) = hub.render_bundles.read(&mut token);
|
||||
let (pipeline_layout_guard, mut token) = hub.pipeline_layouts.read(&mut token);
|
||||
let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token);
|
||||
@ -127,45 +130,30 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let (buffer_guard, mut token) = hub.buffers.read(&mut token);
|
||||
let (texture_guard, _) = hub.textures.read(&mut token);
|
||||
|
||||
let mut pipeline_state = PipelineState::Required;
|
||||
|
||||
let mut state = State {
|
||||
binder: Binder::new(cmb.limits.max_bind_groups),
|
||||
pipeline: PipelineState::Required,
|
||||
debug_scope_depth: 0,
|
||||
};
|
||||
|
||||
let mut peeker = raw_data.as_ptr();
|
||||
let raw_data_end = unsafe { raw_data.as_ptr().add(raw_data.len()) };
|
||||
let mut command = ComputeCommand::Dispatch([0; 3]); // dummy
|
||||
loop {
|
||||
assert!(unsafe { peeker.add(ComputeCommand::max_size()) } <= raw_data_end);
|
||||
peeker = unsafe { ComputeCommand::peek_from(peeker, &mut command) };
|
||||
match command {
|
||||
for command in base.commands {
|
||||
match *command {
|
||||
ComputeCommand::SetBindGroup {
|
||||
index,
|
||||
num_dynamic_offsets,
|
||||
bind_group_id,
|
||||
phantom_offsets,
|
||||
} => {
|
||||
let (new_peeker, offsets) = unsafe {
|
||||
phantom_offsets.decode_unaligned(
|
||||
peeker,
|
||||
num_dynamic_offsets as usize,
|
||||
raw_data_end,
|
||||
)
|
||||
};
|
||||
peeker = new_peeker;
|
||||
let offsets = &base.dynamic_offsets[..num_dynamic_offsets as usize];
|
||||
base.dynamic_offsets = &base.dynamic_offsets[num_dynamic_offsets as usize..];
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
for off in offsets {
|
||||
assert_eq!(
|
||||
*off as BufferAddress % BIND_BUFFER_ALIGNMENT,
|
||||
0,
|
||||
"Misaligned dynamic buffer offset: {} does not align with {}",
|
||||
off,
|
||||
BIND_BUFFER_ALIGNMENT
|
||||
);
|
||||
}
|
||||
for off in offsets {
|
||||
assert_eq!(
|
||||
*off as BufferAddress % BIND_BUFFER_ALIGNMENT,
|
||||
0,
|
||||
"Misaligned dynamic buffer offset: {} does not align with {}",
|
||||
off,
|
||||
BIND_BUFFER_ALIGNMENT
|
||||
);
|
||||
}
|
||||
|
||||
let bind_group = cmb
|
||||
@ -213,7 +201,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
}
|
||||
ComputeCommand::SetPipeline(pipeline_id) => {
|
||||
pipeline_state = PipelineState::Set;
|
||||
state.pipeline = PipelineState::Set;
|
||||
let pipeline = cmb
|
||||
.trackers
|
||||
.compute_pipes
|
||||
@ -262,7 +250,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
ComputeCommand::Dispatch(groups) => {
|
||||
assert_eq!(
|
||||
pipeline_state,
|
||||
state.pipeline,
|
||||
PipelineState::Set,
|
||||
"Dispatch error: Pipeline is missing"
|
||||
);
|
||||
@ -272,7 +260,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
ComputeCommand::DispatchIndirect { buffer_id, offset } => {
|
||||
assert_eq!(
|
||||
pipeline_state,
|
||||
state.pipeline,
|
||||
PipelineState::Set,
|
||||
"Dispatch error: Pipeline is missing"
|
||||
);
|
||||
@ -295,90 +283,41 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
raw.dispatch_indirect(&src_buffer.raw, offset);
|
||||
}
|
||||
}
|
||||
ComputeCommand::PushDebugGroup {
|
||||
color,
|
||||
len,
|
||||
phantom_marker,
|
||||
} => unsafe {
|
||||
ComputeCommand::PushDebugGroup { color, len } => {
|
||||
state.debug_scope_depth += 1;
|
||||
|
||||
let (new_peeker, label) =
|
||||
{ phantom_marker.decode_unaligned(peeker, len, raw_data_end) };
|
||||
peeker = new_peeker;
|
||||
|
||||
raw.begin_debug_marker(str::from_utf8(label).unwrap(), color)
|
||||
},
|
||||
ComputeCommand::PopDebugGroup => unsafe {
|
||||
let label = str::from_utf8(&base.string_data[..len]).unwrap();
|
||||
unsafe {
|
||||
raw.begin_debug_marker(label, color);
|
||||
}
|
||||
base.string_data = &base.string_data[len..];
|
||||
}
|
||||
ComputeCommand::PopDebugGroup => {
|
||||
assert_ne!(
|
||||
state.debug_scope_depth, 0,
|
||||
"Can't pop debug group, because number of pushed debug groups is zero!"
|
||||
);
|
||||
state.debug_scope_depth -= 1;
|
||||
|
||||
raw.end_debug_marker()
|
||||
},
|
||||
ComputeCommand::InsertDebugMarker {
|
||||
color,
|
||||
len,
|
||||
phantom_marker,
|
||||
} => unsafe {
|
||||
let (new_peeker, label) =
|
||||
{ phantom_marker.decode_unaligned(peeker, len, raw_data_end) };
|
||||
peeker = new_peeker;
|
||||
|
||||
raw.insert_debug_marker(str::from_utf8(label).unwrap(), color)
|
||||
},
|
||||
ComputeCommand::End => break,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
match cmb.commands {
|
||||
Some(ref mut list) => {
|
||||
let mut pass_commands = Vec::new();
|
||||
let mut pass_dynamic_offsets = Vec::new();
|
||||
peeker = raw_data.as_ptr();
|
||||
loop {
|
||||
peeker = unsafe { ComputeCommand::peek_from(peeker, &mut command) };
|
||||
match command {
|
||||
ComputeCommand::SetBindGroup {
|
||||
num_dynamic_offsets,
|
||||
phantom_offsets,
|
||||
..
|
||||
} => {
|
||||
let (new_peeker, offsets) = unsafe {
|
||||
phantom_offsets.decode_unaligned(
|
||||
peeker,
|
||||
num_dynamic_offsets as usize,
|
||||
raw_data_end,
|
||||
)
|
||||
};
|
||||
peeker = new_peeker;
|
||||
pass_dynamic_offsets.extend_from_slice(offsets);
|
||||
}
|
||||
ComputeCommand::End => break,
|
||||
_ => {}
|
||||
unsafe {
|
||||
raw.end_debug_marker();
|
||||
}
|
||||
pass_commands.push(command);
|
||||
}
|
||||
list.push(crate::device::trace::Command::RunComputePass {
|
||||
commands: pass_commands,
|
||||
dynamic_offsets: pass_dynamic_offsets,
|
||||
});
|
||||
ComputeCommand::InsertDebugMarker { color, len } => {
|
||||
let label = str::from_utf8(&base.string_data[..len]).unwrap();
|
||||
unsafe { raw.insert_debug_marker(label, color) }
|
||||
base.string_data = &base.string_data[len..];
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod compute_ffi {
|
||||
use super::{super::PhantomSlice, ComputeCommand};
|
||||
use super::{ComputeCommand, ComputePass};
|
||||
use crate::{id, RawString};
|
||||
use std::{convert::TryInto, ffi, slice};
|
||||
use wgt::{BufferAddress, DynamicOffset};
|
||||
|
||||
type RawPass = super::super::RawPass<id::CommandEncoderId>;
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe as there is no guarantee that the given pointer is
|
||||
@ -387,92 +326,87 @@ pub mod compute_ffi {
|
||||
// `RawPass::encode` and `RawPass::encode_slice`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_compute_pass_set_bind_group(
|
||||
pass: &mut RawPass,
|
||||
pass: &mut ComputePass,
|
||||
index: u32,
|
||||
bind_group_id: id::BindGroupId,
|
||||
offsets: *const DynamicOffset,
|
||||
offset_length: usize,
|
||||
) {
|
||||
pass.encode(&ComputeCommand::SetBindGroup {
|
||||
pass.base.commands.push(ComputeCommand::SetBindGroup {
|
||||
index: index.try_into().unwrap(),
|
||||
num_dynamic_offsets: offset_length.try_into().unwrap(),
|
||||
bind_group_id,
|
||||
phantom_offsets: PhantomSlice::default(),
|
||||
});
|
||||
pass.encode_slice(slice::from_raw_parts(offsets, offset_length));
|
||||
pass.base
|
||||
.dynamic_offsets
|
||||
.extend_from_slice(slice::from_raw_parts(offsets, offset_length));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_compute_pass_set_pipeline(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_compute_pass_set_pipeline(
|
||||
pass: &mut ComputePass,
|
||||
pipeline_id: id::ComputePipelineId,
|
||||
) {
|
||||
pass.encode(&ComputeCommand::SetPipeline(pipeline_id));
|
||||
pass.base
|
||||
.commands
|
||||
.push(ComputeCommand::SetPipeline(pipeline_id));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_compute_pass_dispatch(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_compute_pass_dispatch(
|
||||
pass: &mut ComputePass,
|
||||
groups_x: u32,
|
||||
groups_y: u32,
|
||||
groups_z: u32,
|
||||
) {
|
||||
pass.encode(&ComputeCommand::Dispatch([groups_x, groups_y, groups_z]));
|
||||
pass.base
|
||||
.commands
|
||||
.push(ComputeCommand::Dispatch([groups_x, groups_y, groups_z]));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_compute_pass_dispatch_indirect(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_compute_pass_dispatch_indirect(
|
||||
pass: &mut ComputePass,
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
) {
|
||||
pass.encode(&ComputeCommand::DispatchIndirect { buffer_id, offset });
|
||||
pass.base
|
||||
.commands
|
||||
.push(ComputeCommand::DispatchIndirect { buffer_id, offset });
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_compute_pass_push_debug_group(
|
||||
pass: &mut RawPass,
|
||||
pass: &mut ComputePass,
|
||||
label: RawString,
|
||||
color: u32,
|
||||
) {
|
||||
let bytes = ffi::CStr::from_ptr(label).to_bytes();
|
||||
pass.base.string_data.extend_from_slice(bytes);
|
||||
|
||||
pass.encode(&ComputeCommand::PushDebugGroup {
|
||||
pass.base.commands.push(ComputeCommand::PushDebugGroup {
|
||||
color,
|
||||
len: bytes.len(),
|
||||
phantom_marker: PhantomSlice::default(),
|
||||
});
|
||||
pass.encode_slice(bytes);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_compute_pass_pop_debug_group(pass: &mut RawPass) {
|
||||
pass.encode(&ComputeCommand::PopDebugGroup);
|
||||
pub extern "C" fn wgpu_compute_pass_pop_debug_group(pass: &mut ComputePass) {
|
||||
pass.base.commands.push(ComputeCommand::PopDebugGroup);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_compute_pass_insert_debug_marker(
|
||||
pass: &mut RawPass,
|
||||
pass: &mut ComputePass,
|
||||
label: RawString,
|
||||
color: u32,
|
||||
) {
|
||||
let bytes = ffi::CStr::from_ptr(label).to_bytes();
|
||||
pass.base.string_data.extend_from_slice(bytes);
|
||||
|
||||
pass.encode(&ComputeCommand::InsertDebugMarker {
|
||||
pass.base.commands.push(ComputeCommand::InsertDebugMarker {
|
||||
color,
|
||||
len: bytes.len(),
|
||||
phantom_marker: PhantomSlice::default(),
|
||||
});
|
||||
pass.encode_slice(bytes);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_compute_pass_finish(
|
||||
pass: &mut RawPass,
|
||||
length: &mut usize,
|
||||
) -> *const u8 {
|
||||
pass.finish(ComputeCommand::End);
|
||||
*length = pass.size();
|
||||
pass.base
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ pub use self::render::*;
|
||||
pub use self::transfer::*;
|
||||
|
||||
use crate::{
|
||||
device::{all_buffer_stages, all_image_stages, MAX_COLOR_TARGETS},
|
||||
device::{all_buffer_stages, all_image_stages},
|
||||
hub::{GfxBackend, Global, GlobalIdentityHandlerFactory, Storage, Token},
|
||||
id,
|
||||
resource::{Buffer, Texture},
|
||||
@ -26,133 +26,7 @@ use crate::{
|
||||
|
||||
use hal::command::CommandBuffer as _;
|
||||
|
||||
use peek_poke::PeekPoke;
|
||||
|
||||
use std::{marker::PhantomData, mem, ptr, slice, thread::ThreadId};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PeekPoke)]
|
||||
pub struct PhantomSlice<T>(PhantomData<T>);
|
||||
|
||||
impl<T> Default for PhantomSlice<T> {
|
||||
fn default() -> Self {
|
||||
PhantomSlice(PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PhantomSlice<T> {
|
||||
unsafe fn decode_unaligned<'a>(
|
||||
self,
|
||||
pointer: *const u8,
|
||||
count: usize,
|
||||
bound: *const u8,
|
||||
) -> (*const u8, &'a [T]) {
|
||||
let align_offset = pointer.align_offset(mem::align_of::<T>());
|
||||
let aligned = pointer.add(align_offset);
|
||||
let size = count * mem::size_of::<T>();
|
||||
let end = aligned.add(size);
|
||||
assert!(
|
||||
end <= bound,
|
||||
"End of phantom slice ({:?}) exceeds bound ({:?})",
|
||||
end,
|
||||
bound
|
||||
);
|
||||
(end, slice::from_raw_parts(aligned as *const T, count))
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct RawPass<P> {
|
||||
data: *mut u8,
|
||||
base: *mut u8,
|
||||
capacity: usize,
|
||||
parent: P,
|
||||
}
|
||||
|
||||
impl<P: Copy> RawPass<P> {
|
||||
fn new<T>(parent: P) -> Self {
|
||||
let mut vec = Vec::<T>::with_capacity(1);
|
||||
let ptr = vec.as_mut_ptr() as *mut u8;
|
||||
let capacity = mem::size_of::<T>();
|
||||
assert_ne!(capacity, 0);
|
||||
mem::forget(vec);
|
||||
RawPass {
|
||||
data: ptr,
|
||||
base: ptr,
|
||||
capacity,
|
||||
parent,
|
||||
}
|
||||
}
|
||||
|
||||
/// Finish encoding a raw pass.
|
||||
///
|
||||
/// The last command is provided, yet the encoder
|
||||
/// is guaranteed to have exactly `C::max_size()` space for it.
|
||||
unsafe fn finish<C: peek_poke::Poke>(&mut self, command: C) {
|
||||
self.ensure_extra_size(C::max_size());
|
||||
let extended_end = self.data.add(C::max_size());
|
||||
let end = command.poke_into(self.data);
|
||||
ptr::write_bytes(end, 0, extended_end as usize - end as usize);
|
||||
self.data = extended_end;
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
self.data as usize - self.base as usize
|
||||
}
|
||||
|
||||
/// Recover the data vector of the pass, consuming `self`.
|
||||
unsafe fn into_vec(mut self) -> (Vec<u8>, P) {
|
||||
self.invalidate()
|
||||
}
|
||||
|
||||
/// Make pass contents invalid, return the contained data.
|
||||
///
|
||||
/// Any following access to the pass will result in a crash
|
||||
/// for accessing address 0.
|
||||
pub unsafe fn invalidate(&mut self) -> (Vec<u8>, P) {
|
||||
let size = self.size();
|
||||
assert!(
|
||||
size <= self.capacity,
|
||||
"Size of RawPass ({}) exceeds capacity ({})",
|
||||
size,
|
||||
self.capacity
|
||||
);
|
||||
let vec = Vec::from_raw_parts(self.base, size, self.capacity);
|
||||
self.data = ptr::null_mut();
|
||||
self.base = ptr::null_mut();
|
||||
self.capacity = 0;
|
||||
(vec, self.parent)
|
||||
}
|
||||
|
||||
unsafe fn ensure_extra_size(&mut self, extra_size: usize) {
|
||||
let size = self.size();
|
||||
if size + extra_size > self.capacity {
|
||||
let mut vec = Vec::from_raw_parts(self.base, size, self.capacity);
|
||||
vec.reserve(extra_size);
|
||||
//let (data, size, capacity) = vec.into_raw_parts(); //TODO: when stable
|
||||
self.data = vec.as_mut_ptr().add(vec.len());
|
||||
self.base = vec.as_mut_ptr();
|
||||
self.capacity = vec.capacity();
|
||||
mem::forget(vec);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) unsafe fn encode<C: peek_poke::Poke>(&mut self, command: &C) {
|
||||
self.ensure_extra_size(C::max_size());
|
||||
self.data = command.poke_into(self.data);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) unsafe fn encode_slice<T: Copy>(&mut self, data: &[T]) {
|
||||
let align_offset = self.data.align_offset(mem::align_of::<T>());
|
||||
let extra = align_offset + mem::size_of::<T>() * data.len();
|
||||
self.ensure_extra_size(extra);
|
||||
slice::from_raw_parts_mut(self.data.add(align_offset) as *mut T, data.len())
|
||||
.copy_from_slice(data);
|
||||
self.data = self.data.add(extra);
|
||||
}
|
||||
}
|
||||
use std::thread::ThreadId;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CommandBuffer<B: hal::Backend> {
|
||||
@ -209,48 +83,54 @@ impl<B: GfxBackend> CommandBuffer<B> {
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(PeekPoke)]
|
||||
struct PassComponent<T> {
|
||||
load_op: wgt::LoadOp,
|
||||
store_op: wgt::StoreOp,
|
||||
clear_value: T,
|
||||
read_only: bool,
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct BasePassRef<'a, C> {
|
||||
pub commands: &'a [C],
|
||||
pub dynamic_offsets: &'a [wgt::DynamicOffset],
|
||||
pub string_data: &'a [u8],
|
||||
}
|
||||
|
||||
// required for PeekPoke
|
||||
impl<T: Default> Default for PassComponent<T> {
|
||||
fn default() -> Self {
|
||||
PassComponent {
|
||||
load_op: wgt::LoadOp::Clear,
|
||||
store_op: wgt::StoreOp::Clear,
|
||||
clear_value: T::default(),
|
||||
read_only: false,
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(
|
||||
any(feature = "serial-pass", feature = "trace"),
|
||||
derive(serde::Serialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "serial-pass", feature = "replay"),
|
||||
derive(serde::Deserialize)
|
||||
)]
|
||||
pub struct BasePass<C> {
|
||||
pub commands: Vec<C>,
|
||||
pub dynamic_offsets: Vec<wgt::DynamicOffset>,
|
||||
pub string_data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<C: Clone> BasePass<C> {
|
||||
fn new() -> Self {
|
||||
BasePass {
|
||||
commands: Vec::new(),
|
||||
dynamic_offsets: Vec::new(),
|
||||
string_data: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, PeekPoke)]
|
||||
struct RawRenderPassColorAttachmentDescriptor {
|
||||
attachment: u64,
|
||||
resolve_target: u64,
|
||||
component: PassComponent<wgt::Color>,
|
||||
}
|
||||
#[cfg(feature = "trace")]
|
||||
fn from_ref(base: BasePassRef<C>) -> Self {
|
||||
BasePass {
|
||||
commands: base.commands.to_vec(),
|
||||
dynamic_offsets: base.dynamic_offsets.to_vec(),
|
||||
string_data: base.string_data.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, PeekPoke)]
|
||||
struct RawRenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: u64,
|
||||
depth: PassComponent<f32>,
|
||||
stencil: PassComponent<u32>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default, PeekPoke)]
|
||||
struct RawRenderTargets {
|
||||
colors: [RawRenderPassColorAttachmentDescriptor; MAX_COLOR_TARGETS],
|
||||
depth_stencil: RawRenderPassDepthStencilAttachmentDescriptor,
|
||||
pub fn as_ref(&self) -> BasePassRef<C> {
|
||||
BasePassRef {
|
||||
commands: &self.commands,
|
||||
dynamic_offsets: &self.dynamic_offsets,
|
||||
string_data: &self.string_data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
|
@ -5,8 +5,7 @@
|
||||
use crate::{
|
||||
command::{
|
||||
bind::{Binder, LayoutChange},
|
||||
PassComponent, PhantomSlice, RawPass, RawRenderPassColorAttachmentDescriptor,
|
||||
RawRenderPassDepthStencilAttachmentDescriptor, RawRenderTargets,
|
||||
BasePass, BasePassRef,
|
||||
},
|
||||
conv,
|
||||
device::{
|
||||
@ -23,54 +22,49 @@ use crate::{
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
use hal::command::CommandBuffer as _;
|
||||
use peek_poke::{Peek, PeekPoke, Poke};
|
||||
use wgt::{
|
||||
BufferAddress, BufferSize, BufferUsage, Color, DynamicOffset, IndexFormat, InputStepMode,
|
||||
LoadOp, RenderPassColorAttachmentDescriptorBase,
|
||||
RenderPassDepthStencilAttachmentDescriptorBase, StoreOp, TextureUsage, BIND_BUFFER_ALIGNMENT,
|
||||
BufferAddress, BufferSize, BufferUsage, Color, IndexFormat, InputStepMode, LoadOp,
|
||||
RenderPassColorAttachmentDescriptorBase, RenderPassDepthStencilAttachmentDescriptorBase,
|
||||
StoreOp, TextureUsage, BIND_BUFFER_ALIGNMENT,
|
||||
};
|
||||
|
||||
use std::{borrow::Borrow, collections::hash_map::Entry, fmt, iter, mem, ops::Range, slice, str};
|
||||
use std::{borrow::Borrow, collections::hash_map::Entry, fmt, iter, ops::Range, str};
|
||||
|
||||
pub type RenderPassColorAttachmentDescriptor =
|
||||
RenderPassColorAttachmentDescriptorBase<id::TextureViewId>;
|
||||
pub type RenderPassDepthStencilAttachmentDescriptor =
|
||||
pub type ColorAttachmentDescriptor = RenderPassColorAttachmentDescriptorBase<id::TextureViewId>;
|
||||
pub type DepthStencilAttachmentDescriptor =
|
||||
RenderPassDepthStencilAttachmentDescriptorBase<id::TextureViewId>;
|
||||
|
||||
fn is_depth_stencil_read_only(
|
||||
desc: &RenderPassDepthStencilAttachmentDescriptor,
|
||||
desc: &DepthStencilAttachmentDescriptor,
|
||||
aspects: hal::format::Aspects,
|
||||
) -> bool {
|
||||
if aspects.contains(hal::format::Aspects::DEPTH) && !desc.depth_read_only {
|
||||
if aspects.contains(hal::format::Aspects::DEPTH) && !desc.depth.read_only {
|
||||
return false;
|
||||
}
|
||||
assert_eq!(
|
||||
(desc.depth_load_op, desc.depth_store_op),
|
||||
(desc.depth.load_op, desc.depth.store_op),
|
||||
(LoadOp::Load, StoreOp::Store),
|
||||
"Unable to clear non-present/read-only depth"
|
||||
);
|
||||
if aspects.contains(hal::format::Aspects::STENCIL) && !desc.stencil_read_only {
|
||||
if aspects.contains(hal::format::Aspects::STENCIL) && !desc.stencil.read_only {
|
||||
return false;
|
||||
}
|
||||
assert_eq!(
|
||||
(desc.stencil_load_op, desc.stencil_store_op),
|
||||
(desc.stencil.load_op, desc.stencil.store_op),
|
||||
(LoadOp::Load, StoreOp::Store),
|
||||
"Unable to clear non-present/read-only stencil"
|
||||
);
|
||||
true
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct RenderPassDescriptor<'a> {
|
||||
pub color_attachments: *const RenderPassColorAttachmentDescriptor,
|
||||
pub color_attachments_length: usize,
|
||||
pub depth_stencil_attachment: Option<&'a RenderPassDepthStencilAttachmentDescriptor>,
|
||||
pub color_attachments: &'a [ColorAttachmentDescriptor],
|
||||
pub depth_stencil_attachment: Option<&'a DepthStencilAttachmentDescriptor>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PeekPoke)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct Rect<T> {
|
||||
pub x: T,
|
||||
pub y: T,
|
||||
@ -78,28 +72,33 @@ pub struct Rect<T> {
|
||||
pub h: T,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PeekPoke)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
#[doc(hidden)]
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(
|
||||
any(feature = "serial-pass", feature = "trace"),
|
||||
derive(serde::Serialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
any(feature = "serial-pass", feature = "replay"),
|
||||
derive(serde::Deserialize)
|
||||
)]
|
||||
pub enum RenderCommand {
|
||||
SetBindGroup {
|
||||
index: u8,
|
||||
num_dynamic_offsets: u8,
|
||||
bind_group_id: id::BindGroupId,
|
||||
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(skip))]
|
||||
phantom_offsets: PhantomSlice<DynamicOffset>,
|
||||
},
|
||||
SetPipeline(id::RenderPipelineId),
|
||||
SetIndexBuffer {
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
size: BufferSize,
|
||||
size: Option<BufferSize>,
|
||||
},
|
||||
SetVertexBuffer {
|
||||
slot: u32,
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
size: BufferSize,
|
||||
size: Option<BufferSize>,
|
||||
},
|
||||
SetBlendColor(Color),
|
||||
SetStencilReference(u32),
|
||||
@ -134,93 +133,35 @@ pub enum RenderCommand {
|
||||
PushDebugGroup {
|
||||
color: u32,
|
||||
len: usize,
|
||||
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(skip))]
|
||||
phantom_marker: PhantomSlice<u8>,
|
||||
},
|
||||
PopDebugGroup,
|
||||
InsertDebugMarker {
|
||||
color: u32,
|
||||
len: usize,
|
||||
#[cfg_attr(any(feature = "trace", feature = "replay"), serde(skip))]
|
||||
phantom_marker: PhantomSlice<u8>,
|
||||
},
|
||||
ExecuteBundle(id::RenderBundleId),
|
||||
End,
|
||||
}
|
||||
|
||||
// required for PeekPoke
|
||||
impl Default for RenderCommand {
|
||||
fn default() -> Self {
|
||||
RenderCommand::End
|
||||
}
|
||||
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct RenderPass {
|
||||
base: BasePass<RenderCommand>,
|
||||
parent_id: id::CommandEncoderId,
|
||||
color_targets: ArrayVec<[ColorAttachmentDescriptor; MAX_COLOR_TARGETS]>,
|
||||
depth_stencil_target: Option<DepthStencilAttachmentDescriptor>,
|
||||
}
|
||||
|
||||
impl RawPass<id::CommandEncoderId> {
|
||||
pub unsafe fn new_render(parent_id: id::CommandEncoderId, desc: &RenderPassDescriptor) -> Self {
|
||||
let mut pass = Self::new::<RenderCommand>(parent_id);
|
||||
|
||||
let mut targets: RawRenderTargets = mem::zeroed();
|
||||
if let Some(ds) = desc.depth_stencil_attachment {
|
||||
targets.depth_stencil = RawRenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: ds.attachment.into_raw(),
|
||||
depth: PassComponent {
|
||||
load_op: ds.depth_load_op,
|
||||
store_op: ds.depth_store_op,
|
||||
clear_value: ds.clear_depth,
|
||||
read_only: ds.depth_read_only,
|
||||
},
|
||||
stencil: PassComponent {
|
||||
load_op: ds.stencil_load_op,
|
||||
store_op: ds.stencil_store_op,
|
||||
clear_value: ds.clear_stencil,
|
||||
read_only: ds.stencil_read_only,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
for (color, at) in targets.colors.iter_mut().zip(slice::from_raw_parts(
|
||||
desc.color_attachments,
|
||||
desc.color_attachments_length,
|
||||
)) {
|
||||
*color = RawRenderPassColorAttachmentDescriptor {
|
||||
attachment: at.attachment.into_raw(),
|
||||
resolve_target: at.resolve_target.map_or(0, |id| id.into_raw()),
|
||||
component: PassComponent {
|
||||
load_op: at.load_op,
|
||||
store_op: at.store_op,
|
||||
clear_value: at.clear_color,
|
||||
read_only: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pass.encode(&targets);
|
||||
pass
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Copy> RawPass<P> {
|
||||
pub unsafe fn fill_render_commands(
|
||||
&mut self,
|
||||
commands: &[RenderCommand],
|
||||
mut offsets: &[DynamicOffset],
|
||||
) {
|
||||
for com in commands {
|
||||
self.encode(com);
|
||||
if let RenderCommand::SetBindGroup {
|
||||
num_dynamic_offsets,
|
||||
..
|
||||
} = *com
|
||||
{
|
||||
self.encode_slice(&offsets[..num_dynamic_offsets as usize]);
|
||||
offsets = &offsets[num_dynamic_offsets as usize..];
|
||||
}
|
||||
impl RenderPass {
|
||||
pub fn new(parent_id: id::CommandEncoderId, desc: RenderPassDescriptor) -> Self {
|
||||
RenderPass {
|
||||
base: BasePass::new(),
|
||||
parent_id,
|
||||
color_targets: desc.color_attachments.iter().cloned().collect(),
|
||||
depth_stencil_target: desc.depth_stencil_attachment.cloned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn finish_render(mut self) -> (Vec<u8>, P) {
|
||||
self.finish(RenderCommand::End);
|
||||
self.into_vec()
|
||||
pub fn parent_id(&self) -> id::CommandEncoderId {
|
||||
self.parent_id
|
||||
}
|
||||
}
|
||||
|
||||
@ -382,7 +323,23 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
pub fn command_encoder_run_render_pass<B: GfxBackend>(
|
||||
&self,
|
||||
encoder_id: id::CommandEncoderId,
|
||||
raw_data: &[u8],
|
||||
pass: &RenderPass,
|
||||
) {
|
||||
self.command_encoder_run_render_pass_impl::<B>(
|
||||
encoder_id,
|
||||
pass.base.as_ref(),
|
||||
&pass.color_targets,
|
||||
pass.depth_stencil_target.as_ref(),
|
||||
)
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn command_encoder_run_render_pass_impl<B: GfxBackend>(
|
||||
&self,
|
||||
encoder_id: id::CommandEncoderId,
|
||||
mut base: BasePassRef<RenderCommand>,
|
||||
color_attachments: &[ColorAttachmentDescriptor],
|
||||
depth_stencil_attachment: Option<&DepthStencilAttachmentDescriptor>,
|
||||
) {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
@ -395,6 +352,18 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let device = &device_guard[cmb.device_id.value];
|
||||
let mut raw = device.com_allocator.extend(cmb);
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
match cmb.commands {
|
||||
Some(ref mut list) => {
|
||||
list.push(crate::device::trace::Command::RunRenderPass {
|
||||
base: BasePass::from_ref(base),
|
||||
target_colors: color_attachments.iter().cloned().collect(),
|
||||
target_depth_stencil: depth_stencil_attachment.cloned(),
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
raw.begin_primary(hal::command::CommandBufferFlags::ONE_TIME_SUBMIT);
|
||||
}
|
||||
@ -407,50 +376,6 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let (texture_guard, mut token) = hub.textures.read(&mut token);
|
||||
let (view_guard, _) = hub.texture_views.read(&mut token);
|
||||
|
||||
let mut peeker = raw_data.as_ptr();
|
||||
let raw_data_end = unsafe { raw_data.as_ptr().add(raw_data.len()) };
|
||||
|
||||
let mut targets: RawRenderTargets = unsafe { mem::zeroed() };
|
||||
assert!(
|
||||
unsafe { peeker.add(RawRenderTargets::max_size()) <= raw_data_end },
|
||||
"RawRenderTargets (size {}) is too big to fit within raw_data (size {})",
|
||||
RawRenderTargets::max_size(),
|
||||
raw_data.len()
|
||||
);
|
||||
peeker = unsafe { RawRenderTargets::peek_from(peeker, &mut targets) };
|
||||
#[cfg(feature = "trace")]
|
||||
let command_peeker_base = peeker;
|
||||
|
||||
let color_attachments = targets
|
||||
.colors
|
||||
.iter()
|
||||
.take_while(|at| at.attachment != 0)
|
||||
.map(|at| RenderPassColorAttachmentDescriptor {
|
||||
attachment: id::TextureViewId::from_raw(at.attachment).unwrap(),
|
||||
resolve_target: id::TextureViewId::from_raw(at.resolve_target),
|
||||
load_op: at.component.load_op,
|
||||
store_op: at.component.store_op,
|
||||
clear_color: at.component.clear_value,
|
||||
})
|
||||
.collect::<ArrayVec<[_; MAX_COLOR_TARGETS]>>();
|
||||
let depth_stencil_attachment_body;
|
||||
let depth_stencil_attachment = if targets.depth_stencil.attachment == 0 {
|
||||
None
|
||||
} else {
|
||||
let at = &targets.depth_stencil;
|
||||
depth_stencil_attachment_body = RenderPassDepthStencilAttachmentDescriptor {
|
||||
attachment: id::TextureViewId::from_raw(at.attachment).unwrap(),
|
||||
depth_load_op: at.depth.load_op,
|
||||
depth_store_op: at.depth.store_op,
|
||||
depth_read_only: at.depth.read_only,
|
||||
clear_depth: at.depth.clear_value,
|
||||
stencil_load_op: at.stencil.load_op,
|
||||
stencil_store_op: at.stencil.store_op,
|
||||
clear_stencil: at.stencil.clear_value,
|
||||
stencil_read_only: at.stencil.read_only,
|
||||
};
|
||||
Some(&depth_stencil_attachment_body)
|
||||
};
|
||||
// We default to false intentionally, even if depth-stencil isn't used at all.
|
||||
// This allows us to use the primary raw pipeline in `RenderPipeline`,
|
||||
// instead of the special read-only one, which would be `None`.
|
||||
@ -535,11 +460,8 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
device.private_features,
|
||||
)),
|
||||
samples: view.samples,
|
||||
ops: conv::map_load_store_ops(at.depth_load_op, at.depth_store_op),
|
||||
stencil_ops: conv::map_load_store_ops(
|
||||
at.stencil_load_op,
|
||||
at.stencil_store_op,
|
||||
),
|
||||
ops: conv::map_load_store_ops(&at.depth),
|
||||
stencil_ops: conv::map_load_store_ops(&at.stencil),
|
||||
layouts: old_layout..new_layout,
|
||||
};
|
||||
Some((ds_at, new_layout))
|
||||
@ -550,7 +472,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
let mut colors = ArrayVec::new();
|
||||
let mut resolves = ArrayVec::new();
|
||||
|
||||
for at in &color_attachments {
|
||||
for at in color_attachments {
|
||||
let view = trackers
|
||||
.views
|
||||
.use_extend(&*view_guard, at.attachment, (), ())
|
||||
@ -600,7 +522,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
|
||||
let end = hal::image::Layout::Present;
|
||||
let start = match at.load_op {
|
||||
let start = match at.channel.load_op {
|
||||
LoadOp::Clear => hal::image::Layout::Undefined,
|
||||
LoadOp::Load => end,
|
||||
};
|
||||
@ -614,7 +536,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
device.private_features,
|
||||
)),
|
||||
samples: view.samples,
|
||||
ops: conv::map_load_store_ops(at.load_op, at.store_op),
|
||||
ops: conv::map_load_store_ops(&at.channel),
|
||||
stencil_ops: hal::pass::AttachmentOps::DONT_CARE,
|
||||
layouts,
|
||||
};
|
||||
@ -835,7 +757,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
.iter()
|
||||
.zip(&rp_key.colors)
|
||||
.flat_map(|(at, (rat, _layout))| {
|
||||
match at.load_op {
|
||||
match at.channel.load_op {
|
||||
LoadOp::Load => None,
|
||||
LoadOp::Clear => {
|
||||
use hal::format::ChannelType;
|
||||
@ -848,13 +770,13 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
| ChannelType::Uscaled
|
||||
| ChannelType::Sscaled
|
||||
| ChannelType::Srgb => hal::command::ClearColor {
|
||||
float32: conv::map_color_f32(&at.clear_color),
|
||||
float32: conv::map_color_f32(&at.channel.clear_value),
|
||||
},
|
||||
ChannelType::Sint => hal::command::ClearColor {
|
||||
sint32: conv::map_color_i32(&at.clear_color),
|
||||
sint32: conv::map_color_i32(&at.channel.clear_value),
|
||||
},
|
||||
ChannelType::Uint => hal::command::ClearColor {
|
||||
uint32: conv::map_color_u32(&at.clear_color),
|
||||
uint32: conv::map_color_u32(&at.channel.clear_value),
|
||||
},
|
||||
};
|
||||
Some(hal::command::ClearValue { color: value })
|
||||
@ -862,12 +784,12 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
})
|
||||
.chain(depth_stencil_attachment.and_then(|at| {
|
||||
match (at.depth_load_op, at.stencil_load_op) {
|
||||
match (at.depth.load_op, at.stencil.load_op) {
|
||||
(LoadOp::Load, LoadOp::Load) => None,
|
||||
(LoadOp::Clear, _) | (_, LoadOp::Clear) => {
|
||||
let value = hal::command::ClearDepthStencil {
|
||||
depth: at.clear_depth,
|
||||
stencil: at.clear_stencil,
|
||||
depth: at.depth.clear_value,
|
||||
stencil: at.stencil.clear_value,
|
||||
};
|
||||
Some(hal::command::ClearValue {
|
||||
depth_stencil: value,
|
||||
@ -922,46 +844,23 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
debug_scope_depth: 0,
|
||||
};
|
||||
|
||||
let mut command = RenderCommand::Draw {
|
||||
vertex_count: 0,
|
||||
instance_count: 0,
|
||||
first_vertex: 0,
|
||||
first_instance: 0,
|
||||
};
|
||||
loop {
|
||||
assert!(
|
||||
unsafe { peeker.add(RenderCommand::max_size()) <= raw_data_end },
|
||||
"RenderCommand (size {}) is too big to fit within raw_data (size {})",
|
||||
RenderCommand::max_size(),
|
||||
raw_data.len()
|
||||
);
|
||||
peeker = unsafe { RenderCommand::peek_from(peeker, &mut command) };
|
||||
match command {
|
||||
for command in base.commands {
|
||||
match *command {
|
||||
RenderCommand::SetBindGroup {
|
||||
index,
|
||||
num_dynamic_offsets,
|
||||
bind_group_id,
|
||||
phantom_offsets,
|
||||
} => {
|
||||
let (new_peeker, offsets) = unsafe {
|
||||
phantom_offsets.decode_unaligned(
|
||||
peeker,
|
||||
num_dynamic_offsets as usize,
|
||||
raw_data_end,
|
||||
)
|
||||
};
|
||||
peeker = new_peeker;
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
for off in offsets {
|
||||
assert_eq!(
|
||||
*off as BufferAddress % BIND_BUFFER_ALIGNMENT,
|
||||
0,
|
||||
"Misaligned dynamic buffer offset: {} does not align with {}",
|
||||
off,
|
||||
BIND_BUFFER_ALIGNMENT
|
||||
);
|
||||
}
|
||||
let offsets = &base.dynamic_offsets[..num_dynamic_offsets as usize];
|
||||
base.dynamic_offsets = &base.dynamic_offsets[num_dynamic_offsets as usize..];
|
||||
for off in offsets {
|
||||
assert_eq!(
|
||||
*off as BufferAddress % BIND_BUFFER_ALIGNMENT,
|
||||
0,
|
||||
"Misaligned dynamic buffer offset: {} does not align with {}",
|
||||
off,
|
||||
BIND_BUFFER_ALIGNMENT
|
||||
);
|
||||
}
|
||||
|
||||
let bind_group = trackers
|
||||
@ -1110,10 +1009,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
.unwrap();
|
||||
assert!(buffer.usage.contains(BufferUsage::INDEX), "An invalid setIndexBuffer call has been made. The buffer usage is {:?} which does not contain required usage INDEX", buffer.usage);
|
||||
|
||||
let end = if size != BufferSize::WHOLE {
|
||||
offset + size.0
|
||||
} else {
|
||||
buffer.size
|
||||
let end = match size {
|
||||
Some(s) => offset + s.get(),
|
||||
None => buffer.size,
|
||||
};
|
||||
state.index.bound_buffer_view = Some((buffer_id, offset..end));
|
||||
state.index.update_limit();
|
||||
@ -1147,19 +1045,14 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
.vertex
|
||||
.inputs
|
||||
.extend(iter::repeat(VertexBufferState::EMPTY).take(empty_slots));
|
||||
state.vertex.inputs[slot as usize].total_size = if size != BufferSize::WHOLE {
|
||||
size.0
|
||||
} else {
|
||||
buffer.size - offset
|
||||
state.vertex.inputs[slot as usize].total_size = match size {
|
||||
Some(s) => s.get(),
|
||||
None => buffer.size - offset,
|
||||
};
|
||||
|
||||
let range = hal::buffer::SubRange {
|
||||
offset,
|
||||
size: if size != BufferSize::WHOLE {
|
||||
Some(size.0)
|
||||
} else {
|
||||
None
|
||||
},
|
||||
size: size.map(|s| s.get()),
|
||||
};
|
||||
unsafe {
|
||||
raw.bind_vertex_buffers(slot, iter::once((&buffer.raw, range)));
|
||||
@ -1296,39 +1189,30 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
raw.draw_indexed_indirect(&buffer.raw, offset, 1, 0);
|
||||
}
|
||||
}
|
||||
RenderCommand::PushDebugGroup {
|
||||
color,
|
||||
len,
|
||||
phantom_marker,
|
||||
} => unsafe {
|
||||
RenderCommand::PushDebugGroup { color, len } => {
|
||||
state.debug_scope_depth += 1;
|
||||
|
||||
let (new_peeker, label) =
|
||||
{ phantom_marker.decode_unaligned(peeker, len, raw_data_end) };
|
||||
peeker = new_peeker;
|
||||
|
||||
raw.begin_debug_marker(str::from_utf8(label).unwrap(), color)
|
||||
},
|
||||
RenderCommand::PopDebugGroup => unsafe {
|
||||
let label = str::from_utf8(&base.string_data[..len]).unwrap();
|
||||
unsafe {
|
||||
raw.begin_debug_marker(label, color);
|
||||
}
|
||||
base.string_data = &base.string_data[len..];
|
||||
}
|
||||
RenderCommand::PopDebugGroup => {
|
||||
assert_ne!(
|
||||
state.debug_scope_depth, 0,
|
||||
"Can't pop debug group, because number of pushed debug groups is zero!"
|
||||
);
|
||||
state.debug_scope_depth -= 1;
|
||||
|
||||
raw.end_debug_marker()
|
||||
},
|
||||
RenderCommand::InsertDebugMarker {
|
||||
color,
|
||||
len,
|
||||
phantom_marker,
|
||||
} => unsafe {
|
||||
let (new_peeker, label) =
|
||||
{ phantom_marker.decode_unaligned(peeker, len, raw_data_end) };
|
||||
peeker = new_peeker;
|
||||
|
||||
raw.insert_debug_marker(str::from_utf8(label).unwrap(), color)
|
||||
},
|
||||
unsafe {
|
||||
raw.end_debug_marker();
|
||||
}
|
||||
}
|
||||
RenderCommand::InsertDebugMarker { color, len } => {
|
||||
let label = str::from_utf8(&base.string_data[..len]).unwrap();
|
||||
unsafe {
|
||||
raw.insert_debug_marker(label, color);
|
||||
}
|
||||
}
|
||||
RenderCommand::ExecuteBundle(bundle_id) => {
|
||||
let bundle = trackers
|
||||
.bundles
|
||||
@ -1353,49 +1237,9 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
trackers.merge_extend(&bundle.used);
|
||||
state.reset_bundle();
|
||||
}
|
||||
RenderCommand::End => break,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
match cmb.commands {
|
||||
Some(ref mut list) => {
|
||||
let mut pass_commands = Vec::new();
|
||||
let mut pass_dynamic_offsets = Vec::new();
|
||||
peeker = command_peeker_base;
|
||||
loop {
|
||||
peeker = unsafe { RenderCommand::peek_from(peeker, &mut command) };
|
||||
match command {
|
||||
RenderCommand::SetBindGroup {
|
||||
num_dynamic_offsets,
|
||||
phantom_offsets,
|
||||
..
|
||||
} => {
|
||||
let (new_peeker, offsets) = unsafe {
|
||||
phantom_offsets.decode_unaligned(
|
||||
peeker,
|
||||
num_dynamic_offsets as usize,
|
||||
raw_data_end,
|
||||
)
|
||||
};
|
||||
peeker = new_peeker;
|
||||
pass_dynamic_offsets.extend_from_slice(offsets);
|
||||
}
|
||||
RenderCommand::End => break,
|
||||
_ => {}
|
||||
}
|
||||
pass_commands.push(command);
|
||||
}
|
||||
list.push(crate::device::trace::Command::RunRenderPass {
|
||||
target_colors: color_attachments.into_iter().collect(),
|
||||
target_depth_stencil: depth_stencil_attachment.cloned(),
|
||||
commands: pass_commands,
|
||||
dynamic_offsets: pass_dynamic_offsets,
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
log::trace!("Merging {:?} with the render pass", encoder_id);
|
||||
unsafe {
|
||||
raw.end_render_pass();
|
||||
@ -1451,16 +1295,11 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
}
|
||||
|
||||
pub mod render_ffi {
|
||||
use super::{
|
||||
super::{PhantomSlice, Rect},
|
||||
RenderCommand,
|
||||
};
|
||||
use super::{super::Rect, RenderCommand, RenderPass};
|
||||
use crate::{id, RawString};
|
||||
use std::{convert::TryInto, ffi, slice};
|
||||
use wgt::{BufferAddress, BufferSize, Color, DynamicOffset};
|
||||
|
||||
type RawPass = super::super::RawPass<id::CommandEncoderId>;
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is unsafe as there is no guarantee that the given pointer is
|
||||
@ -1469,37 +1308,40 @@ pub mod render_ffi {
|
||||
// `RawPass::encode` and `RawPass::encode_slice`.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_set_bind_group(
|
||||
pass: &mut RawPass,
|
||||
pass: &mut RenderPass,
|
||||
index: u32,
|
||||
bind_group_id: id::BindGroupId,
|
||||
offsets: *const DynamicOffset,
|
||||
offset_length: usize,
|
||||
) {
|
||||
pass.encode(&RenderCommand::SetBindGroup {
|
||||
pass.base.commands.push(RenderCommand::SetBindGroup {
|
||||
index: index.try_into().unwrap(),
|
||||
num_dynamic_offsets: offset_length.try_into().unwrap(),
|
||||
bind_group_id,
|
||||
phantom_offsets: PhantomSlice::default(),
|
||||
});
|
||||
pass.encode_slice(slice::from_raw_parts(offsets, offset_length));
|
||||
pass.base
|
||||
.dynamic_offsets
|
||||
.extend_from_slice(slice::from_raw_parts(offsets, offset_length));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_set_pipeline(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_render_pass_set_pipeline(
|
||||
pass: &mut RenderPass,
|
||||
pipeline_id: id::RenderPipelineId,
|
||||
) {
|
||||
pass.encode(&RenderCommand::SetPipeline(pipeline_id));
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::SetPipeline(pipeline_id));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_set_index_buffer(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_render_pass_set_index_buffer(
|
||||
pass: &mut RenderPass,
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
size: BufferSize,
|
||||
size: Option<BufferSize>,
|
||||
) {
|
||||
pass.encode(&RenderCommand::SetIndexBuffer {
|
||||
pass.base.commands.push(RenderCommand::SetIndexBuffer {
|
||||
buffer_id,
|
||||
offset,
|
||||
size,
|
||||
@ -1507,14 +1349,14 @@ pub mod render_ffi {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_set_vertex_buffer(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_render_pass_set_vertex_buffer(
|
||||
pass: &mut RenderPass,
|
||||
slot: u32,
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
size: BufferSize,
|
||||
size: Option<BufferSize>,
|
||||
) {
|
||||
pass.encode(&RenderCommand::SetVertexBuffer {
|
||||
pass.base.commands.push(RenderCommand::SetVertexBuffer {
|
||||
slot,
|
||||
buffer_id,
|
||||
offset,
|
||||
@ -1523,21 +1365,22 @@ pub mod render_ffi {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_set_blend_color(pass: &mut RawPass, color: &Color) {
|
||||
pass.encode(&RenderCommand::SetBlendColor(*color));
|
||||
pub extern "C" fn wgpu_render_pass_set_blend_color(pass: &mut RenderPass, color: &Color) {
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::SetBlendColor(*color));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_set_stencil_reference(
|
||||
pass: &mut RawPass,
|
||||
value: u32,
|
||||
) {
|
||||
pass.encode(&RenderCommand::SetStencilReference(value));
|
||||
pub extern "C" fn wgpu_render_pass_set_stencil_reference(pass: &mut RenderPass, value: u32) {
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::SetStencilReference(value));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_set_viewport(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_render_pass_set_viewport(
|
||||
pass: &mut RenderPass,
|
||||
x: f32,
|
||||
y: f32,
|
||||
w: f32,
|
||||
@ -1545,7 +1388,7 @@ pub mod render_ffi {
|
||||
depth_min: f32,
|
||||
depth_max: f32,
|
||||
) {
|
||||
pass.encode(&RenderCommand::SetViewport {
|
||||
pass.base.commands.push(RenderCommand::SetViewport {
|
||||
rect: Rect { x, y, w, h },
|
||||
depth_min,
|
||||
depth_max,
|
||||
@ -1553,25 +1396,27 @@ pub mod render_ffi {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_set_scissor_rect(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_render_pass_set_scissor_rect(
|
||||
pass: &mut RenderPass,
|
||||
x: u32,
|
||||
y: u32,
|
||||
w: u32,
|
||||
h: u32,
|
||||
) {
|
||||
pass.encode(&RenderCommand::SetScissor(Rect { x, y, w, h }));
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::SetScissor(Rect { x, y, w, h }));
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_draw(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_render_pass_draw(
|
||||
pass: &mut RenderPass,
|
||||
vertex_count: u32,
|
||||
instance_count: u32,
|
||||
first_vertex: u32,
|
||||
first_instance: u32,
|
||||
) {
|
||||
pass.encode(&RenderCommand::Draw {
|
||||
pass.base.commands.push(RenderCommand::Draw {
|
||||
vertex_count,
|
||||
instance_count,
|
||||
first_vertex,
|
||||
@ -1580,15 +1425,15 @@ pub mod render_ffi {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_draw_indexed(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_render_pass_draw_indexed(
|
||||
pass: &mut RenderPass,
|
||||
index_count: u32,
|
||||
instance_count: u32,
|
||||
first_index: u32,
|
||||
base_vertex: i32,
|
||||
first_instance: u32,
|
||||
) {
|
||||
pass.encode(&RenderCommand::DrawIndexed {
|
||||
pass.base.commands.push(RenderCommand::DrawIndexed {
|
||||
index_count,
|
||||
instance_count,
|
||||
first_index,
|
||||
@ -1598,78 +1443,72 @@ pub mod render_ffi {
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_draw_indirect(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_render_pass_draw_indirect(
|
||||
pass: &mut RenderPass,
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
) {
|
||||
pass.encode(&RenderCommand::DrawIndirect { buffer_id, offset });
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::DrawIndirect { buffer_id, offset });
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_draw_indexed_indirect(
|
||||
pass: &mut RawPass,
|
||||
pub extern "C" fn wgpu_render_pass_draw_indexed_indirect(
|
||||
pass: &mut RenderPass,
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
) {
|
||||
pass.encode(&RenderCommand::DrawIndexedIndirect { buffer_id, offset });
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::DrawIndexedIndirect { buffer_id, offset });
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_push_debug_group(
|
||||
pass: &mut RawPass,
|
||||
pass: &mut RenderPass,
|
||||
label: RawString,
|
||||
color: u32,
|
||||
) {
|
||||
let bytes = ffi::CStr::from_ptr(label).to_bytes();
|
||||
pass.base.string_data.extend_from_slice(bytes);
|
||||
|
||||
pass.encode(&RenderCommand::PushDebugGroup {
|
||||
pass.base.commands.push(RenderCommand::PushDebugGroup {
|
||||
color,
|
||||
len: bytes.len(),
|
||||
phantom_marker: PhantomSlice::default(),
|
||||
});
|
||||
pass.encode_slice(bytes);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_pop_debug_group(pass: &mut RawPass) {
|
||||
pass.encode(&RenderCommand::PopDebugGroup);
|
||||
pub extern "C" fn wgpu_render_pass_pop_debug_group(pass: &mut RenderPass) {
|
||||
pass.base.commands.push(RenderCommand::PopDebugGroup);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_insert_debug_marker(
|
||||
pass: &mut RawPass,
|
||||
pass: &mut RenderPass,
|
||||
label: RawString,
|
||||
color: u32,
|
||||
) {
|
||||
let bytes = ffi::CStr::from_ptr(label).to_bytes();
|
||||
pass.base.string_data.extend_from_slice(bytes);
|
||||
|
||||
pass.encode(&RenderCommand::InsertDebugMarker {
|
||||
pass.base.commands.push(RenderCommand::InsertDebugMarker {
|
||||
color,
|
||||
len: bytes.len(),
|
||||
phantom_marker: PhantomSlice::default(),
|
||||
});
|
||||
pass.encode_slice(bytes);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe fn wgpu_render_pass_execute_bundles(
|
||||
pass: &mut RawPass,
|
||||
pass: &mut RenderPass,
|
||||
render_bundle_ids: *const id::RenderBundleId,
|
||||
render_bundle_ids_length: usize,
|
||||
) {
|
||||
for &bundle_id in slice::from_raw_parts(render_bundle_ids, render_bundle_ids_length) {
|
||||
pass.encode(&RenderCommand::ExecuteBundle(bundle_id));
|
||||
pass.base
|
||||
.commands
|
||||
.push(RenderCommand::ExecuteBundle(bundle_id));
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn wgpu_render_pass_finish(
|
||||
pass: &mut RawPass,
|
||||
length: &mut usize,
|
||||
) -> *const u8 {
|
||||
pass.finish(RenderCommand::End);
|
||||
*length = pass.size();
|
||||
pass.base
|
||||
}
|
||||
}
|
||||
|
@ -574,13 +574,13 @@ pub(crate) fn map_texture_state(
|
||||
(access, layout)
|
||||
}
|
||||
|
||||
pub fn map_load_store_ops(load: wgt::LoadOp, store: wgt::StoreOp) -> hal::pass::AttachmentOps {
|
||||
pub fn map_load_store_ops<V>(channel: &wgt::PassChannel<V>) -> hal::pass::AttachmentOps {
|
||||
hal::pass::AttachmentOps {
|
||||
load: match load {
|
||||
load: match channel.load_op {
|
||||
wgt::LoadOp::Clear => hal::pass::AttachmentLoadOp::Clear,
|
||||
wgt::LoadOp::Load => hal::pass::AttachmentLoadOp::Load,
|
||||
},
|
||||
store: match store {
|
||||
store: match channel.store_op {
|
||||
wgt::StoreOp::Clear => hal::pass::AttachmentStoreOp::DontCare, //TODO!
|
||||
wgt::StoreOp::Store => hal::pass::AttachmentStoreOp::Store,
|
||||
},
|
||||
|
@ -86,6 +86,7 @@ pub enum HostMap {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq)]
|
||||
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub(crate) struct AttachmentData<T> {
|
||||
pub colors: ArrayVec<[T; MAX_COLOR_TARGETS]>,
|
||||
pub resolves: ArrayVec<[T; MAX_COLOR_TARGETS]>,
|
||||
@ -105,6 +106,7 @@ pub(crate) type RenderPassKey = AttachmentData<(hal::pass::Attachment, hal::imag
|
||||
pub(crate) type FramebufferKey = AttachmentData<id::TextureViewId>;
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq)]
|
||||
#[cfg_attr(feature = "serial-pass", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub(crate) struct RenderPassContext {
|
||||
pub attachments: AttachmentData<TextureFormat>,
|
||||
pub sample_count: u8,
|
||||
@ -1492,17 +1494,18 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
buffer.usage,
|
||||
pub_usage
|
||||
);
|
||||
let bind_size = if bb.size == BufferSize::WHOLE {
|
||||
buffer.size - bb.offset
|
||||
} else {
|
||||
let end = bb.offset + bb.size.0;
|
||||
assert!(
|
||||
end <= buffer.size,
|
||||
"Bound buffer range {:?} does not fit in buffer size {}",
|
||||
bb.offset..end,
|
||||
buffer.size
|
||||
);
|
||||
bb.size.0
|
||||
let bind_size = match bb.size {
|
||||
Some(size) => {
|
||||
let end = bb.offset + size.get();
|
||||
assert!(
|
||||
end <= buffer.size,
|
||||
"Bound buffer range {:?} does not fit in buffer size {}",
|
||||
bb.offset..end,
|
||||
buffer.size
|
||||
);
|
||||
size.get()
|
||||
}
|
||||
None => buffer.size - bb.offset,
|
||||
};
|
||||
match min_size {
|
||||
Some(non_zero) if non_zero.get() > bind_size => panic!(
|
||||
@ -1919,17 +1922,10 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
device_id: id::DeviceId,
|
||||
desc: &wgt::RenderBundleEncoderDescriptor,
|
||||
) -> id::RenderBundleEncoderId {
|
||||
let encoder = command::RenderBundleEncoder::new(desc, device_id);
|
||||
let encoder = command::RenderBundleEncoder::new(desc, device_id, None);
|
||||
Box::into_raw(Box::new(encoder))
|
||||
}
|
||||
|
||||
pub fn render_bundle_encoder_destroy(
|
||||
&self,
|
||||
render_bundle_encoder: command::RenderBundleEncoder,
|
||||
) {
|
||||
render_bundle_encoder.destroy();
|
||||
}
|
||||
|
||||
pub fn render_bundle_destroy<B: GfxBackend>(&self, render_bundle_id: id::RenderBundleId) {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
@ -2732,7 +2728,7 @@ impl<G: GlobalIdentityHandlerFactory> Global<G> {
|
||||
&self,
|
||||
buffer_id: id::BufferId,
|
||||
offset: BufferAddress,
|
||||
_size: BufferSize,
|
||||
_size: Option<BufferSize>,
|
||||
) -> *mut u8 {
|
||||
let hub = B::hub(self);
|
||||
let mut token = Token::root();
|
||||
|
@ -20,7 +20,7 @@ pub enum BindingResource {
|
||||
Buffer {
|
||||
id: id::BufferId,
|
||||
offset: wgt::BufferAddress,
|
||||
size: wgt::BufferSize,
|
||||
size: Option<wgt::BufferSize>,
|
||||
},
|
||||
Sampler(id::SamplerId),
|
||||
TextureView(id::TextureViewId),
|
||||
@ -185,8 +185,7 @@ pub enum Action {
|
||||
CreateRenderBundle {
|
||||
id: id::RenderBundleId,
|
||||
desc: RenderBundleDescriptor,
|
||||
commands: Vec<crate::command::RenderCommand>,
|
||||
dynamic_offsets: Vec<wgt::DynamicOffset>,
|
||||
base: crate::command::BasePass<crate::command::RenderCommand>,
|
||||
},
|
||||
DestroyRenderBundle(id::RenderBundleId),
|
||||
WriteBuffer {
|
||||
@ -231,14 +230,12 @@ pub enum Command {
|
||||
size: wgt::Extent3d,
|
||||
},
|
||||
RunComputePass {
|
||||
commands: Vec<crate::command::ComputeCommand>,
|
||||
dynamic_offsets: Vec<wgt::DynamicOffset>,
|
||||
base: crate::command::BasePass<crate::command::ComputeCommand>,
|
||||
},
|
||||
RunRenderPass {
|
||||
target_colors: Vec<crate::command::RenderPassColorAttachmentDescriptor>,
|
||||
target_depth_stencil: Option<crate::command::RenderPassDepthStencilAttachmentDescriptor>,
|
||||
commands: Vec<crate::command::RenderCommand>,
|
||||
dynamic_offsets: Vec<wgt::DynamicOffset>,
|
||||
base: crate::command::BasePass<crate::command::RenderCommand>,
|
||||
target_colors: Vec<crate::command::ColorAttachmentDescriptor>,
|
||||
target_depth_stencil: Option<crate::command::DepthStencilAttachmentDescriptor>,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::{Epoch, Index};
|
||||
use std::{fmt, marker::PhantomData, mem, num::NonZeroU64};
|
||||
use std::{fmt, marker::PhantomData, num::NonZeroU64};
|
||||
use wgt::Backend;
|
||||
|
||||
const BACKEND_BITS: usize = 3;
|
||||
@ -17,6 +17,14 @@ type Dummy = crate::backend::Empty;
|
||||
derive(serde::Deserialize),
|
||||
serde(from = "SerialId")
|
||||
)]
|
||||
#[cfg_attr(
|
||||
all(feature = "serde", not(feature = "trace")),
|
||||
derive(serde::Serialize)
|
||||
)]
|
||||
#[cfg_attr(
|
||||
all(feature = "serde", not(feature = "replay")),
|
||||
derive(serde::Deserialize)
|
||||
)]
|
||||
pub struct Id<T>(NonZeroU64, PhantomData<T>);
|
||||
|
||||
// This type represents Id in a more readable (and editable) way.
|
||||
@ -43,20 +51,12 @@ impl<T> From<SerialId> for Id<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// required for PeekPoke
|
||||
impl<T> Default for Id<T> {
|
||||
fn default() -> Self {
|
||||
Id(
|
||||
// Create an ID that doesn't make sense:
|
||||
// the high `BACKEND_BITS` are to be set to 0, which matches `Backend::Empty`,
|
||||
// the other bits are all 1s
|
||||
unsafe { NonZeroU64::new_unchecked(!0 >> BACKEND_BITS) },
|
||||
PhantomData,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Id<T> {
|
||||
#[cfg(test)]
|
||||
pub(crate) fn dummy() -> Self {
|
||||
Id(NonZeroU64::new(1).unwrap(), PhantomData)
|
||||
}
|
||||
|
||||
pub fn backend(self) -> Backend {
|
||||
match self.0.get() >> (64 - BACKEND_BITS) as u8 {
|
||||
0 => Backend::Empty,
|
||||
@ -68,14 +68,6 @@ impl<T> Id<T> {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_raw(self) -> u64 {
|
||||
self.0.get()
|
||||
}
|
||||
|
||||
pub(crate) fn from_raw(value: u64) -> Option<Self> {
|
||||
NonZeroU64::new(value).map(|nz| Id(nz, PhantomData))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Copy for Id<T> {}
|
||||
@ -106,24 +98,6 @@ impl<T> PartialEq for Id<T> {
|
||||
|
||||
impl<T> Eq for Id<T> {}
|
||||
|
||||
unsafe impl<T> peek_poke::Poke for Id<T> {
|
||||
fn max_size() -> usize {
|
||||
mem::size_of::<u64>()
|
||||
}
|
||||
unsafe fn poke_into(&self, data: *mut u8) -> *mut u8 {
|
||||
self.0.get().poke_into(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> peek_poke::Peek for Id<T> {
|
||||
unsafe fn peek_from(mut data: *const u8, this: *mut Self) -> *const u8 {
|
||||
let mut v = 0u64;
|
||||
data = u64::peek_from(data, &mut v);
|
||||
(*this).0 = NonZeroU64::new(v).unwrap();
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TypedId {
|
||||
fn zip(index: Index, epoch: Epoch, backend: Backend) -> Self;
|
||||
fn unzip(self) -> (Index, Epoch, Backend);
|
||||
@ -166,8 +140,8 @@ pub type ComputePipelineId = Id<crate::pipeline::ComputePipeline<Dummy>>;
|
||||
// Command
|
||||
pub type CommandEncoderId = CommandBufferId;
|
||||
pub type CommandBufferId = Id<crate::command::CommandBuffer<Dummy>>;
|
||||
pub type RenderPassId = *mut crate::command::RawPass<CommandEncoderId>;
|
||||
pub type ComputePassId = *mut crate::command::RawPass<CommandEncoderId>;
|
||||
pub type RenderPassEncoderId = *mut crate::command::RenderPass;
|
||||
pub type ComputePassEncoderId = *mut crate::command::ComputePass;
|
||||
pub type RenderBundleEncoderId = *mut crate::command::RenderBundleEncoder;
|
||||
pub type RenderBundleId = Id<crate::command::RenderBundle>;
|
||||
// Swap chain
|
||||
|
@ -150,7 +150,7 @@ mod test {
|
||||
first: None,
|
||||
last: BufferUse::INDEX,
|
||||
};
|
||||
let id = Id::default();
|
||||
let id = Id::dummy();
|
||||
assert_eq!(
|
||||
bs.change(id, (), BufferUse::STORAGE_STORE, None),
|
||||
Err(PendingTransition {
|
||||
@ -170,7 +170,7 @@ mod test {
|
||||
first: None,
|
||||
last: BufferUse::STORAGE_STORE,
|
||||
};
|
||||
let id = Id::default();
|
||||
let id = Id::dummy();
|
||||
let mut list = Vec::new();
|
||||
bs.change(id, (), BufferUse::VERTEX, Some(&mut list))
|
||||
.unwrap();
|
||||
@ -216,7 +216,7 @@ mod test {
|
||||
first: None,
|
||||
last: BufferUse::VERTEX,
|
||||
};
|
||||
let id = Id::default();
|
||||
let id = Id::dummy();
|
||||
bs.prepend(id, (), BufferUse::INDEX).unwrap();
|
||||
bs.prepend(id, (), BufferUse::INDEX).unwrap();
|
||||
assert_eq!(
|
||||
|
@ -324,7 +324,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn merge() {
|
||||
let id = Id::default();
|
||||
let id = Id::dummy();
|
||||
let mut ts1 = TextureState::default();
|
||||
ts1.mips.push(PlaneStates::from_slice(&[(
|
||||
1..3,
|
||||
@ -342,7 +342,7 @@ mod test {
|
||||
Unit::new(TextureUse::COPY_SRC),
|
||||
)]));
|
||||
assert_eq!(
|
||||
ts1.merge(Id::default(), &ts2, None),
|
||||
ts1.merge(Id::dummy(), &ts2, None),
|
||||
Ok(()),
|
||||
"failed to extend a compatible state"
|
||||
);
|
||||
@ -357,7 +357,7 @@ mod test {
|
||||
|
||||
ts2.mips[0] = PlaneStates::from_slice(&[(1..2, Unit::new(TextureUse::COPY_DST))]);
|
||||
assert_eq!(
|
||||
ts1.clone().merge(Id::default(), &ts2, None),
|
||||
ts1.clone().merge(Id::dummy(), &ts2, None),
|
||||
Err(PendingTransition {
|
||||
id,
|
||||
selector: SubresourceRange {
|
||||
@ -381,7 +381,7 @@ mod test {
|
||||
},
|
||||
),
|
||||
]);
|
||||
ts1.merge(Id::default(), &ts2, Some(&mut list)).unwrap();
|
||||
ts1.merge(Id::dummy(), &ts2, Some(&mut list)).unwrap();
|
||||
assert_eq!(
|
||||
&list,
|
||||
&[
|
||||
@ -433,7 +433,7 @@ mod test {
|
||||
last: TextureUse::COPY_SRC,
|
||||
},
|
||||
)]);
|
||||
ts1.merge(Id::default(), &ts2, Some(&mut list)).unwrap();
|
||||
ts1.merge(Id::dummy(), &ts2, Some(&mut list)).unwrap();
|
||||
assert_eq!(&list, &[], "unexpected replacing transition");
|
||||
|
||||
list.clear();
|
||||
@ -444,7 +444,7 @@ mod test {
|
||||
last: TextureUse::COPY_DST,
|
||||
},
|
||||
)]);
|
||||
ts1.merge(Id::default(), &ts2, Some(&mut list)).unwrap();
|
||||
ts1.merge(Id::dummy(), &ts2, Some(&mut list)).unwrap();
|
||||
assert_eq!(
|
||||
&list,
|
||||
&[PendingTransition {
|
||||
|
@ -18,4 +18,3 @@ replay = ["serde"]
|
||||
[dependencies]
|
||||
bitflags = "1.0"
|
||||
serde = { version = "1.0", features = ["serde_derive"], optional = true }
|
||||
peek-poke = { version = "0.2", optional = true }
|
||||
|
@ -2,16 +2,13 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#[cfg(feature = "peek-poke")]
|
||||
use peek_poke::PeekPoke;
|
||||
#[cfg(feature = "replay")]
|
||||
use serde::Deserialize;
|
||||
#[cfg(feature = "trace")]
|
||||
use serde::Serialize;
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Integral type used for buffer sizes/offsets.
|
||||
/// Integral type used for buffer offsets.
|
||||
pub type BufferAddress = u64;
|
||||
pub type NonZeroBufferAddress = std::num::NonZeroU64;
|
||||
/// Integral type used for buffer slice sizes.
|
||||
pub type BufferSize = std::num::NonZeroU64;
|
||||
|
||||
/// Buffer-Texture copies must have [`bytes_per_row`] aligned to this number.
|
||||
///
|
||||
@ -24,32 +21,6 @@ pub const BIND_BUFFER_ALIGNMENT: BufferAddress = 256;
|
||||
/// Buffer to buffer copy offsets and sizes must be aligned to this number.
|
||||
pub const COPY_BUFFER_ALIGNMENT: BufferAddress = 4;
|
||||
|
||||
/// Integral newtype for buffer sizes.
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, Debug, Hash, PartialEq)]
|
||||
#[cfg_attr(feature = "peek-poke", derive(PeekPoke))]
|
||||
#[cfg_attr(
|
||||
feature = "trace",
|
||||
derive(serde::Serialize),
|
||||
serde(into = "SerBufferSize")
|
||||
)]
|
||||
#[cfg_attr(
|
||||
feature = "replay",
|
||||
derive(serde::Deserialize),
|
||||
serde(from = "SerBufferSize")
|
||||
)]
|
||||
pub struct BufferSize(pub BufferAddress);
|
||||
|
||||
impl BufferSize {
|
||||
pub const WHOLE: BufferSize = BufferSize(!0);
|
||||
}
|
||||
|
||||
impl Default for BufferSize {
|
||||
fn default() -> Self {
|
||||
BufferSize::WHOLE
|
||||
}
|
||||
}
|
||||
|
||||
/// Backends supported by wgpu.
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
@ -612,8 +583,7 @@ pub struct RasterizationStateDescriptor {
|
||||
/// loading from texture in a shader. When writing to the texture, the opposite conversion takes place.
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "trace", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
|
||||
pub enum TextureFormat {
|
||||
// Normal 8 bit formats
|
||||
/// Red channel only. 8 bit integer per channel. [0, 255] converted to/from float [0, 1] in shader.
|
||||
@ -1149,9 +1119,7 @@ pub enum SwapChainStatus {
|
||||
/// Operation to perform to the output attachment at the start of a renderpass.
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "trace", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[cfg_attr(feature = "peek-poke", derive(PeekPoke))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum LoadOp {
|
||||
/// Clear the output attachment with the clear color. Clearing is faster than loading.
|
||||
Clear = 0,
|
||||
@ -1162,9 +1130,7 @@ pub enum LoadOp {
|
||||
/// Operation to perform to the output attachment at the end of a renderpass.
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "trace", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[cfg_attr(feature = "peek-poke", derive(PeekPoke))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum StoreOp {
|
||||
/// Clear the render target. If you don't care about the contents of the target, this can be faster.
|
||||
Clear = 0,
|
||||
@ -1172,12 +1138,27 @@ pub enum StoreOp {
|
||||
Store = 1,
|
||||
}
|
||||
|
||||
/// Describes an individual channel within a render pass, such as color, depth, or stencil.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct PassChannel<V> {
|
||||
/// Operation to perform to the output attachment at the start of a renderpass. This must be clear if it
|
||||
/// is the first renderpass rendering to a swap chain image.
|
||||
pub load_op: LoadOp,
|
||||
/// Operation to perform to the output attachment at the end of a renderpass.
|
||||
pub store_op: StoreOp,
|
||||
/// If load_op is [`LoadOp::Clear`], the attachement will be cleared to this color.
|
||||
pub clear_value: V,
|
||||
/// If true, the relevant channel is not changed by a renderpass, and the corresponding attachment
|
||||
/// can be used inside the pass by other read-only usages.
|
||||
pub read_only: bool,
|
||||
}
|
||||
|
||||
/// Describes a color attachment to a [`RenderPass`].
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "trace", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[cfg_attr(feature = "peek-poke", derive(PeekPoke))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct RenderPassColorAttachmentDescriptorBase<T> {
|
||||
/// Texture attachment to render to. Must contain [`TextureUsage::OUTPUT_ATTACHMENT`].
|
||||
pub attachment: T,
|
||||
@ -1185,44 +1166,22 @@ pub struct RenderPassColorAttachmentDescriptorBase<T> {
|
||||
/// attachment has 1 sample (does not have MSAA). This is not mandatory for rendering with multisampling,
|
||||
/// you can choose to resolve later or manually.
|
||||
pub resolve_target: Option<T>,
|
||||
/// Operation to perform to the output attachment at the start of a renderpass. This must be clear if it
|
||||
/// is the first renderpass rendering to a swap chain image.
|
||||
pub load_op: LoadOp,
|
||||
/// Operation to perform to the output attachment at the end of a renderpass.
|
||||
pub store_op: StoreOp,
|
||||
/// If load_op is [`LoadOp::Clear`], the attachement will be cleared to this color.
|
||||
pub clear_color: Color,
|
||||
/// Color channel.
|
||||
pub channel: PassChannel<Color>,
|
||||
}
|
||||
|
||||
/// Describes a depth/stencil attachment to a [`RenderPass`].
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "trace", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[cfg_attr(feature = "peek-poke", derive(PeekPoke))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct RenderPassDepthStencilAttachmentDescriptorBase<T> {
|
||||
/// Texture attachment to render to. Must contain [`TextureUsage::OUTPUT_ATTACHMENT`] and be a valid
|
||||
/// texture type for a depth/stencil attachment.
|
||||
pub attachment: T,
|
||||
/// Operation to perform to the depth component of the output attachment at the start of a renderpass.
|
||||
pub depth_load_op: LoadOp,
|
||||
/// Operation to perform to the depth component of the output attachment at the end of a renderpass.
|
||||
pub depth_store_op: StoreOp,
|
||||
/// If depth_load_op is [`LoadOp::Clear`], the depth component will be cleared to this depth.
|
||||
pub clear_depth: f32,
|
||||
/// Enabling read only depth means that depth cannot be cleared or written to, but it can be used
|
||||
/// as the input to some part of this render pass.
|
||||
pub depth_read_only: bool,
|
||||
/// Operation to perform to the stencil component of the output attachment at the start of a renderpass.
|
||||
pub stencil_load_op: LoadOp,
|
||||
/// Operation to perform to the stencil component of the output attachment at the end of a renderpass.
|
||||
pub stencil_store_op: StoreOp,
|
||||
/// If stencil_load_op is [`LoadOp::Clear`], the stencil component will be cleared to this stencil value.
|
||||
/// Only the low 8 bits are used.
|
||||
pub clear_stencil: u32,
|
||||
/// Enabling read only stencil means that stencil cannot be cleared or written to, but it can be used
|
||||
/// as the input to some part of this render pass.
|
||||
pub stencil_read_only: bool,
|
||||
/// Depth channel.
|
||||
pub depth: PassChannel<f32>,
|
||||
/// Stencil channel.
|
||||
pub stencil: PassChannel<u32>,
|
||||
}
|
||||
|
||||
/// RGBA double precision color.
|
||||
@ -1230,9 +1189,7 @@ pub struct RenderPassDepthStencilAttachmentDescriptorBase<T> {
|
||||
/// This is not to be used as a generic color type, only for specific wgpu interfaces.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||
#[cfg_attr(feature = "trace", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
#[cfg_attr(feature = "peek-poke", derive(PeekPoke))]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Color {
|
||||
pub r: f64,
|
||||
pub g: f64,
|
||||
@ -1683,7 +1640,7 @@ pub enum BindingType {
|
||||
/// When pipeline is created, the size has to cover at least the corresponding structure in the shader
|
||||
/// plus one element of the unbound array, which can only be last in the structure.
|
||||
/// If `None`, the check is performed at draw call time instead of pipeline and bind group creation.
|
||||
min_binding_size: Option<NonZeroBufferAddress>,
|
||||
min_binding_size: Option<BufferSize>,
|
||||
},
|
||||
/// A storage buffer.
|
||||
///
|
||||
@ -1701,7 +1658,7 @@ pub enum BindingType {
|
||||
/// When pipeline is created, the size has to cover at least the corresponding structure in the shader
|
||||
/// plus one element of the unbound array, which can only be last in the structure.
|
||||
/// If `None`, the check is performed at draw call time instead of pipeline and bind group creation.
|
||||
min_binding_size: Option<NonZeroBufferAddress>,
|
||||
min_binding_size: Option<BufferSize>,
|
||||
/// The buffer can only be read in the shader and it must be annotated with `readonly`.
|
||||
///
|
||||
/// Example GLSL syntax:
|
||||
@ -1817,33 +1774,3 @@ pub struct BindGroupLayoutDescriptor<'a> {
|
||||
/// Array of bindings in this BindGroupLayout
|
||||
pub bindings: &'a [BindGroupLayoutEntry],
|
||||
}
|
||||
|
||||
/// This type allows us to make the serialized representation of a BufferSize more human-readable
|
||||
#[allow(dead_code)]
|
||||
#[cfg_attr(feature = "trace", derive(serde::Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(serde::Deserialize))]
|
||||
enum SerBufferSize {
|
||||
Size(u64),
|
||||
Whole,
|
||||
}
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
impl From<BufferSize> for SerBufferSize {
|
||||
fn from(buffer_size: BufferSize) -> Self {
|
||||
if buffer_size == BufferSize::WHOLE {
|
||||
Self::Whole
|
||||
} else {
|
||||
Self::Size(buffer_size.0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "replay")]
|
||||
impl From<SerBufferSize> for BufferSize {
|
||||
fn from(ser_buffer_size: SerBufferSize) -> Self {
|
||||
match ser_buffer_size {
|
||||
SerBufferSize::Size(size) => BufferSize(size),
|
||||
SerBufferSize::Whole => BufferSize::WHOLE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user