搜索
查看
编辑修改
首页
UNITY
NODEJS
PYTHON
AI
GIT
PHP
GO
CEF3
JAVA
HTML
CSS
搜索
Gausst松鼠会
这个屌丝很懒,什么也没留下!
关注作者
热门标签
jquery
HTML
CSS
PHP
ASP
PYTHON
GO
AI
C
C++
C#
PHOTOSHOP
UNITY
iOS
android
vue
xml
爬虫
SEO
LINUX
WINDOWS
JAVA
MFC
CEF3
CAD
NODEJS
GIT
Pyppeteer
article
热门文章
1
论文初稿查重和定稿查重 神码ai
2
深度学习第一步——Pytorch-Gpu环境配置:Win11/Win10+Cuda10.2+cuDNN8.5.0+Pytorch1.8.0(步步巨细,少走十年弯路)
3
HarmonyOS应用开发者基础认证【闯关习题 满分答案】
4
轻松查看数据库正在执行的SQL,并可以追踪、诊断、优化,一站式解决SQL问题
5
Kali Linux:网络与安全专家的终极武器
6
【Unity3D日常开发】Unity3D中实现不同脚本之间的执行顺序控制_unity update执行顺序
7
vue2引入Element UI组件去创建新页面的详细步骤--项目阶段2_新建vue页面
8
【SpringCloud】Eureka基于Ribbon负载均衡的调用链路流程分析
9
04. Idea集成Docker_idea 连接docker
10
关于账本数据库:你想知道的这里都有
当前位置:
article
> 正文
双缓冲(Double Buffer)原理和使用_pwm double buffer
作者:Gausst松鼠会 | 2024-02-11 15:58:04
赞
踩
pwm double buffer
原文转自:http://blog.csdn.net/xiaohui_hubei/article/details/16319249
一、双缓冲作用
双缓冲甚至是多缓冲,在许多情况下都很有用。一般需要使用双缓冲区的地方都是由于“生产者”和“消费者”供需不一致所造成的。这样的情况在很多地方后可能会发生,使用多缓冲可以很好的解决。我举几个常见的例子:
例 1. 在网络传输过程中数据的接收,有时可能数据来的太快来不及接收导致数据丢失。这是由于“发送者”和“接收者”速度不一致所致,在他们之间安排一个或多个缓冲区来存放来不及接收的数据,让速度较慢的“接收者”可以慢慢地取完数据不至于丢失。
例2. 再如,计算机中的三级缓存结构:外存(硬盘)、内存、高速缓存(介于CPU和内存之间,可能由多级)。从左到右他们的存储容量不断减小,但速度不断提升,当然价格也是越来越贵。作为“生产者”的 CPU 处理速度很快,而内存存取速度相对CPU较慢,如果直接在内存中存取数据,他们的速度不一致会导致 CPU 能力下降。因此在他们之间又增加的高速缓存来作为缓冲区平衡二者速度上的差异。
例3. 在图形图像显示过程中,计算机从显示缓冲区取数据然后显示,很多图形的操作都很复杂需要大量的计算,很难访问一次显示缓冲区就能写入待显示的完整图形数据,通常需要多次访问显示缓冲区,每次访问时写入最新计算的图形数据。而这样造成的后果是一个需要复杂计算的图形,你看到的效果可能是一部分一部分地显示出来的,造成很大的闪烁不连贯。而使用双缓冲,可以使你先将计算的中间结果存放在另一个缓冲区中,但全部的计算结束,该缓冲区已经存储了完整的图形之后,再将该缓冲区的图形数据一次性复制到显示缓冲区。
例1 中使用双缓冲是为了防止数据丢失,例2 中使用双缓冲是为了提高 CPU 的处理效率,而例3使用双缓冲是为了防止显示图形时的闪烁延迟等不良体验。
二、双缓冲原理
这里,主要以双缓冲在图形图像显示中的应用做说明。
上面例3中提到了双缓冲的主要原理,这里通过一个图再次理解一下:
图 1 双缓冲示意图
注意,显示缓冲区是和显示器一起的,显示器只负责从显示缓冲区取数据显示。我们通常所说的在显示器上画一条直线,其实就是往该显示缓冲区中写入数据。显示器通过不断的刷新(从显示缓冲区取数据),从而使显示缓冲区中数据的改变及时的反映到显示器上。
这也是显示复杂图形时造成延迟的原因,比如你现在要显示从屏幕中心向外发射的一簇射线,你开始编写代码用一个循环从0度开始到360度,每隔一定角度画一条从圆心开始向外的直线。你每次画线其实是往显示缓冲区写入数据,如果你还没有画完,显示器就从显示缓冲区取数据显示图形,此时你看到的是一个不完整的图形,然后你继续画线,等到显示器再次取显示缓冲区数据显示时,图形比上次完整了一些,依次下去直到显示完整的图形。你看到图形不是一次性完整地显示出来,而是每次显示一部分,从而造成闪烁。
原理懂了,看下 demo 就知道怎么用了。下面先介绍 Win32 API 和 C# 中如何使用双缓冲,其他环境下由于没有用到所以没写,等用到了再在下面补充,不过其他环境下过程也基本相似。
三、双缓冲使用 (Win32 版本)
[cpp]
view plain
copy
LRESULT
CALLBACK WndProc(
HWND
hWnd,
UINT
message,
WPARAM
wParam,
LPARAM
lParam)
{
HDC
hDC, hDCMem;
HBITMAP
hBmpMem, hPreBmp;
switch
(message)
{
case
WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
/* 创建双缓冲区 */
// 创建与当前DC兼容的内存DC
hDCMem = CreateCompatibleDC(hDC);
// 创建一块指定大小的位图
hBmpMem = CreateCompatibleBitmap(hDC, rect.right, rect.bottom);
// 将该位图选入到内存DC中,默认是全黑色的
hPreBmp = SelectObject(hDCMem, hBmpMem);
/* 在双缓冲中绘图 */
// 加载背景位图
hBkBmp = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP1));
hBrush = CreatePatternBrush(hBkBmp);
GetClientRect(hWnd, &rect);
FillRect(hDCMem, &rect, hBrush);
DeleteObject(hBrush);
/* 将双缓冲区图像复制到显示缓冲区 */
BitBlt(hDC, 0, 0, rect.right, rect.bottom, hDCMem, 0, 0, SRCCOPY);
/* 释放资源 */
SelectObject(hDCMem, hPreBmp);
DeleteObject(hMemBmp);
DeleteDC(hDCMem);
EndPaint(hWnd, &ps);
break
;
}
}
使用 Win32 版本时注意释放资源,释放顺序与创建顺序相反。我在使用过程中不小心遗漏了一句上面的 "DeleteObject(hMemBmp);"导致图形显示一段时间后就卡死了,查看内存使用发现内存随时间推移飙升,加上上面这句代码后,就没这个问题了。这也再次提醒我们释放资源是多么重要,成对编程的习惯是多么重要。
图 2 处理几次
WM_PAINT
消息后内存变化图
在使用过程中,如果想更新使用双缓冲区显示的区域,可以使用 InvalidateRect(hWnd, &rect, FALSE); ,这里要注意第三个参数一定要设置成 FALSE ,第三个参数表示更新第二个参数指定的区域时是否擦除背景,因为使用双缓冲技术时是直接复制整个缓冲区数据到显示缓冲区,因此无论原有缓冲区里面有什么都会被覆盖,因此第三个参数设置成 FALSE 有助于提高新能。更主要的原因是,如果先擦除原有缓冲区,会导致中间有一瞬间显示缓冲区被清空(显示为默认背景色),然后等到复制了双缓冲区的数据后再显示新的图像,这将导致闪烁!这与使用双缓冲的本意相违背,所以要注意这一点。
四、双缓冲使用 (MFC 版本)
[cpp]
view plain
copy
void
CGame2Dlg::OnPaint()
{
CPaintDC dc(
this
);
// device context for painting
CRect rect;
GetClientRect(&rect);
// 创建内存DC
CDC memDC;
memDC.CreateCompatibleDC(&dc);
// 创建内存位图
CBitmap bmp;
bmp.CreateCompatibleBitmap(&memDC, rect.right - rect.left, rect.bottom - rect.top);
// 将位图选入DC
memDC.SelectObject(&bmp);
// 绘图
m_pGameEngine->Show(memDC.m_hDC);
// 将后备缓冲区中的图形拷贝到前端缓冲区
dc.BitBlt(0, 0, rect.right - rect.left, rect.bottom - rect.top, &memDC, 0, 0, SRCCOPY);
}
五、双缓冲使用 (C# 版本)
[csharp]
view plain
copy
public
void
Show(System.Windows.Forms.Control control)
{
Graphics gc = control.CreateGraphics();
// 创建缓冲图形上下文 (类似 Win32 中的CreateCompatibleDC)
BufferedGraphicsContext dc =
new
BufferedGraphicsContext();
// 创建指定大小缓冲区 (类似 Win32 中的 CreateCompatibleBitmap)
BufferedGraphics backBuffer = dc.Allocate(gc,
new
Rectangle(
new
Point(0, 0), control.Size));
gc = backBuffer.Graphics;
// 获取缓冲区画布
/* 像使用一般的 Graphics 一样绘图 */
Pen pen =
new
Pen(Color.Gray);
foreach
(Step s
in
m_steps)
{
gc.DrawLine(pen, s.Start, s.End);
}
// 将双缓冲区中的图形渲染到指定画布上 (类似 Win32 中的)BitBlt
backBuffer.Render(control.CreateGraphics());
}
其他版本后续用到时再补充。
参考资料:
文中用到的 Win32 API 在MSDN中的说明:
CreateCompatibleDC
CreateCompatibleBitmap
BitBlt
C# 中使用double buffer
http://msdn.microsoft.com/en-us/library/ms229622(v=vs.110).aspx
声明:
本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:
https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/76006
推荐阅读
article
Linux
查看
内存
和
cpu
利用率
的命令(亲测有效)_
linux
系统
内存
利用率
...
参考资料:https://zhidao.baidu.com/question/287497401.htmlhttps:/...
赞
踩
article
虚拟化
系统
(
XenServer
,
ESXi
)-
ESXi
_
esxi
essentials
是什么
版本
...
VMware vSphere 锁定本词条由“科普中国”百科科学词条编写与应用工作项目审核。VMware vSphere ...
赞
踩
article
linux
下
的
top
命令
初识_
top
命令
的
%mem...
top
命令
是最流行Unix/Linux
的
性能工具之一。系统管理员可用运行
top
命令
监视进程和Linux整体性能。
top
...
赞
踩
article
【
Ubuntu
下开启
定时
任务
crontab
】_
ubuntu
crontab
...
Ubuntu
下开启
定时
任务
crontab
_
ubuntu
crontab
ubuntu
crontab
...
赞
踩
article
Linux
运维
工程师
的
10
个日常
使用
工具分享_
linux
常用
服务器软件
...
Linux
运维
工程师
的
10
个日常
使用
工具分享_
linux
常用
服务器软件
linux
常用
服务器软件
...
赞
踩
article
方舟
生存
进化
ARK个人
服务器
搭建教程保姆级_
arkts
服务端
...
大家在创建新
服务器
新地图时,最好是在ark文件夹中的server文件单独的创建一个新的文件夹命名为server X多少方...
赞
踩
article
【
STM32
】
单片机
启动
文件
分析
01
_
stm32
启动
文件
详解...
单片机
上电后
启动
文件
做了什么_
stm32
启动
文件
详解
stm32
启动
文件
详解 ...
赞
踩
article
Python
进阶:
函数
式
编程
...
函数
式
编程
(Functional Programming)作为一种
编程
范式,近年来在软件开发领域备受关注。它强调将计算视...
赞
踩
article
再看
bit
、k
bit
、
bit
/s,
byte
、k
byte
、
byte
/s...
我们常说硬盘多少多少G,宽带多少多少兆,网速多少多少兆,这个具体什么区分呢?
bit
:存储单位表示的是一位;
byte
:存储...
赞
踩
article
C++
赛马
游戏
...
【代码】
C++
赛马
游戏
。
C++
赛马
游戏
题目: 代码: #include<iostream...
赞
踩
article
CentOS
和
Ubuntu
如何实现
定时
执行
python
脚本
_
ubuntu
每1分钟
脚本
...
一般来说,在
CentOS
下,可以使用crontab进行
定时
任务的处理。1、安装yum install crontabs2...
赞
踩
article
麒麟系统禁用
不必要
的
服务
_
biometric
-
authentication
.
service
...
禁用
不必要
的
服务
说明关闭当前不需要的
服务
,以防止黑客通过相关
服务
的漏洞入侵主机。检查方法1)在终端中输入命令:[test...
赞
踩
article
控制服务和守护进程_job
dev
-
virtio
\
x2dports
-
org
.
qemu
.
guest
_a...
控制服务和守护进程_job
dev
-
virtio
\
x2dports
-
org
.
qemu
.
guest
_agent.0.
dev
...
赞
踩
article
Linux
性能监测工具及调优介绍(from cu)_调优
context
switches
per
...
原贴:http://blog.chinaunix.net/u/26011/showart_365530.html ...
赞
踩
article
使用
crontab
定时任务实现
服务器
磁盘
占用监控,同时把
数据
推送到
数据
库
_将监控
服务器
数据
输出到
数据
...
crontab
shell
磁盘
容量检查
数据
库
脚本启动
crontab
查看
crontab
运行状态遇到的坑
crontab
基本...
赞
踩
article
STM32
FSMC
(
Flexible
static
memory
controller
) 灵活静...
FSMC
模块能够与同步和异步存储器以及16位PC内存卡进行接口。其主要目的是:将AHB事务转换为适当的外部设备协议,满足...
赞
踩
article
上
采样
、
转置
卷积
、
反
卷积
、
反
池化,傻傻分不清_
反
卷积
和
上
采样
的区别...
下
采样
、
转置
卷积
、
反
卷积
、
下池化,傻傻分不清_
反
卷积
和
上
采样
的区别
反
卷积
和
上
采样
的区别 ...
赞
踩
article
Printf
输出
格式总结_
printf
的
输出
规则...
① 首先介绍
printf
输出
正型数,
输出
的
形式为
printf
(“%d”,n);n为变量,n必须被int 或 long i...
赞
踩
article
bat
脚本
关闭
某个
程序
后
,
启动
某些
程序
_
批处理
强制
关闭
进程后
启动
软件...
例子:
关闭
mspaint.exe(画图
程序
)脚本内容:@ echo offecho 准备
关闭
mspaint
程序
...ta...
赞
踩
article
在
Vue
实现
自定义
步骤
条
_
vue
步骤
条关联卡片...
利用
vue
实现的
自定义
样式的
步骤
条;关键点:用到了三目运算,v-show效果图页面的源码
_
vue
步骤
条关联卡片
vue
步骤
...
赞
踩
相关标签
ubuntu
linux
服务器
运维
C++
Linux开发
Linux运维
Linux服务器开发
游戏引擎
驰网艾西
游戏程序
方舟生存进化
单片机
stm32
嵌入式硬件
python
c++
游戏
开发语言
centos
kylin