Full MSAA handling

This commit is contained in:
Rukai 2019-06-18 11:55:03 +10:00
parent c8deae32bd
commit 194943c12c
6 changed files with 171 additions and 26 deletions

20
Cargo.lock generated
View File

@ -378,15 +378,17 @@ dependencies = [
[[package]]
name = "gfx-backend-vulkan"
version = "0.2.0"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ash 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
"derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
"winit 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -997,7 +999,7 @@ dependencies = [
[[package]]
name = "rendy-descriptor"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"derivative 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1010,7 +1012,7 @@ dependencies = [
[[package]]
name = "rendy-memory"
version = "0.2.0"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"colorful 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1294,13 +1296,13 @@ dependencies = [
"gfx-backend-empty 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-backend-gl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-backend-metal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-backend-vulkan 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-backend-vulkan 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"gfx-hal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rendy-descriptor 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rendy-memory 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rendy-descriptor 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rendy-memory 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)",
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winit 0.19.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1485,7 +1487,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum gfx-backend-empty 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48d970b730c75da0e4905380e9af664e0ef46c5c4643fbacf637e114df047fb5"
"checksum gfx-backend-gl 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "387c0d9e9f9177478413af94e57580cb98fde035e08a723ed7e6b45b022f3092"
"checksum gfx-backend-metal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d39d1a05e08367faa2006316d4420439fc5f82de63bc8706bab50b4eba7760c"
"checksum gfx-backend-vulkan 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "40aed111bb822e01f3569345eefc732c5b557b19d7905b0a865e553cf4e4e7ea"
"checksum gfx-backend-vulkan 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c3947889fe783aa17c4ca184f18d1142e61a4aaa292715ada4b8bf75a6a6e1"
"checksum gfx-hal 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c045161572372465ebbcb0d33ee937b6ed8874a193148c053688a400b92b197c"
"checksum gfx_gl 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e8a920f8f6c1025a7ddf9dd25502bf059506fd3cd765dfbe8dba0b56b7eeecb"
"checksum gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39a23d5e872a275135d66895d954269cf5e8661d234eb1c2480f4ce0d586acbd"
@ -1551,8 +1553,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252"
"checksum relevant 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bbc232e13d37f4547f5b9b42a5efc380cabe5dbc1807f8b893580640b2ab0308"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rendy-descriptor 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d994004622af2fe3848fde527258dd6bee8cf089a51e2e83fe5f2b7aeb09f6c0"
"checksum rendy-memory 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fbdab806e4d349037b60ff6a25dad1260da58eb4b43ecac31350443278d5c002"
"checksum rendy-descriptor 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83249fea9ebf5ce1715b13158f5f0947d831b2df63809d41dac2501556635db8"
"checksum rendy-memory 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b3846dfe67af528d47ef5fbf30aff05ab683ebf076971dd5a9293a9bf75a0c1"
"checksum rustc-demangle 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc78bfd5acd7bf3e89cffcf899e5cb1a52d6fafa8dec2739ad70c9577a57288"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum rusttype 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "25951e85bb2647960969f72c559392245a5bd07446a589390bf427dda31cdc4a"

View File

@ -39,11 +39,16 @@ use crate::{
#[cfg(feature = "local")]
use crate::{ComputePassId, RenderPassId};
use arrayvec::ArrayVec;
use back::Backend;
use hal::{command::RawCommandBuffer, Device as _};
use hal::{
adapter::PhysicalDevice,
command::RawCommandBuffer,
Device as _
};
use log::trace;
use std::{collections::hash_map::Entry, iter, mem, slice, thread::ThreadId};
use std::{collections::hash_map::Entry, iter, mem, slice, ptr, thread::ThreadId};
#[repr(C)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
@ -183,10 +188,24 @@ pub fn command_encoder_begin_render_pass(
let mut extent = None;
let mut barriers = Vec::new();
let limits = HUB.adapters.read()[device.adapter_id].physical_device.limits();
let samples_count_limit = limits.framebuffer_color_samples_count;
let color_attachments =
unsafe { slice::from_raw_parts(desc.color_attachments, desc.color_attachments_length) };
let depth_stencil_attachment = unsafe { desc.depth_stencil_attachment.as_ref() };
let sample_count = color_attachments.get(0).map(|at| view_guard[at.attachment].samples).unwrap_or(1);
assert!(sample_count & samples_count_limit != 0, "Attachment sample_count must be supported by physical device limits");
for at in color_attachments.iter() {
let sample_count_check = view_guard[at.attachment].samples;
assert_eq!(sample_count_check, sample_count, "All attachments must have the same sample_count");
if let Some(resolve) = unsafe { at.resolve_target.as_ref() } {
assert_eq!(view_guard[*resolve].samples, 1, "All target_resolves must have a sample_count of 1");
}
}
let rp_key = {
let trackers = &mut cmb.trackers;
let swap_chain_links = &mut cmb.swap_chain_links;
@ -237,7 +256,10 @@ pub fn command_encoder_begin_render_pass(
}
});
let color_keys = color_attachments.iter().map(|at| {
let mut colors = ArrayVec::new();
let mut resolves = ArrayVec::new();
for at in color_attachments {
let view = trackers.views
.use_extend(&*view_guard, at.attachment, (), ())
.unwrap();
@ -284,17 +306,76 @@ pub fn command_encoder_begin_render_pass(
hal::image::Layout::ColorAttachmentOptimal
}
};
hal::pass::Attachment {
colors.push(hal::pass::Attachment {
format: Some(conv::map_texture_format(view.format)),
samples: view.samples,
ops: conv::map_load_store_ops(at.load_op, at.store_op),
stencil_ops: hal::pass::AttachmentOps::DONT_CARE,
layouts: old_layout .. hal::image::Layout::ColorAttachmentOptimal,
});
if let Some(resolve_target) = unsafe { at.resolve_target.as_ref() } {
let view = trackers.views
.use_extend(&*view_guard, *resolve_target, (), ())
.unwrap();
if let Some(ex) = extent {
assert_eq!(ex, view.extent);
} else {
extent = Some(view.extent);
}
if view.is_owned_by_swap_chain {
let link = match texture_guard[view.texture_id.value].placement {
TexturePlacement::SwapChain(ref link) => SwapChainLink {
swap_chain_id: link.swap_chain_id.clone(),
epoch: *link.epoch.lock(),
image_index: link.image_index,
},
TexturePlacement::Memory(_) | TexturePlacement::Void => unreachable!(),
};
swap_chain_links.push(link);
}
let old_layout = match trackers.textures.query(
view.texture_id.value,
view.range.clone(),
) {
Some(usage) => {
conv::map_texture_state(usage, hal::format::Aspects::COLOR).1
}
None => {
// Required sub-resources have inconsistent states, we need to
// issue individual barriers instead of relying on the render pass.
let (texture, pending) = trackers.textures.use_replace(
&*texture_guard,
view.texture_id.value,
view.range.clone(),
TextureUsage::OUTPUT_ATTACHMENT,
);
barriers.extend(pending.map(|pending| hal::memory::Barrier::Image {
states: pending.to_states(),
target: &texture.raw,
families: None,
range: pending.selector,
}));
hal::image::Layout::ColorAttachmentOptimal
}
};
resolves.push(hal::pass::Attachment {
format: Some(conv::map_texture_format(view.format)),
samples: view.samples,
ops: hal::pass::AttachmentOps::new(hal::pass::AttachmentLoadOp::DontCare, hal::pass::AttachmentStoreOp::Store),
stencil_ops: hal::pass::AttachmentOps::DONT_CARE,
layouts: old_layout .. hal::image::Layout::ColorAttachmentOptimal,
});
}
});
}
RenderPassKey {
colors: color_keys.collect(),
colors,
resolves,
depth_stencil,
}
};
@ -313,22 +394,40 @@ pub fn command_encoder_begin_render_pass(
let render_pass = match render_pass_cache.entry(rp_key.clone()) {
Entry::Occupied(e) => e.into_mut(),
Entry::Vacant(e) => {
let attachment_unused: u32 = !0; // TODO: Get from ash or expose in gfx-hal. Very important this remains a u32.
let color_ids = [
(0, hal::image::Layout::ColorAttachmentOptimal),
(1, hal::image::Layout::ColorAttachmentOptimal),
(2, hal::image::Layout::ColorAttachmentOptimal),
(3, hal::image::Layout::ColorAttachmentOptimal),
];
let mut resolve_ids = ArrayVec::<[_; crate::device::MAX_COLOR_TARGETS]>::new();
let mut attachment_index = color_attachments.len();
if color_attachments.iter().any(|at| at.resolve_target != ptr::null()) {
for (i, at) in color_attachments.iter().enumerate() {
if at.resolve_target == ptr::null() {
resolve_ids.push((attachment_unused as usize, hal::image::Layout::ColorAttachmentOptimal));
} else {
let sample_count_check = view_guard[color_attachments[i].attachment].samples;
assert!(sample_count_check > 1, "RenderPassColorAttachmentDescriptor with a resolve_target must have an attachment with sample_count > 1");
resolve_ids.push((attachment_index, hal::image::Layout::ColorAttachmentOptimal));
attachment_index += 1;
}
}
}
let depth_id = (
color_attachments.len(),
attachment_index,
hal::image::Layout::DepthStencilAttachmentOptimal,
);
let subpass = hal::pass::SubpassDesc {
colors: &color_ids[.. color_attachments.len()],
resolves: &resolve_ids,
depth_stencil: depth_stencil_attachment.map(|_| &depth_id),
inputs: &[],
resolves: &[],
preserves: &[],
};
@ -345,6 +444,9 @@ pub fn command_encoder_begin_render_pass(
let mut framebuffer_cache = device.framebuffers.lock();
let fb_key = FramebufferKey {
colors: color_attachments.iter().map(|at| at.attachment).collect(),
resolves: color_attachments.iter().filter_map(|at|
unsafe { at.resolve_target.as_ref() }.cloned()
).collect(),
depth_stencil: depth_stencil_attachment.map(|at| at.attachment),
};
let framebuffer = match framebuffer_cache.entry(fb_key) {
@ -437,6 +539,11 @@ pub fn command_encoder_begin_render_pass(
.iter()
.map(|at| view_guard[at.attachment].format)
.collect(),
resolves: color_attachments
.iter()
.filter_map(|at| unsafe { at.resolve_target.as_ref() })
.map(|resolve| view_guard[*resolve].format)
.collect(),
depth_stencil: depth_stencil_attachment.map(|at| view_guard[at.attachment].format),
};
@ -447,6 +554,7 @@ pub fn command_encoder_begin_render_pass(
ref_count: cmb.life_guard.ref_count.clone(),
},
context,
sample_count,
)
}

View File

@ -119,6 +119,7 @@ pub struct RenderPass<B: hal::Backend> {
stencil_reference_status: OptionalState,
index_state: IndexState,
vertex_state: VertexState,
sample_count: u8,
}
impl<B: hal::Backend> RenderPass<B> {
@ -126,6 +127,7 @@ impl<B: hal::Backend> RenderPass<B> {
raw: B::CommandBuffer,
cmb_id: Stored<CommandBufferId>,
context: RenderPassContext,
sample_count: u8,
) -> Self {
RenderPass {
raw,
@ -145,6 +147,7 @@ impl<B: hal::Backend> RenderPass<B> {
vertex_limit: 0,
instance_limit: 0,
},
sample_count,
}
}
@ -400,10 +403,11 @@ pub extern "C" fn wgpu_render_pass_set_pipeline(
let pipeline_guard = HUB.render_pipelines.read();
let pipeline = &pipeline_guard[pipeline_id];
assert_eq!(
pass.context, pipeline.pass_context,
assert!(
pass.context.compatible(&pipeline.pass_context),
"The render pipeline is not compatible with the pass!"
);
assert_eq!(pipeline.sample_count, pass.sample_count, "The render pipeline and renderpass have mismatching sample_count");
pass.blend_color_status
.require(pipeline.flags.contains(PipelineFlags::BLEND_COLOR));

View File

@ -428,7 +428,7 @@ pub fn map_texture_dimension_size(
D2 => {
assert_eq!(depth, 1);
assert!(sample_size == 1 || sample_size == 2 || sample_size == 4
|| sample_size == 8 || sample_size == 16 || sample_size == 32 || sample_size == 64,
|| sample_size == 8 || sample_size == 16 || sample_size == 32,
"Invalid sample_count of {}", sample_size);
H::D2(width, height, checked_u32_as_u16(array_size), sample_size as u8)
}

View File

@ -94,12 +94,20 @@ enum HostMap {
#[derive(Clone, Debug, Hash, PartialEq)]
pub(crate) struct AttachmentData<T> {
pub colors: ArrayVec<[T; MAX_COLOR_TARGETS]>,
pub resolves: ArrayVec<[T; MAX_COLOR_TARGETS]>,
pub depth_stencil: Option<T>,
}
impl<T: PartialEq> Eq for AttachmentData<T> {}
impl<T> AttachmentData<T> {
pub(crate) fn all(&self) -> impl Iterator<Item = &T> {
self.colors.iter().chain(&self.depth_stencil)
self.colors.iter().chain(&self.resolves).chain(&self.depth_stencil)
}
}
impl RenderPassContext {
// Assumed the renderpass only contains one subpass
pub(crate) fn compatible(&self, other: &RenderPassContext) -> bool {
self.colors == other.colors && self.depth_stencil == other.depth_stencil
}
}
@ -424,7 +432,7 @@ fn map_buffer(
pub struct Device<B: hal::Backend> {
pub(crate) raw: B::Device,
adapter_id: AdapterId,
pub(crate) adapter_id: AdapterId,
pub(crate) queue_group: hal::QueueGroup<B, hal::General>,
pub(crate) com_allocator: command::CommandAllocator<B>,
mem_allocator: Mutex<Heaps<B>>,
@ -1394,6 +1402,11 @@ pub fn device_create_render_pipeline(
device_id: DeviceId,
desc: &pipeline::RenderPipelineDescriptor,
) -> pipeline::RenderPipeline<back::Backend> {
let sc = desc.sample_count;
assert!(sc == 1 || sc == 2 || sc == 4 || sc == 8 || sc == 16 || sc == 32,
"Invalid sample_count of {}", sc);
let sc = sc as u8;
let device_guard = HUB.devices.read();
let device = &device_guard[device_id];
let pipeline_layout_guard = HUB.pipeline_layouts.read();
@ -1409,15 +1422,20 @@ pub fn device_create_render_pipeline(
.iter()
.map(|at| hal::pass::Attachment {
format: Some(conv::map_texture_format(at.format)),
samples: desc.sample_count as u8,
samples: sc,
ops: hal::pass::AttachmentOps::PRESERVE,
stencil_ops: hal::pass::AttachmentOps::DONT_CARE,
layouts: hal::image::Layout::General .. hal::image::Layout::General,
})
.collect(),
// We can ignore the resolves as the vulkan specs says:
// As an additional special case, if two render passes have a single subpass,
// they are compatible even if they have different resolve attachment references
// or depth/stencil resolve modes but satisfy the other compatibility conditions.
resolves: ArrayVec::new(),
depth_stencil: depth_stencil_state.map(|at| hal::pass::Attachment {
format: Some(conv::map_texture_format(at.format)),
samples: desc.sample_count as u8,
samples: sc,
ops: hal::pass::AttachmentOps::PRESERVE,
stencil_ops: hal::pass::AttachmentOps::PRESERVE,
layouts: hal::image::Layout::General .. hal::image::Layout::General,
@ -1434,6 +1452,7 @@ pub fn device_create_render_pipeline(
(2, hal::image::Layout::ColorAttachmentOptimal),
(3, hal::image::Layout::ColorAttachmentOptimal),
];
let depth_id = (
desc.color_states_length,
hal::image::Layout::DepthStencilAttachmentOptimal,
@ -1538,8 +1557,17 @@ pub fn device_create_render_pipeline(
.map(conv::map_depth_stencil_state_descriptor)
.unwrap_or_default();
// TODO
let multisampling: Option<hal::pso::Multisampling> = None;
let multisampling: Option<hal::pso::Multisampling> = if sc == 1 {
None
} else {
Some(hal::pso::Multisampling {
rasterization_samples: sc,
sample_shading: None,
sample_mask: !0,
alpha_coverage: false,
alpha_to_one: false,
})
};
// TODO
let baked_states = hal::pso::BakedStates {
@ -1585,6 +1613,7 @@ pub fn device_create_render_pipeline(
let pass_context = RenderPassContext {
colors: color_states.iter().map(|state| state.format).collect(),
resolves: ArrayVec::new(),
depth_stencil: depth_stencil_state.map(|state| state.format),
};
@ -1607,6 +1636,7 @@ pub fn device_create_render_pipeline(
flags,
index_format: desc.vertex_input.index_format,
vertex_strides,
sample_count: sc,
}
}

View File

@ -301,5 +301,6 @@ pub struct RenderPipeline<B: hal::Backend> {
pub(crate) pass_context: RenderPassContext,
pub(crate) flags: PipelineFlags,
pub(crate) index_format: IndexFormat,
pub(crate) sample_count: u8,
pub(crate) vertex_strides: Vec<(BufferAddress, InputStepMode)>,
}