以OpenGL/ES视角介绍gfx-hal(Vulkan) Framebuffer接口使用
文档列表见:Rust 移动端跨平台复杂图形渲染项目开发系列总结(目录)
草稿状态
以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: 描述Images
和Framebuffer
的区别。
/// Swapchain backbuffer type
#[derive(Debug)]
pub enum Backbuffer<B: Backend> {/// Color image chainImages(Vec<B::Image>),/// A single opaque framebufferFramebuffer(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.
www.khronos.org/registry/vu…
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 casesamples: 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<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());
}
复制代码
创建CommandBuffer
// 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);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()
,这一步相当于eglSwapbuffer
或EAGLContext presentRenderbuffer
交换前后帧缓冲区,不算OpenGL/ES Framebuffer的操作,但是,不切EGLContext的默认帧缓冲区将看不到画面,为了方便,在此将其当成Framebuffer的协同操作。
// present frame
swapchain.present(&mut queues.queues[0],frame,Some(&*image_present),
)
复制代码
以OpenGL/ES视角介绍gfx-hal(Vulkan) Framebuffer接口使用相关推荐
- OpenGL ES 简介
目录 一.前言 1.WebGL 2.OpenCV 3.Direct3D 4.OpenGL 5.OpenGL ES 和 OpenGL 二.OpenGL ES 跨平台 1.OpenGL ES 2.Meta ...
- OpenGL ES EGL eglDestroyContext
目录 一. EGL 前言 二. EGL 绘制流程简介 三.eglDestroyContext 函数简介 四.eglDestroyContext 使用 四.猜你喜欢 零基础 OpenGL ES 学习路线 ...
- OpenGL ES EGL eglCreatePbufferSurface
目录 一. EGL 前言 二. EGL 绘制流程简介 三.eglCreatePbufferSurface 函数简介 1.eglCreatePbufferSurface 简介 2.eglCreatePb ...
- OpenGL ES EGL eglQueryContext
目录 一. EGL 前言 二. EGL 绘制流程简介 三.eglQueryContext 函数简介 四.eglQueryContext 使用 四.猜你喜欢 零基础 OpenGL ES 学习路线推荐 : ...
- OpenGL ES glut glew glfw glad freeglut
目录 一.简介 1.freeglut 2.glew 3.glut 4.glfw 5.glad 二.分类 1.窗口管理 2.函数加载 三.组合使用 1.freeglut + glew 2.glfw + ...
- OpenGL ES glfw 下载和使用
目录 一.glfw 简介 二.glfw 下载 三.glfw 编译 四.glfw 使用 1.OpenGL glfw + glad 效果演示 2.OpenGL glfw + glad <源码下载&g ...
- OpenGL ES EGL eglDestroySurface
目录 一. EGL 前言 二. EGL 绘制流程简介 三.eglDestroySurface 函数简介 四.eglDestroySurface 使用 四.猜你喜欢 零基础 OpenGL ES 学习路线 ...
- OpenGL ES EGL 简介
目录 一.EGL 简介 二.EGL 跨平台之 ANGLE 1.ANGLE 支持跨平台 2.ANGLE 支持渲染器 3.ANGLE 下载地址 三.EGL 坐标系 四.EGL 绘图步骤 五.猜你喜欢 零基 ...
- OpenGL ES EGL eglSwapBuffer
目录 一. EGL 前言 二. EGL 绘制流程简介 三.eglSwapBuffer 函数简介 四.关于多个 EGLContext 五.共享 EGLContext 六.猜你喜欢 零基础 OpenGL ...
最新文章
- 【Ubuntu】Ubuntu14.04添加163的源
- python能做什么游戏ll-一个简单的python game游戏
- 误删Windows文件后恢复技巧
- 设计模式整理之简单工厂
- AI理论知识整理(11)-线性组合线性相关与线性无关
- 8s 使用本地打包镜像_在Docker环境构建、打包和运行Spring Boot应用
- YARN体系学习笔记
- php7.2 event扩展php_sockets_le_socket错误解决
- web前端新手入门教程:Web 框架的架构模式探讨
- asp.net中用LinkButton取到gridview中当前行的ID值
- python xlutils教程_python xlutils复制表格使用方法
- Mac磁盘工具---Disk Xray三大功能使用指南
- Java毕业设计-社区疫情防控管理系统
- 数学基础知识02——常用积分公式
- 因一纸设计稿,我把竞品APP扒得裤衩不剩(上)
- 利用Travis IC实现Hexo博客自动化部署
- 更新来袭!新增语音添加待办、邮箱通知等功能
- 微信小程序使用后台播放器播放音乐
- [ExtJS] Tpl模板中的extjs控件无法失焦处理
- DBGrid 各属性的设置