以OpenGL/ES視角介紹gfx-hal(Vulkan) Framebuffer介面使用
阿新 • • 發佈:2018-11-29
文件列表見:Rust 移動端跨平臺複雜圖形渲染專案開發系列總結(目錄)
草稿狀態
Swapchain
The
Swapchain
is the backend representation of the surface. It consists of multiple buffers, which will be presented on the surface.A
Surface
abstracts the surface of a native window, which will be presented on the display.
Backbuffer - Swapchain的後端緩衝區型別
todo: 描述Images和Framebuffer的區別。
/// Swapchain backbuffer type
#[derive(Debug)]
pub enum Backbuffer<B: Backend> {
/// Color image chain
Images(Vec<B::Image>),
/// A single opaque framebuffer
Framebuffer(B::Framebuffer),
}
複製程式碼
SwapchainConfig
SwapchainConfig定義
/// Contains all the data necessary to create a new `Swapchain`:
/// color, depth, and number of images.
///
/// # Examples
///
/// This type implements the builder pattern, method calls can be
/// easily chained.
///
/// ```no_run
/// # extern crate gfx_hal;
/// # fn main() {
/// # use gfx_hal::{SwapchainConfig};
/// # use gfx_hal::format::Format;
/// let config = SwapchainConfig::new(100, 100, Format::Bgra8Unorm, 2);
/// # }
/// ```
#[derive(Debug, Clone)]
pub struct SwapchainConfig {
/// Presentation mode.
pub present_mode: PresentMode,
/// Format of the backbuffer images.
pub format: Format,
/// Requested image extent. Must be in
/// `SurfaceCapabilities::extents` range.
pub extent: Extent2D,
/// Number of images in the swapchain. Must be in
/// `SurfaceCapabilities::image_count` range.
pub image_count: SwapImageIndex,
/// Number of image layers. Must be lower or equal to
/// `SurfaceCapabilities::max_image_layers`.
pub image_layers: image::Layer,
/// Image usage of the backbuffer images.
pub image_usage: image::Usage,
}
複製程式碼
初始化SwapchainConfig
let (caps, formats, _present_modes) = surface.compatibility(&physical_device);
println!("formats: {:?}", formats);
let format = formats
.map_or(f::Format::Rgba8Srgb, |formats| {
formats
.iter()
.find(|format| format.base_format().1 == ChannelType::Srgb)
.map(|format| *format)
.unwrap_or(formats[0])
});
println!("Surface format: {:?}", format);
let swap_config = SwapchainConfig::from_caps(&caps, format);
複製程式碼
建立Swapchain
todo: 描述Render To Texture(RTT)情況的Swapchain建立注意事項。
let (swapchain, backbuffer) = device.create_swapchain(
&mut surface,
swap_config,
None,
);
複製程式碼
RenderPass
建立RenderPass
let render_pass = {
let attachment = pass::Attachment {
format: Some(swapchain.format.clone()),
samples: 1,
ops: pass::AttachmentOps::new(
pass::AttachmentLoadOp::Clear,
pass::AttachmentStoreOp::Store,
),
stencil_ops: pass::AttachmentOps::DONT_CARE,
layouts: image::Layout::Undefined..image::Layout::Present,
};
let subpass = pass::SubpassDesc {
colors: &[(0, image::Layout::ColorAttachmentOptimal)],
depth_stencil: None,
inputs: &[],
resolves: &[],
preserves: &[],
};
let dependency = pass::SubpassDependency {
passes: pass::SubpassRef::External..pass::SubpassRef::Pass(0),
stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT
..PipelineStage::COLOR_ATTACHMENT_OUTPUT,
accesses: image::Access::empty()
..(image::Access::COLOR_ATTACHMENT_READ | image::Access::COLOR_ATTACHMENT_WRITE),
};
device.create_render_pass(&[attachment], &[subpass], &[dependency])
};
複製程式碼
Framebuffer
建立Framebuffer
let (frame_images, framebuffers) = match swapchain.backbuffer.take().unwrap() {
Backbuffer::Images(images) => {
let extent = image::Extent {
width: swapchain.extent.width as _,
height: swapchain.extent.height as _,
depth: 1,
};
let pairs = images
.into_iter()
.map(|image| {
let rtv = device
.create_image_view(
&image,
image::ViewKind::D2,
swapchain.format,
Swizzle::NO,
COLOR_RANGE.clone(),
)
.unwrap();
(image, rtv)
})
.collect::<Vec<_>>();
let fbos = pairs
.iter()
.map(|&(_, ref rtv)| {
device
.create_framebuffer(
render_pass.render_pass.as_ref().unwrap(),
Some(rtv),
extent,
)
.unwrap()
})
.collect();
(pairs, fbos)
}
Backbuffer::Framebuffer(fbo) => (Vec::new(), vec![fbo]),
};
let iter_count = if frame_images.len() != 0 {
frame_images.len()
} else {
1 // GL can have zero
};
let mut fences: Vec<B::Fence> = vec![];
let mut command_pools: Vec<hal::CommandPool<B, hal::Graphics>> = vec![];
let mut acquire_semaphores: Vec<B::Semaphore> = vec![];
let mut present_semaphores: Vec<B::Semaphore> = vec![];
for _ in 0..iter_count {
fences.push(device.create_fence(true));
command_pools.push(device.create_command_pool_typed(
&queues,
pool::CommandPoolCreateFlags::empty(),
16,
));
acquire_semaphores.push(device.create_semaphore());
present_semaphores.push(device.create_semaphore());
}
複製程式碼
建立渲染命令
// Rendering
let submit = {
let mut cmd_buffer = command_pool.acquire_command_buffer(false);
cmd_buffer.set_viewports(0, &[self.viewport.clone()]);
cmd_buffer.set_scissors(0, &[self.viewport.rect]);
cmd_buffer.bind_graphics_pipeline(self.pipeline.pipeline.as_ref().unwrap());
cmd_buffer.bind_vertex_buffers(
0,
Some((self.vertex_buffer.get_buffer(), 0)),
);
cmd_buffer.bind_graphics_descriptor_sets(
self.pipeline.pipeline_layout.as_ref().unwrap(),
0,
vec![self.image.desc.set.as_ref().unwrap(), self.uniform.desc.as_ref().unwrap().set.as_ref().unwrap()],
&[],
); //TODO
{
let mut encoder = cmd_buffer.begin_render_pass_inline(
render_pass.as_ref().unwrap(),
framebuffer,
self.viewport.rect,
&[command::ClearValue::Color(command::ClearColor::Float([
cr, cg, cb, 1.0,
]))],
);
encoder.draw(0..6, 0..1);
}
cmd_buffer.finish()
};
複製程式碼
提交渲染命令到GPU佇列
Render to Texture(RTT)場景到這一步就結束了,通常還會配置Submission執行完成的回撥,方便我們提交下一個Submission。
let submission = Submission::new()
.wait_on(&[(&*image_acquired, PipelineStage::BOTTOM_OF_PIPE)])
.signal(&[&*image_present])
.submit(Some(submit));
queues.queues[0].submit(submission, Some(framebuffer_fence));
複製程式碼
交換前後幀緩衝區
目前來看,渲染到螢幕才需要swapchain.present()
。
// present frame
swapchain.as_ref().unwrap().present(
&mut queues.queues[0],
frame,
Some(&*image_present),
)
複製程式碼