Commit 76eff110 authored by Benjamin Lee's avatar Benjamin Lee 💬
Browse files

Detect present modes and only allow selecting supported ones.

parent 955ae7af
......@@ -4,6 +4,7 @@ use crate::ui;
use crossbeam::channel::{self, Receiver, Sender};
use gfx_hal::{Backend, PresentMode};
use imgui::{im_str, ImString, Ui};
use smallvec::SmallVec;
use std::time::Duration;
const NETWORK_HISTORY_LENGTH: usize = 256;
......@@ -180,23 +181,25 @@ impl DebugState {
)))
.build();
let supported = graphics.supported_present_modes();
let labels = supported
.iter()
.map(|present_mode| {
match present_mode {
PresentMode::Immediate => im_str!("immediate"),
PresentMode::Relaxed => im_str!("relaxed"),
PresentMode::Fifo => im_str!("fifo"),
PresentMode::Mailbox => im_str!("mailbox"),
}
})
.collect::<SmallVec<[_; 4]>>();
let mut present_mode = graphics.present_mode();
if ui::enum_combo(
&ui,
im_str!("Present mode"),
&mut present_mode,
&[
im_str!("immediate"),
im_str!("relaxed"),
im_str!("fifo"),
im_str!("mailbox"),
],
&[
PresentMode::Immediate,
PresentMode::Relaxed,
PresentMode::Fifo,
PresentMode::Mailbox,
],
&labels,
supported,
4,
) {
graphics.set_present_mode(present_mode);
......
......@@ -24,7 +24,6 @@ use gfx_hal::{
ShaderStageFlags,
Specialization,
VertexBufferDesc,
Viewport,
},
Backend,
DescriptorPool,
......@@ -74,76 +73,6 @@ pub struct CircleRenderer<B: Backend> {
pipeline: B::GraphicsPipeline,
}
fn create_pipeline<'a, B: Backend>(
device: &B::Device,
vs_module: &'a B::ShaderModule,
fs_module: &'a B::ShaderModule,
pipeline_layout: &'a B::PipelineLayout,
render_pass: &'a B::RenderPass,
viewport: &Viewport,
) -> B::GraphicsPipeline {
let vs_entry = EntryPoint {
entry: "main",
module: vs_module,
specialization: Specialization::default(),
};
let fs_entry = EntryPoint {
entry: "main",
module: fs_module,
specialization: Specialization::default(),
};
let shader_entries = GraphicsShaderSet {
vertex: vs_entry,
hull: None,
domain: None,
geometry: None,
fragment: Some(fs_entry),
};
let subpass = Subpass {
index: 0,
main_pass: render_pass,
};
let mut pipeline_desc = GraphicsPipelineDesc::new(
shader_entries,
Primitive::TriangleStrip,
Rasterizer {
cull_face: Face::NONE,
..Rasterizer::FILL
},
pipeline_layout,
subpass,
);
// Enable blending (for fake AA).
pipeline_desc
.blender
.targets
.push(ColorBlendDesc(ColorMask::ALL, BlendState::ALPHA));
pipeline_desc.vertex_buffers.push(VertexBufferDesc {
binding: 0,
stride: mem::size_of::<Vertex>() as u32,
rate: 0,
});
pipeline_desc.attributes.push(AttributeDesc {
location: 0,
binding: 0,
element: Element {
format: Format::Rg32Float,
offset: 0,
},
});
pipeline_desc.baked_states.viewport = Some(viewport.clone());
pipeline_desc.baked_states.scissor = Some(viewport.rect);
unsafe { device.create_graphics_pipeline(&pipeline_desc, None).unwrap() }
}
impl<B: Backend> CircleRenderer<B> {
pub fn new(graphics: &mut Graphics<B>) -> CircleRenderer<B> {
// Create vertex buffer.
......@@ -277,15 +206,70 @@ impl<B: Backend> CircleRenderer<B> {
)
.unwrap()
};
let pipeline = create_pipeline::<B>(
&graphics.device,
&vs_module,
&fs_module,
let vs_entry = EntryPoint {
entry: "main",
module: &vs_module,
specialization: Specialization::default(),
};
let fs_entry = EntryPoint {
entry: "main",
module: &fs_module,
specialization: Specialization::default(),
};
let shader_entries = GraphicsShaderSet {
vertex: vs_entry,
hull: None,
domain: None,
geometry: None,
fragment: Some(fs_entry),
};
let subpass = Subpass {
index: 0,
main_pass: &graphics.render_pass,
};
let mut pipeline_desc = GraphicsPipelineDesc::new(
shader_entries,
Primitive::TriangleStrip,
Rasterizer {
cull_face: Face::NONE,
..Rasterizer::FILL
},
&pipeline_layout,
&graphics.render_pass,
&graphics.swapchain_state.viewport,
subpass,
);
// Enable blending (for fake AA).
pipeline_desc
.blender
.targets
.push(ColorBlendDesc(ColorMask::ALL, BlendState::ALPHA));
pipeline_desc.vertex_buffers.push(VertexBufferDesc {
binding: 0,
stride: mem::size_of::<Vertex>() as u32,
rate: 0,
});
pipeline_desc.attributes.push(AttributeDesc {
location: 0,
binding: 0,
element: Element {
format: Format::Rg32Float,
offset: 0,
},
});
let pipeline = unsafe {
graphics
.device
.create_graphics_pipeline(&pipeline_desc, None)
.unwrap()
};
// When transfer is finished, delete the staging buffers.
unsafe {
graphics
......@@ -313,25 +297,6 @@ impl<B: Backend> CircleRenderer<B> {
ctx: &mut DrawContext<B>,
circles: I,
) {
if ctx.update_viewport {
let cleanup = ctx.cleanup.as_mut().unwrap();
// Silly hack to prevent calling draw more than once in a
// frame from creating a pipeline each time.
if let None = cleanup.pipeline {
let pipeline = create_pipeline::<B>(
ctx.device,
&self.vs_module,
&self.fs_module,
&self.pipeline_layout,
ctx.render_pass,
&ctx.viewport,
);
let old_pipeline = mem::replace(&mut self.pipeline, pipeline);
cleanup.pipeline = Some(old_pipeline);
}
}
// TODO: re-use command buffers
unsafe {
ctx.encoder.bind_vertex_buffers(
......@@ -339,6 +304,8 @@ impl<B: Backend> CircleRenderer<B> {
[(&self.vertex_buffer, 0)].iter().cloned(),
);
ctx.encoder.bind_graphics_pipeline(&self.pipeline);
ctx.encoder.set_viewports(0, Some(ctx.viewport));
ctx.encoder.set_scissors(0, Some(&ctx.viewport.rect));
ctx.encoder.bind_graphics_descriptor_sets(
&self.pipeline_layout,
0,
......
......@@ -103,6 +103,7 @@ pub struct Graphics<B: Backend> {
imgui_renderer: imgui_gfx_hal::Renderer<B>,
color_format: Format,
present_mode: PresentMode,
supported_present_modes: Vec<PresentMode>,
cleanup: ArrayVec<[SmallVec<[Cleanup<B>; 3]>; MAX_FRAMES]>,
current_frame: usize,
swapchain_update: bool,
......@@ -117,16 +118,11 @@ pub struct Graphics<B: Backend> {
pub struct Cleanup<B: Backend> {
framebuffers: Vec<B::Framebuffer>,
frame_views: Vec<B::ImageView>,
pipeline: Option<B::GraphicsPipeline>,
}
pub struct DrawContext<'a, 'b, 'c, B: Backend> {
device: &'c B::Device,
render_pass: &'c B::RenderPass,
encoder: &'a mut RenderPassInlineEncoder<'b, B>,
viewport: &'c Viewport,
update_viewport: bool,
cleanup: Option<&'a mut Cleanup<B>>,
}
#[cfg(feature = "renderdoc")]
......@@ -214,7 +210,6 @@ impl<B: Backend> Graphics<B> {
instance: &I,
mut surface: B::Surface,
imgui: &mut ImGui,
present_mode: PresentMode,
) -> Graphics<B> {
let mut adapters =
instance.enumerate_adapters().into_iter().sorted_by(|a, b| {
......@@ -291,7 +286,19 @@ impl<B: Backend> Graphics<B> {
// Determine image capabilities and color format
// TODO figure out what available present modes are
let (_, formats, ..) = surface.compatibility(physical_device);
let (_, formats, supported_present_modes, _) =
surface.compatibility(physical_device);
// Select present mode.
let present_mode =
if supported_present_modes.contains(&PresentMode::Mailbox) {
// Use mailbox if available.
PresentMode::Mailbox
} else {
// Otherwise default to immediate.
PresentMode::Immediate
};
let color_format = formats.map_or(Format::Rgba8Unorm, |formats| {
formats
.iter()
......@@ -377,7 +384,8 @@ impl<B: Backend> Graphics<B> {
.collect();
// Allocate a separate command pool for each frame, to allow
// resetting the corresponding command buffers individually.
let mut frame_command_pools: ArrayVec<[_; 2]> = (0..MAX_FRAMES)
let mut frame_command_pools: ArrayVec<[_; MAX_FRAMES]> = (0..
MAX_FRAMES)
.map(|_| {
unsafe {
device
......@@ -449,9 +457,14 @@ impl<B: Backend> Graphics<B> {
viewport_update: false,
first_frame: true,
present_mode,
supported_present_modes,
}
}
pub fn supported_present_modes(&self) -> &[PresentMode] {
&self.supported_present_modes
}
pub fn present_mode(&self) -> PresentMode {
self.present_mode
}
......@@ -514,7 +527,6 @@ impl<B: Backend> Graphics<B> {
cleanup = Some(Cleanup {
framebuffers,
frame_views,
pipeline: None,
});
SwapchainState::new(
device,
......@@ -648,12 +660,8 @@ impl<B: Backend> Graphics<B> {
{
let ctx = DrawContext {
device: &self.device,
render_pass: &self.render_pass,
encoder: &mut encoder,
viewport: &self.swapchain_state.viewport,
update_viewport: self.viewport_update,
cleanup: cleanup.as_mut(),
};
draw_fn(ctx);
}
......@@ -774,13 +782,9 @@ impl<B: Backend> Cleanup<B> {
let Cleanup {
framebuffers,
frame_views,
pipeline,
..
} = self;
unsafe {
if let Some(pipeline) = pipeline {
device.destroy_graphics_pipeline(pipeline);
}
for framebuffer in framebuffers {
device.destroy_framebuffer(framebuffer);
}
......
#![feature(duration_float, range_contains, exact_size_is_empty, copy_within)]
#![feature(duration_float, range_contains, copy_within)]
extern crate gfx_backend_vulkan as backend;
use ctrlc;
use gfx_hal::PresentMode;
use imgui::ImGui;
use imgui_winit::ImGuiWinit;
use nalgebra::Point2;
......@@ -102,12 +101,7 @@ fn run_gui() {
let instance = backend::Instance::create("Ball", 1);
let surface = instance.create_surface(&window);
let mut graphics = graphics::Graphics::new(
&instance,
surface,
&mut imgui,
PresentMode::Immediate,
);
let mut graphics = graphics::Graphics::new(&instance, surface, &mut imgui);
let mut circle_rend = graphics::CircleRenderer::new(&mut graphics);
let mut renderdoc = graphics::renderdoc::init();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment