博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
以OpenGL/ES视角介绍gfx-hal(Vulkan) Framebuffer接口使用
阅读量:6569 次
发布时间:2019-06-24

本文共 5757 字,大约阅读时间需要 19 分钟。

文档列表见:

草稿状态

以OpenGL/ES Framebuffer角度看,如果用gfx-hal(Vulkan)接口实现类似OpenGL/ES Framebuffer的功能,这一过程远比OpenGL/ES那几个函数调用复杂,因为涉及了多个组件:Swapchain、RenderPass、Framebuffer、CommandBuffer、Submission等。对于不同场景,这些组件并不是必需的:

  • 当渲染到屏幕时,它们是必需的,全都要合理配置。
  • 当渲染到纹理(Render to Texture,后面简称RTT)时,可忽略Swaphain,只需RenderPass、Framebuffer、CommandBuffer等。

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: 描述ImagesFramebuffer的区别。

/// Swapchain backbuffer type#[derive(Debug)]pub enum Backbuffer
{ /// Color image chain Images(Vec
), /// 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.

SwapchainConfig初始化

let (caps, formats, _present_modes) = surface.compatibility(&physical_device);println!("formats: {:?}", formats);let format = formats    .map_or(format::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

值得注意的是,RTT场景无需创建Swapchain。

let (swapchain, backbuffer) = device.create_swapchain(    &mut surface,    swap_config,    None,);复制代码

RenderPass

A render pass represents a collection of attachments, subpasses, and dependencies between the subpasses, and describes how the attachments are used over the course of the subpasses. The use of a render pass in a command buffer is a render pass instance.

RenderPass包含Attachment、SubpassDesc和SubpassDependency。RTT场景由于偷懒没创建Surface和Swapchain,那么,在创建Attachment时format值不能再从swapchain获取,改用Image(Texture)的format才合理。

初始化RenderPass

根据前面可知,创建RenderPass需要先创建它的子组件,下面逐次描述。

创建Attachment

let attachment = pass::Attachment {    format: Some(swapchain.format.clone()), // NOTE: RTT case    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,};复制代码

创建SubpassDesc

let subpass = pass::SubpassDesc {    colors: &[(0, image::Layout::ColorAttachmentOptimal)],    depth_stencil: None,    inputs: &[],    resolves: &[],    preserves: &[],};复制代码

创建SubpassDependency

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),};复制代码

创建RenderPass

终于,三大组件就绪后,可以从Device创建一个RenderPass。

let render_pass = device.create_render_pass(&[attachment], &[subpass], &[dependency]);复制代码

Framebuffer

初始化Framebuffer

创建Framebuffer

渲染到View场景会根据swapchain.backbuffer类型进行不同的Framebuffer创建流程,主体逻辑示意如下:

let (frame_images, framebuffers) = match swapchain.backbuffer.take().unwrap() {    Backbuffer::Images(images) => {        let extent = // ...         let pairs = // ...         let fbos = pairs.iter().map(            /* ... */            device.create_framebuffer(/* ... */);            /* ... */).collect();        (pairs, fbos)    }    Backbuffer::Framebuffer(fbo) => (Vec::new(), vec![fbo]),};复制代码

创建CommandPool

let iter_count = if frame_images.len() != 0 {    frame_images.len()} else {    1 // GL can have zero};let mut fences: Vec
= vec![];let mut command_pools: Vec
> = vec![];let mut acquire_semaphores: Vec
= vec![];let mut present_semaphores: Vec
= 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());}复制代码

创建CommandBuffer

// Renderinglet 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);    cmd_buffer.bind_vertex_buffers(        0,        Some((self.vertex_buffer.get_buffer(), 0)),    );    cmd_buffer.bind_graphics_descriptor_sets(        self.pipeline.pipeline_layout,        0,        vec![self.image.desc.set, self.uniform.desc.set],        &[],    ); //TODO    {        let mut encoder = cmd_buffer.begin_render_pass_inline(            render_pass,            framebuffer,            self.viewport.rect,            &[command::ClearValue::Color(command::ClearColor::Float([                cr, cg, cb, 1.0,            ]))],        );        encoder.draw(0..6, 0..1);    }    cmd_buffer.finish()};复制代码

提交CommandBuffer到GPU队列

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(),这一步相当于eglSwapbufferEAGLContext presentRenderbuffer交换前后帧缓冲区,不算OpenGL/ES Framebuffer的操作,但是,不切EGLContext的默认帧缓冲区将看不到画面,为了方便,在此将其当成Framebuffer的协同操作。

// present frameswapchain.present(    &mut queues.queues[0],    frame,    Some(&*image_present),)复制代码

转载地址:http://wzvjo.baihongyu.com/

你可能感兴趣的文章
Python入门(good)
查看>>
程序员必须知道的几个Git代码托管平台(转)
查看>>
[日常] Go语言圣经-基于select的多路复用习题
查看>>
ubuntu获取root权限
查看>>
C#获得枚举类型的长度
查看>>
Unity中使用射线查询MeshCollider背面的方法
查看>>
2016/05/03(接口 买票 临界资源同步锁)
查看>>
点击按钮显示隐藏的表格
查看>>
hibernate中inverse作用
查看>>
迷宫问题//bfs
查看>>
2018-2019-1 20165206 《信息安全系统设计基础》第九周学习总结
查看>>
ASP.NET MVC 防止 CSRF 的方法
查看>>
Qt笔记——入门
查看>>
bootstrap-table对前台页面表格的支持
查看>>
泛型委托Func<string,string>()
查看>>
入门讲解HTML5的画布功能(1)
查看>>
Java enum的用法详解
查看>>
(38)Spring Boot分布式Session状态保存Redis【从零开始学Spring Boot】
查看>>
使用PHP Excel类读取和生成excel文件
查看>>
【转】python包导入细节
查看>>