mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-25 08:13:27 +00:00
Merge #116
116: Validation bits from 0.2 r=kvark a=kvark Sibling of #114 Co-authored-by: Dzmitry Malyshau <dmalyshau@mozilla.com>
This commit is contained in:
commit
81ff6fac05
@ -1,5 +1,11 @@
|
||||
# Change Log
|
||||
|
||||
## v0.2.5 (31-03-2019)
|
||||
- fixed submission tracking
|
||||
- added support for blend colors
|
||||
- fixed bind group compatibility at the gfx-hal level
|
||||
- validating the bind groups and blend colors
|
||||
|
||||
## v0.2.3 (20-03-2019)
|
||||
- fixed vertex format mapping
|
||||
- fixed building with "empty" backend on Windows
|
||||
|
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -325,8 +325,8 @@ name = "examples"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wgpu 0.2.1",
|
||||
"wgpu-native 0.2.4",
|
||||
"wgpu 0.2.2",
|
||||
"wgpu-native 0.2.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -503,7 +503,7 @@ dependencies = [
|
||||
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"glsl-to-spirv 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wgpu 0.2.1",
|
||||
"wgpu 0.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1389,10 +1389,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wgpu"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wgpu-native 0.2.4",
|
||||
"wgpu-native 0.2.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1404,7 +1404,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wgpu-native"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
dependencies = [
|
||||
"arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1431,7 +1431,7 @@ dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wgpu-native 0.2.4",
|
||||
"wgpu-native 0.2.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -73,6 +73,14 @@ int main() {
|
||||
.bindings = NULL,
|
||||
.bindings_length = 0,
|
||||
});
|
||||
WGPUBindGroupId bind_group =
|
||||
wgpu_device_create_bind_group(device,
|
||||
&(WGPUBindGroupDescriptor){
|
||||
.layout = bind_group_layout,
|
||||
.bindings = NULL,
|
||||
.bindings_length = 0,
|
||||
});
|
||||
|
||||
WGPUBindGroupLayoutId bind_group_layouts[BIND_GROUP_LAYOUTS_LENGTH] = {
|
||||
bind_group_layout};
|
||||
|
||||
@ -211,6 +219,7 @@ int main() {
|
||||
});
|
||||
|
||||
wgpu_render_pass_set_pipeline(rpass, render_pipeline);
|
||||
wgpu_render_pass_set_bind_group(rpass, 0, bind_group);
|
||||
wgpu_render_pass_draw(rpass, 3, 1, 0, 0);
|
||||
WGPUQueueId queue = wgpu_device_get_queue(device);
|
||||
WGPUCommandBufferId cmd_buf = wgpu_render_pass_end_pass(rpass);
|
||||
|
@ -21,6 +21,10 @@ fn main() {
|
||||
|
||||
let bind_group_layout =
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { bindings: &[] });
|
||||
let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
|
||||
layout: &bind_group_layout,
|
||||
bindings: &[],
|
||||
});
|
||||
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||
bind_group_layouts: &[&bind_group_layout],
|
||||
});
|
||||
@ -113,6 +117,7 @@ fn main() {
|
||||
depth_stencil_attachment: None,
|
||||
});
|
||||
rpass.set_pipeline(&render_pipeline);
|
||||
rpass.set_bind_group(0, &bind_group);
|
||||
rpass.draw(0..3, 0..1);
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,8 @@
|
||||
|
||||
#define WGPUBITS_PER_BYTE 8
|
||||
|
||||
#define WGPUMAX_BIND_GROUPS 4
|
||||
|
||||
typedef enum {
|
||||
WGPUAddressMode_ClampToEdge = 0,
|
||||
WGPUAddressMode_Repeat = 1,
|
||||
@ -617,6 +619,8 @@ typedef struct {
|
||||
|
||||
#define WGPUColor_WHITE (WGPUColor){ .r = 1, .g = 1, .b = 1, .a = 1 }
|
||||
|
||||
#define WGPUPipelineFlags_BLEND_COLOR 1
|
||||
|
||||
#define WGPUShaderStageFlags_COMPUTE 4
|
||||
|
||||
#define WGPUShaderStageFlags_FRAGMENT 2
|
||||
@ -789,6 +793,8 @@ void wgpu_render_pass_set_bind_group(WGPURenderPassId pass_id,
|
||||
uint32_t index,
|
||||
WGPUBindGroupId bind_group_id);
|
||||
|
||||
void wgpu_render_pass_set_blend_color(WGPURenderPassId pass_id, const WGPUColor *color);
|
||||
|
||||
void wgpu_render_pass_set_index_buffer(WGPURenderPassId pass_id,
|
||||
WGPUBufferId buffer_id,
|
||||
uint32_t offset);
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wgpu-native"
|
||||
version = "0.2.4"
|
||||
version = "0.2.5"
|
||||
authors = [
|
||||
"Dzmitry Malyshau <kvark@mozilla.com>",
|
||||
"Joshua Groves <josh@joshgroves.com>",
|
||||
|
@ -9,6 +9,7 @@ use hal::{
|
||||
pool::RawCommandPool,
|
||||
Device,
|
||||
};
|
||||
use log::trace;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
use std::{
|
||||
@ -17,6 +18,7 @@ use std::{
|
||||
thread,
|
||||
};
|
||||
|
||||
|
||||
struct CommandPool<B: hal::Backend> {
|
||||
raw: B::CommandPool,
|
||||
available: Vec<B::CommandBuffer>,
|
||||
@ -109,7 +111,9 @@ impl<B: hal::Backend> CommandAllocator<B> {
|
||||
pool.available.pop().unwrap()
|
||||
}
|
||||
|
||||
pub fn after_submit(&self, cmd_buf: CommandBuffer<B>) {
|
||||
pub fn after_submit(&self, cmd_buf: CommandBuffer<B>, submit_index: SubmissionIndex) {
|
||||
cmd_buf.life_guard.submission_index
|
||||
.store(submit_index, Ordering::Release);
|
||||
self.inner.lock().pending.push(cmd_buf);
|
||||
}
|
||||
|
||||
@ -122,6 +126,7 @@ impl<B: hal::Backend> CommandAllocator<B> {
|
||||
.load(Ordering::Acquire);
|
||||
if index <= last_done {
|
||||
let cmd_buf = inner.pending.swap_remove(i);
|
||||
trace!("recycling comb submitted in {} when {} is done", index, last_done);
|
||||
inner.recycle(cmd_buf);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,12 @@
|
||||
use crate::{BindGroupHandle, BindGroupId, BindGroupLayoutId, PipelineLayoutId, Stored};
|
||||
|
||||
use copyless::VecHelper as _;
|
||||
use log::trace;
|
||||
|
||||
use std::convert::identity;
|
||||
|
||||
|
||||
pub const MAX_BIND_GROUPS: usize = 4;
|
||||
type BindGroupMask = u8;
|
||||
|
||||
|
||||
pub struct BindGroupPair {
|
||||
@ -8,6 +14,34 @@ pub struct BindGroupPair {
|
||||
group_id: Stored<BindGroupId>,
|
||||
}
|
||||
|
||||
pub enum LayoutChange {
|
||||
Unchanged,
|
||||
Match(BindGroupId),
|
||||
Mismatch,
|
||||
}
|
||||
|
||||
pub enum Provision {
|
||||
Unchanged,
|
||||
Changed {
|
||||
was_compatible: bool,
|
||||
now_compatible: bool,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
struct TakeSome<I> {
|
||||
iter: I,
|
||||
}
|
||||
impl<T, I> Iterator for TakeSome<I>
|
||||
where
|
||||
I: Iterator<Item = Option<T>>,
|
||||
{
|
||||
type Item = T;
|
||||
fn next(&mut self) -> Option<T> {
|
||||
self.iter.next().and_then(identity)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BindGroupEntry {
|
||||
expected_layout_id: Option<BindGroupLayoutId>,
|
||||
@ -15,33 +49,36 @@ pub struct BindGroupEntry {
|
||||
}
|
||||
|
||||
impl BindGroupEntry {
|
||||
fn provide(&mut self, bind_group_id: BindGroupId, bind_group: &BindGroupHandle) -> bool {
|
||||
if let Some(BindGroupPair {
|
||||
ref layout_id,
|
||||
ref group_id,
|
||||
}) = self.provided
|
||||
{
|
||||
if group_id.value == bind_group_id {
|
||||
assert_eq!(*layout_id, bind_group.layout_id);
|
||||
return false;
|
||||
fn provide(&mut self, bind_group_id: BindGroupId, bind_group: &BindGroupHandle) -> Provision {
|
||||
let was_compatible = match self.provided {
|
||||
Some(BindGroupPair { layout_id, ref group_id }) => {
|
||||
if group_id.value == bind_group_id {
|
||||
assert_eq!(layout_id, bind_group.layout_id);
|
||||
return Provision::Unchanged;
|
||||
}
|
||||
self.expected_layout_id == Some(layout_id)
|
||||
}
|
||||
}
|
||||
None => true
|
||||
};
|
||||
|
||||
self.provided = Some(BindGroupPair {
|
||||
layout_id: bind_group.layout_id.clone(),
|
||||
layout_id: bind_group.layout_id,
|
||||
group_id: Stored {
|
||||
value: bind_group_id,
|
||||
ref_count: bind_group.life_guard.ref_count.clone(),
|
||||
},
|
||||
});
|
||||
|
||||
self.expected_layout_id == Some(bind_group.layout_id.clone())
|
||||
Provision::Changed {
|
||||
was_compatible,
|
||||
now_compatible: self.expected_layout_id == Some(bind_group.layout_id),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expect_layout(
|
||||
&mut self,
|
||||
bind_group_layout_id: BindGroupLayoutId,
|
||||
) -> Option<BindGroupId> {
|
||||
) -> LayoutChange {
|
||||
let some = Some(bind_group_layout_id);
|
||||
if self.expected_layout_id != some {
|
||||
self.expected_layout_id = some;
|
||||
@ -49,39 +86,97 @@ impl BindGroupEntry {
|
||||
Some(BindGroupPair {
|
||||
layout_id,
|
||||
ref group_id,
|
||||
}) if layout_id == bind_group_layout_id => Some(group_id.value),
|
||||
Some(_) | None => None,
|
||||
}) if layout_id == bind_group_layout_id => LayoutChange::Match(group_id.value),
|
||||
Some(_) | None => LayoutChange::Mismatch,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
LayoutChange::Unchanged
|
||||
}
|
||||
}
|
||||
|
||||
fn is_valid(&self) -> bool {
|
||||
match (self.expected_layout_id, self.provided.as_ref()) {
|
||||
(None, _) => true,
|
||||
(Some(_), None) => false,
|
||||
(Some(layout), Some(pair)) => layout == pair.layout_id,
|
||||
}
|
||||
}
|
||||
|
||||
fn actual_value(&self) -> Option<BindGroupId> {
|
||||
self.expected_layout_id
|
||||
.and_then(|layout_id| self.provided.as_ref().and_then(|pair| {
|
||||
if pair.layout_id == layout_id {
|
||||
Some(pair.group_id.value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Binder {
|
||||
pub(crate) pipeline_layout_id: Option<PipelineLayoutId>, //TODO: strongly `Stored`
|
||||
pub(crate) entries: Vec<BindGroupEntry>,
|
||||
pub(crate) entries: [BindGroupEntry; MAX_BIND_GROUPS],
|
||||
}
|
||||
|
||||
impl Binder {
|
||||
pub fn ensure_length(&mut self, length: usize) {
|
||||
while self.entries.len() < length {
|
||||
self.entries.alloc().init(BindGroupEntry::default());
|
||||
pub(crate) fn reset_expectations(&mut self, length: usize) {
|
||||
for entry in self.entries[length ..].iter_mut() {
|
||||
entry.expected_layout_id = None;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn provide_entry(
|
||||
&mut self,
|
||||
/// Attempt to set the value of the specified bind group index.
|
||||
/// Returns Some() when the new bind group is ready to be actually bound
|
||||
/// (i.e. compatible with current expectations). Also returns an iterator
|
||||
/// of bind group IDs to be bound with it: those are compatible bind groups
|
||||
/// that were previously blocked because the current one was incompatible.
|
||||
pub(crate) fn provide_entry<'a>(
|
||||
&'a mut self,
|
||||
index: usize,
|
||||
bind_group_id: BindGroupId,
|
||||
bind_group: &BindGroupHandle,
|
||||
) -> Option<PipelineLayoutId> {
|
||||
self.ensure_length(index + 1);
|
||||
if self.entries[index].provide(bind_group_id, bind_group) {
|
||||
self.pipeline_layout_id.as_ref().cloned()
|
||||
} else {
|
||||
None
|
||||
) -> Option<(PipelineLayoutId, impl 'a + Iterator<Item = BindGroupId>)> {
|
||||
trace!("\tBinding [{}] = group {:?}", index, bind_group_id);
|
||||
match self.entries[index].provide(bind_group_id, bind_group) {
|
||||
Provision::Unchanged => {
|
||||
None
|
||||
}
|
||||
Provision::Changed { now_compatible: false, .. } => {
|
||||
trace!("\t\tnot compatible");
|
||||
None
|
||||
}
|
||||
Provision::Changed { was_compatible, .. } => {
|
||||
if self.entries[.. index].iter().all(|entry| entry.is_valid()) {
|
||||
self.pipeline_layout_id.map(move |pipeline_layout_id| {
|
||||
let end = if was_compatible {
|
||||
trace!("\t\tgenerating follow-up sequence");
|
||||
MAX_BIND_GROUPS
|
||||
} else {
|
||||
index + 1
|
||||
};
|
||||
(pipeline_layout_id, TakeSome {
|
||||
iter: self.entries[index + 1 .. end]
|
||||
.iter()
|
||||
.map(|entry| entry.actual_value()),
|
||||
})
|
||||
})
|
||||
} else {
|
||||
trace!("\t\tbehind an incompatible");
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn invalid_mask(&self) -> BindGroupMask {
|
||||
self.entries.iter().enumerate().fold(0, |mask, (i, entry)| {
|
||||
if entry.is_valid() {
|
||||
mask
|
||||
} else {
|
||||
mask | 1u8 << i
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
command::bind::Binder,
|
||||
command::bind::{Binder, LayoutChange},
|
||||
hub::HUB,
|
||||
track::{Stitch, TrackerSet},
|
||||
BindGroupId, CommandBuffer, CommandBufferId, ComputePassId, ComputePipelineId, Stored,
|
||||
@ -73,20 +73,22 @@ pub extern "C" fn wgpu_compute_pass_set_bind_group(
|
||||
&*HUB.textures.read(),
|
||||
);
|
||||
|
||||
if let Some(pipeline_layout_id) =
|
||||
if let Some((pipeline_layout_id, follow_up)) =
|
||||
pass.binder
|
||||
.provide_entry(index as usize, bind_group_id, bind_group)
|
||||
{
|
||||
let pipeline_layout_guard = HUB.pipeline_layouts.read();
|
||||
let bind_groups = iter::once(&bind_group.raw)
|
||||
.chain(follow_up.map(|bg_id| &bind_group_guard[bg_id].raw));
|
||||
unsafe {
|
||||
pass.raw.bind_compute_descriptor_sets(
|
||||
&pipeline_layout_guard[pipeline_layout_id].raw,
|
||||
index as usize,
|
||||
iter::once(&bind_group.raw),
|
||||
bind_groups,
|
||||
&[],
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -109,11 +111,10 @@ pub extern "C" fn wgpu_compute_pass_set_pipeline(
|
||||
|
||||
let pipeline_layout_guard = HUB.pipeline_layouts.read();
|
||||
let pipeline_layout = &pipeline_layout_guard[pipeline.layout_id];
|
||||
let bing_group_guard = HUB.bind_groups.read();
|
||||
let bind_group_guard = HUB.bind_groups.read();
|
||||
|
||||
pass.binder.pipeline_layout_id = Some(pipeline.layout_id.clone());
|
||||
pass.binder
|
||||
.ensure_length(pipeline_layout.bind_group_layout_ids.len());
|
||||
pass.binder.reset_expectations(pipeline_layout.bind_group_layout_ids.len());
|
||||
|
||||
for (index, (entry, &bgl_id)) in pass
|
||||
.binder
|
||||
@ -122,8 +123,8 @@ pub extern "C" fn wgpu_compute_pass_set_pipeline(
|
||||
.zip(&pipeline_layout.bind_group_layout_ids)
|
||||
.enumerate()
|
||||
{
|
||||
if let Some(bg_id) = entry.expect_layout(bgl_id) {
|
||||
let desc_set = &bing_group_guard[bg_id].raw;
|
||||
if let LayoutChange::Match(bg_id) = entry.expect_layout(bgl_id) {
|
||||
let desc_set = &bind_group_guard[bg_id].raw;
|
||||
unsafe {
|
||||
pass.raw.bind_compute_descriptor_sets(
|
||||
&pipeline_layout.raw,
|
||||
|
@ -321,7 +321,7 @@ pub fn command_encoder_begin_render_pass(
|
||||
.iter()
|
||||
.map(|at| {
|
||||
//TODO: integer types?
|
||||
let value = hal::command::ClearColor::Float(conv::map_color(at.clear_color));
|
||||
let value = hal::command::ClearColor::Float(conv::map_color(&at.clear_color));
|
||||
hal::command::ClearValueRaw::from(hal::command::ClearValue::Color(value))
|
||||
})
|
||||
.chain(depth_stencil_attachment.map(|at| {
|
||||
|
@ -1,10 +1,12 @@
|
||||
use crate::{
|
||||
command::bind::Binder,
|
||||
command::bind::{Binder, LayoutChange},
|
||||
conv,
|
||||
device::RenderPassContext,
|
||||
hub::HUB,
|
||||
pipeline::PipelineFlags,
|
||||
resource::BufferUsageFlags,
|
||||
track::{Stitch, TrackerSet},
|
||||
BindGroupId, BufferId, CommandBuffer, CommandBufferId, RenderPassId, RenderPipelineId, Stored,
|
||||
BindGroupId, BufferId, Color, CommandBuffer, CommandBufferId, RenderPassId, RenderPipelineId, Stored,
|
||||
};
|
||||
|
||||
use hal::command::RawCommandBuffer;
|
||||
@ -12,12 +14,30 @@ use hal::command::RawCommandBuffer;
|
||||
use std::{iter, slice};
|
||||
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum BlendColorStatus {
|
||||
Unused,
|
||||
Required,
|
||||
Set,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum DrawError {
|
||||
MissingBlendColor,
|
||||
IncompatibleBindGroup {
|
||||
index: u32,
|
||||
//expected: BindGroupLayoutId,
|
||||
//provided: Option<(BindGroupLayoutId, BindGroupId)>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct RenderPass<B: hal::Backend> {
|
||||
raw: B::CommandBuffer,
|
||||
cmb_id: Stored<CommandBufferId>,
|
||||
context: RenderPassContext,
|
||||
binder: Binder,
|
||||
trackers: TrackerSet,
|
||||
blend_color_status: BlendColorStatus,
|
||||
}
|
||||
|
||||
impl<B: hal::Backend> RenderPass<B> {
|
||||
@ -32,8 +52,24 @@ impl<B: hal::Backend> RenderPass<B> {
|
||||
context,
|
||||
binder: Binder::default(),
|
||||
trackers: TrackerSet::new(),
|
||||
blend_color_status: BlendColorStatus::Unused,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_ready(&self) -> Result<(), DrawError> {
|
||||
//TODO: vertex buffers
|
||||
let bind_mask = self.binder.invalid_mask();
|
||||
if bind_mask != 0 {
|
||||
//let (expected, provided) = self.binder.entries[index as usize].info();
|
||||
return Err(DrawError::IncompatibleBindGroup {
|
||||
index: bind_mask.trailing_zeros() as u32,
|
||||
});
|
||||
}
|
||||
if self.blend_color_status == BlendColorStatus::Required {
|
||||
return Err(DrawError::MissingBlendColor)
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -132,8 +168,12 @@ pub extern "C" fn wgpu_render_pass_draw(
|
||||
first_vertex: u32,
|
||||
first_instance: u32,
|
||||
) {
|
||||
let mut pass_guard = HUB.render_passes.write();
|
||||
let pass = &mut pass_guard[pass_id];
|
||||
pass.is_ready().unwrap();
|
||||
|
||||
unsafe {
|
||||
HUB.render_passes.write()[pass_id].raw.draw(
|
||||
pass.raw.draw(
|
||||
first_vertex..first_vertex + vertex_count,
|
||||
first_instance..first_instance + instance_count,
|
||||
);
|
||||
@ -149,8 +189,12 @@ pub extern "C" fn wgpu_render_pass_draw_indexed(
|
||||
base_vertex: i32,
|
||||
first_instance: u32,
|
||||
) {
|
||||
let mut pass_guard = HUB.render_passes.write();
|
||||
let pass = &mut pass_guard[pass_id];
|
||||
pass.is_ready().unwrap();
|
||||
|
||||
unsafe {
|
||||
HUB.render_passes.write()[pass_id].raw.draw_indexed(
|
||||
pass.raw.draw_indexed(
|
||||
first_index..first_index + index_count,
|
||||
base_vertex,
|
||||
first_instance..first_instance + instance_count,
|
||||
@ -171,21 +215,22 @@ pub extern "C" fn wgpu_render_pass_set_bind_group(
|
||||
|
||||
pass.trackers.consume_by_extend(&bind_group.used);
|
||||
|
||||
if let Some(pipeline_layout_id) =
|
||||
if let Some((pipeline_layout_id, follow_up)) =
|
||||
pass.binder
|
||||
.provide_entry(index as usize, bind_group_id, bind_group)
|
||||
{
|
||||
let pipeline_layout_guard = HUB.pipeline_layouts.read();
|
||||
let pipeline_layout = &pipeline_layout_guard[pipeline_layout_id];
|
||||
let bind_groups = iter::once(&bind_group.raw)
|
||||
.chain(follow_up.map(|bg_id| &bind_group_guard[bg_id].raw));
|
||||
unsafe {
|
||||
pass.raw.bind_graphics_descriptor_sets(
|
||||
&pipeline_layout.raw,
|
||||
&&pipeline_layout_guard[pipeline_layout_id].raw,
|
||||
index as usize,
|
||||
iter::once(&bind_group.raw),
|
||||
bind_groups,
|
||||
&[],
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -203,6 +248,10 @@ pub extern "C" fn wgpu_render_pass_set_pipeline(
|
||||
"The render pipeline is not compatible with the pass!"
|
||||
);
|
||||
|
||||
if pipeline.flags.contains(PipelineFlags::BLEND_COLOR) && pass.blend_color_status == BlendColorStatus::Unused {
|
||||
pass.blend_color_status = BlendColorStatus::Required;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
pass.raw.bind_graphics_pipeline(&pipeline.raw);
|
||||
}
|
||||
@ -216,8 +265,7 @@ pub extern "C" fn wgpu_render_pass_set_pipeline(
|
||||
let bind_group_guard = HUB.bind_groups.read();
|
||||
|
||||
pass.binder.pipeline_layout_id = Some(pipeline.layout_id.clone());
|
||||
pass.binder
|
||||
.ensure_length(pipeline_layout.bind_group_layout_ids.len());
|
||||
pass.binder.reset_expectations(pipeline_layout.bind_group_layout_ids.len());
|
||||
|
||||
for (index, (entry, &bgl_id)) in pass
|
||||
.binder
|
||||
@ -226,7 +274,7 @@ pub extern "C" fn wgpu_render_pass_set_pipeline(
|
||||
.zip(&pipeline_layout.bind_group_layout_ids)
|
||||
.enumerate()
|
||||
{
|
||||
if let Some(bg_id) = entry.expect_layout(bgl_id) {
|
||||
if let LayoutChange::Match(bg_id) = entry.expect_layout(bgl_id) {
|
||||
let desc_set = &bind_group_guard[bg_id].raw;
|
||||
unsafe {
|
||||
pass.raw.bind_graphics_descriptor_sets(
|
||||
@ -239,3 +287,18 @@ pub extern "C" fn wgpu_render_pass_set_pipeline(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wgpu_render_pass_set_blend_color(
|
||||
pass_id: RenderPassId,
|
||||
color: &Color,
|
||||
) {
|
||||
let mut pass_guard = HUB.render_passes.write();
|
||||
let pass = &mut pass_guard[pass_id];
|
||||
|
||||
pass.blend_color_status = BlendColorStatus::Set;
|
||||
|
||||
unsafe {
|
||||
pass.raw.set_blend_constants(conv::map_color(color));
|
||||
}
|
||||
}
|
||||
|
@ -571,7 +571,7 @@ pub fn map_load_store_ops(
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_color(color: Color) -> hal::pso::ColorValue {
|
||||
pub fn map_color(color: &Color) -> hal::pso::ColorValue {
|
||||
[color.r, color.g, color.b, color.a]
|
||||
}
|
||||
|
||||
|
@ -138,6 +138,7 @@ impl<B: hal::Backend> DestroyedResources<B> {
|
||||
for i in (0..self.active.len()).rev() {
|
||||
if unsafe { device.get_fence_status(&self.active[i].fence).unwrap() } {
|
||||
let a = self.active.swap_remove(i);
|
||||
trace!("Active submission {} is done", a.index);
|
||||
last_done = last_done.max(a.index);
|
||||
self.free.extend(a.resources.into_iter().map(|(_, r)| r));
|
||||
unsafe {
|
||||
@ -957,6 +958,7 @@ pub fn device_create_bind_group(
|
||||
.unwrap();
|
||||
let alignment = match decl.ty {
|
||||
binding_model::BindingType::UniformBuffer => device.limits.min_uniform_buffer_offset_alignment,
|
||||
binding_model::BindingType::StorageBuffer => device.limits.min_storage_buffer_offset_alignment,
|
||||
_ => panic!("Mismatched buffer binding for {:?}", decl),
|
||||
};
|
||||
assert_eq!(bb.offset as hal::buffer::Offset % alignment, 0,
|
||||
@ -965,10 +967,12 @@ pub fn device_create_bind_group(
|
||||
hal::pso::Descriptor::Buffer(&buffer.raw, range)
|
||||
}
|
||||
binding_model::BindingResource::Sampler(id) => {
|
||||
assert_eq!(decl.ty, binding_model::BindingType::Sampler);
|
||||
let sampler = &sampler_guard[id];
|
||||
hal::pso::Descriptor::Sampler(&sampler.raw)
|
||||
}
|
||||
binding_model::BindingResource::TextureView(id) => {
|
||||
assert_eq!(decl.ty, binding_model::BindingType::SampledTexture);
|
||||
let view = &texture_view_guard[id];
|
||||
used.views.query(id, &view.life_guard.ref_count, DummyUsage);
|
||||
used.textures
|
||||
@ -1087,7 +1091,7 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
let command_buffer_ids =
|
||||
unsafe { slice::from_raw_parts(command_buffer_ptr, command_buffer_count) };
|
||||
|
||||
let (old_submit_index, fence) = {
|
||||
let (submit_index, fence) = {
|
||||
let mut device_guard = HUB.devices.write();
|
||||
let device = &mut device_guard[queue_id];
|
||||
|
||||
@ -1098,7 +1102,7 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
destroyed.triage_referenced(&mut *trackers);
|
||||
destroyed.triage_framebuffers(&mut *device.framebuffers.lock());
|
||||
|
||||
let old_submit_index = device
|
||||
let submit_index = 1 + device
|
||||
.life_guard
|
||||
.submission_index
|
||||
.fetch_add(1, Ordering::Relaxed);
|
||||
@ -1117,26 +1121,23 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
let comb = &mut command_buffer_guard[cmb_id];
|
||||
swap_chain_links.extend(comb.swap_chain_links.drain(..));
|
||||
// update submission IDs
|
||||
comb.life_guard
|
||||
.submission_index
|
||||
.store(old_submit_index, Ordering::Release);
|
||||
for id in comb.trackers.buffers.used() {
|
||||
buffer_guard[id]
|
||||
.life_guard
|
||||
.submission_index
|
||||
.store(old_submit_index, Ordering::Release);
|
||||
.store(submit_index, Ordering::Release);
|
||||
}
|
||||
for id in comb.trackers.textures.used() {
|
||||
texture_guard[id]
|
||||
.life_guard
|
||||
.submission_index
|
||||
.store(old_submit_index, Ordering::Release);
|
||||
.store(submit_index, Ordering::Release);
|
||||
}
|
||||
for id in comb.trackers.views.used() {
|
||||
texture_view_guard[id]
|
||||
.life_guard
|
||||
.submission_index
|
||||
.store(old_submit_index, Ordering::Release);
|
||||
.store(submit_index, Ordering::Release);
|
||||
}
|
||||
|
||||
// execute resource transitions
|
||||
@ -1201,7 +1202,7 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
}
|
||||
}
|
||||
|
||||
(old_submit_index, fence)
|
||||
(submit_index, fence)
|
||||
};
|
||||
|
||||
// No need for write access to the device from here on out
|
||||
@ -1214,7 +1215,7 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
destroyed.handle_mapping(&device.raw, &device.limits);
|
||||
|
||||
destroyed.active.alloc().init(ActiveSubmission {
|
||||
index: old_submit_index + 1,
|
||||
index: submit_index,
|
||||
fence,
|
||||
resources: Vec::new(),
|
||||
mapped: Vec::new(),
|
||||
@ -1230,7 +1231,7 @@ pub extern "C" fn wgpu_queue_submit(
|
||||
// finally, return the command buffers to the allocator
|
||||
for &cmb_id in command_buffer_ids {
|
||||
let cmd_buf = HUB.command_buffers.unregister(cmb_id);
|
||||
device.com_allocator.after_submit(cmd_buf);
|
||||
device.com_allocator.after_submit(cmd_buf, submit_index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1435,10 +1436,16 @@ pub fn device_create_render_pipeline(
|
||||
depth_stencil: depth_stencil_state.map(|state| state.format),
|
||||
};
|
||||
|
||||
let mut flags = pipeline::PipelineFlags::empty();
|
||||
if color_states.iter().any(|state| state.color.uses_color() | state.alpha.uses_color()) {
|
||||
flags |= pipeline::PipelineFlags::BLEND_COLOR;
|
||||
}
|
||||
|
||||
pipeline::RenderPipeline {
|
||||
raw: pipeline,
|
||||
layout_id: desc.layout,
|
||||
pass_context,
|
||||
flags,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1754,10 +1761,7 @@ pub extern "C" fn wgpu_buffer_set_sub_data(
|
||||
.com_allocator
|
||||
.allocate(buffer.device_id.clone(), &device.raw);
|
||||
// mark as used by the next submission, conservatively
|
||||
let last_submit_index = device.life_guard.submission_index.load(Ordering::Acquire);
|
||||
comb.life_guard
|
||||
.submission_index
|
||||
.store(last_submit_index + 1, Ordering::Release);
|
||||
let submit_index = 1 + device.life_guard.submission_index.load(Ordering::Acquire);
|
||||
unsafe {
|
||||
let raw = comb.raw.last_mut().unwrap();
|
||||
raw.begin(
|
||||
@ -1786,7 +1790,7 @@ pub extern "C" fn wgpu_buffer_set_sub_data(
|
||||
.submit::<_, _, <back::Backend as hal::Backend>::Semaphore, _, _>(submission, None);
|
||||
}
|
||||
|
||||
device.com_allocator.after_submit(comb);
|
||||
device.com_allocator.after_submit(comb, submit_index);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -63,6 +63,16 @@ impl BlendDescriptor {
|
||||
dst_factor: BlendFactor::Zero,
|
||||
operation: BlendOperation::Add,
|
||||
};
|
||||
|
||||
pub fn uses_color(&self) -> bool {
|
||||
match (self.src_factor, self.dst_factor) {
|
||||
(BlendFactor::BlendColor, _) |
|
||||
(BlendFactor::OneMinusBlendColor, _) |
|
||||
(_, BlendFactor::BlendColor) |
|
||||
(_, BlendFactor::OneMinusBlendColor) => true,
|
||||
(_, _) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
@ -279,8 +289,16 @@ pub struct RenderPipelineDescriptor {
|
||||
pub sample_count: u32,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[repr(transparent)]
|
||||
pub struct PipelineFlags: u32 {
|
||||
const BLEND_COLOR = 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RenderPipeline<B: hal::Backend> {
|
||||
pub(crate) raw: B::GraphicsPipeline,
|
||||
pub(crate) layout_id: PipelineLayoutId,
|
||||
pub(crate) pass_context: RenderPassContext,
|
||||
pub(crate) flags: PipelineFlags,
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "wgpu"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
authors = [
|
||||
"Dzmitry Malyshau <kvark@mozilla.com>",
|
||||
"Joshua Groves <josh@joshgroves.com>",
|
||||
@ -23,5 +23,5 @@ dx12 = ["wgpu-native/gfx-backend-dx12"]
|
||||
vulkan = ["wgpu-native/gfx-backend-vulkan"]
|
||||
|
||||
[dependencies]
|
||||
wgpu-native = { version = "0.2", path = "../wgpu-native", features = ["local", "window-winit"] }
|
||||
wgpu-native = { version = "0.2.5", path = "../wgpu-native", features = ["local", "window-winit"] }
|
||||
arrayvec = "0.4"
|
||||
|
@ -784,6 +784,10 @@ impl<'a> RenderPass<'a> {
|
||||
wgn::wgpu_render_pass_set_pipeline(self.id, pipeline.id);
|
||||
}
|
||||
|
||||
pub fn set_blend_color(&mut self, color: Color) {
|
||||
wgn::wgpu_render_pass_set_blend_color(self.id, &color);
|
||||
}
|
||||
|
||||
pub fn set_index_buffer(&mut self, buffer: &Buffer, offset: u32) {
|
||||
wgn::wgpu_render_pass_set_index_buffer(self.id, buffer.id, offset);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user