use std::sync::Arc;
use vulkano::command_buffer::pool::standard::StandardCommandPoolBuilder;
use vulkano::command_buffer::AutoCommandBufferBuilder;
use vulkano::image::traits::ImageAccess;
use vulkano::image::traits::ImageViewAccess;
use vulkano::pipeline::GraphicsPipelineAbstract;
use vulkano::image::attachment::AttachmentImage;
use vulkano::framebuffer::RenderPassAbstract;
use vulkano::framebuffer::FramebufferAbstract;
use vulkano::descriptor::descriptor_set::FixedSizeDescriptorSetsPool;
use vulkano::format::Format as VkFormat;
use vulkano::image::ImageUsage;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::vertex::SingleBufferDefinition;
use vulkano::framebuffer::Subpass;
use vulkano::framebuffer::Framebuffer;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::command_buffer;
use vulkano::image::swapchain::SwapchainImage;
use vulkano::format::ClearValue;
use Basalt;
use interface::interface::ItfVertInfo;
use shaders;
use parking_lot::Mutex;
use interface::interface::ItfEvent;
#[allow(dead_code)]
struct RenderContext {
target_op: Option<(Arc<dyn ImageAccess + Send + Sync>, Arc<dyn ImageViewAccess + Send + Sync>)>,
target_ms_op: Option<Arc<dyn ImageAccess + Send + Sync>>,
renderpass: Arc<dyn RenderPassAbstract + Send + Sync>,
framebuffer: Vec<Arc<dyn FramebufferAbstract + Send + Sync>>,
pipeline: Arc<dyn GraphicsPipelineAbstract + Send + Sync>,
set_pool: FixedSizeDescriptorSetsPool<Arc<dyn GraphicsPipelineAbstract + Send + Sync>>,
clear_values: Vec<ClearValue>,
}
pub struct ItfRenderer {
basalt: Arc<Basalt>,
rc_op: Option<RenderContext>,
shader_vs: shaders::interface_vs::Shader,
shader_fs: shaders::interface_fs::Shader,
msaa: Mutex<u32>,
scale: Mutex<f32>,
}
impl ItfRenderer {
pub fn new(basalt: Arc<Basalt>) -> Self {
let shader_vs = shaders::interface_vs::Shader::load(basalt.device.clone()).unwrap();
let shader_fs = shaders::interface_fs::Shader::load(basalt.device.clone()).unwrap();
ItfRenderer {
rc_op: None,
msaa: Mutex::new(4),
scale: Mutex::new(1.0),
basalt, shader_vs, shader_fs
}
}
pub fn draw<S: Send + Sync + 'static>(
&mut self,
mut cmd: AutoCommandBufferBuilder<StandardCommandPoolBuilder>,
win_size: [u32; 2],
mut resize: bool,
swap_imgs: &Vec<Arc<SwapchainImage<S>>>,
render_to_swapchain: bool,
image_num: usize
) -> (AutoCommandBufferBuilder<StandardCommandPoolBuilder>, Option<Arc<dyn ImageViewAccess + Send + Sync>>) {
const COLOR_FORMAT: VkFormat = VkFormat::R8G8B8A8Srgb;
let mut samples = self.msaa.lock();
let mut scale = self.scale.lock();
let mut recreate_rc = resize;
self.basalt.interface_ref().itf_events.lock().retain(|e| match e {
ItfEvent::MSAAChanged => {
*samples = self.basalt.interface_ref().msaa();
recreate_rc = true;
false
}, ItfEvent::ScaleChanged => {
*scale = self.basalt.interface_ref().scale();
resize = true;
false
}
});
if self.rc_op.is_none() || recreate_rc {
let target_op = if !render_to_swapchain {
Some(AttachmentImage::with_usage(
self.basalt.device(),
win_size,
COLOR_FORMAT,
ImageUsage {
transfer_source: true,
color_attachment: true,
sampled: true,
.. vulkano::image::ImageUsage::none()
}
).unwrap())
} else {
None
};
let target_ms_op = if *samples > 1 {
Some(AttachmentImage::multisampled_with_usage(
self.basalt.device(),
win_size,
*samples,
COLOR_FORMAT,
ImageUsage {
transfer_source: true,
color_attachment: true,
sampled: true,
.. vulkano::image::ImageUsage::none()
}
).unwrap())
} else {
None
};
let color_format = match render_to_swapchain {
false => COLOR_FORMAT,
true => swap_imgs[0].swapchain().format()
};
let renderpass = match *samples {
1 => Arc::new(
single_pass_renderpass!(self.basalt.device(),
attachments: {
image: {
load: Clear,
store: Store,
format: color_format,
samples: 1,
}
}, pass: {
color: [image],
depth_stencil: {},
resolve: []
}
).unwrap()
) as Arc<dyn RenderPassAbstract + Send + Sync>,
s => if render_to_swapchain {
Arc::new(
single_pass_renderpass!(self.basalt.device(),
attachments: {
image_ms: {
load: Clear,
store: Store,
format: COLOR_FORMAT,
samples: s,
}, image: {
load: Clear,
store: Store,
format: color_format,
samples: 1,
}
}, pass: {
color: [image_ms],
depth_stencil: {},
resolve: [image]
}
).unwrap()
) as Arc<dyn RenderPassAbstract + Send + Sync>
} else {
Arc::new(
single_pass_renderpass!(self.basalt.device(),
attachments: {
image_ms: {
load: Clear,
store: Store,
format: COLOR_FORMAT,
samples: s,
}, image: {
load: Clear,
store: Store,
format: COLOR_FORMAT,
samples: 1,
}
}, pass: {
color: [image_ms],
depth_stencil: {},
resolve: [image]
}
).unwrap()
) as Arc<dyn RenderPassAbstract + Send + Sync>
}
};
let framebuffer = swap_imgs.iter().map(|image| {
if render_to_swapchain {
if *samples > 1 {
Arc::new(Framebuffer::start(renderpass.clone())
.add(target_ms_op.as_ref().unwrap().clone()).unwrap()
.add(image.clone()).unwrap()
.build().unwrap()
) as Arc<dyn vulkano::framebuffer::FramebufferAbstract + Send + Sync>
} else {
Arc::new(Framebuffer::start(renderpass.clone())
.add(image.clone()).unwrap()
.build().unwrap()
) as Arc<dyn vulkano::framebuffer::FramebufferAbstract + Send + Sync>
}
} else {
if *samples > 1 {
Arc::new(Framebuffer::start(renderpass.clone())
.add(target_ms_op.as_ref().unwrap().clone()).unwrap()
.add(target_op.as_ref().unwrap().clone()).unwrap()
.build().unwrap()
) as Arc<dyn vulkano::framebuffer::FramebufferAbstract + Send + Sync>
} else {
Arc::new(Framebuffer::start(renderpass.clone())
.add(target_op.as_ref().unwrap().clone()).unwrap()
.build().unwrap()
) as Arc<dyn vulkano::framebuffer::FramebufferAbstract + Send + Sync>
}
}
}).collect::<Vec<_>>();
let vert_input: Arc<SingleBufferDefinition<ItfVertInfo>> = Arc::new(SingleBufferDefinition::new());
let pipeline = Arc::new(
GraphicsPipeline::start()
.vertex_input(vert_input)
.vertex_shader(self.shader_vs.main_entry_point(), ())
.triangle_list()
.viewports(::std::iter::once(Viewport {
origin: [0.0, 0.0],
depth_range: 0.0 .. 1.0,
dimensions: [win_size[0] as f32, win_size[1] as f32],
}))
.fragment_shader(self.shader_fs.main_entry_point(), ())
.depth_stencil_disabled()
.blend_collective(vulkano::pipeline::blend::AttachmentBlend::alpha_blending())
.render_pass(Subpass::from(renderpass.clone(), 0).unwrap())
.polygon_mode_fill()
.build(self.basalt.device()).unwrap()
) as Arc<dyn GraphicsPipelineAbstract + Send + Sync>;
let set_pool = FixedSizeDescriptorSetsPool::new(pipeline.clone(), 0);
let clear_values = if *samples > 1 {
vec![[0.0, 0.0, 0.0, 0.0].into(), [0.0, 0.0, 0.0, 0.0].into()]
} else {
vec![[0.0, 0.0, 0.0, 0.0].into()]
};
self.rc_op = Some(RenderContext {
target_op: target_op.map(|v| (
v.clone() as Arc<dyn ImageAccess + Send + Sync>,
v as Arc<dyn ImageViewAccess + Send + Sync>
)),
target_ms_op: target_ms_op.map(|v| v as Arc<dyn ImageAccess + Send + Sync>),
renderpass, framebuffer, pipeline, set_pool, clear_values
});
}
let rc = self.rc_op.as_mut().unwrap();
cmd = cmd.begin_render_pass(rc.framebuffer[image_num].clone(), false, rc.clear_values.clone()).unwrap();
for (buf, buf_img, buf_sampler) in self.basalt.interface_ref().odb.draw_data(win_size, resize, *scale) {
let set = rc.set_pool.next().add_sampled_image(buf_img, buf_sampler).unwrap().build().unwrap();
cmd = cmd.draw(rc.pipeline.clone(), &command_buffer::DynamicState::none(), vec![Arc::new(buf)], set, ()).unwrap();
}
cmd = cmd.end_render_pass().unwrap();
(cmd, rc.target_op.as_ref().map(|v| v.1.clone()))
}
}