我想做的是在缓冲区上绘制我的图形然后能够将其原样复制到画布上,这样我就可以做动画并避免闪烁.但我找不到这个选项.谁知道我怎么能这样做?
我在$ work处有一个应用程序,我必须在两个以不同频率调度的实时线程之间移动.(实际的调度是我无法控制的.)应用程序是硬实时的(其中一个线程必须驱动硬件接口),因此线程之间的数据传输应该是无锁的,并且无需等待尽可能.
重要的是要注意,只需要传输一个数据块:因为两个线程以不同的速率运行,所以有时会在较慢的线程的两个唤醒之间完成两个较快的线程迭代; 在这种情况下,可以覆盖写缓冲区中的数据,以便较慢的线程只获取最新的数据.
换句话说,双缓冲解决方案代替队列就足够了.这两个缓冲区在初始化期间分配,读取器和写入线程可以调用类的方法来获取指向这些缓冲区之一的指针.
C++代码:
#include <mutex>
template <typename T>
class ProducerConsumerDoubleBuffer {
public:
ProducerConsumerDoubleBuffer() {
m_write_busy = false;
m_read_idx = m_write_idx = 0;
}
~ProducerConsumerDoubleBuffer() { }
// The writer thread using this class must call
// start_writing() at the start of its iteration
// before doing anything else to get the pointer
// to the current write buffer.
T * start_writing(void) {
std::lock_guard<std::mutex> lock(m_mutex);
m_write_busy = true;
m_write_idx = 1 - m_read_idx;
return &m_buf[m_write_idx];
}
// The …Run Code Online (Sandbox Code Playgroud) c++ concurrency real-time producer-consumer double-buffering
通常情况下,即使使用双缓冲,在调整窗口大小时,似乎也不可避免地会发生闪烁.
第1步,原始窗口.
第2步,调整窗口大小,但额外区域尚未绘制.
步骤3,调整窗口大小,并绘制额外区域.
有可能以某种方式隐藏setp 2吗?我可以暂停调整大小过程直到绘画操作完成吗?
这是一个例子:
#include <Windows.h>
#include <windowsx.h>
#include <Uxtheme.h>
#pragma comment(lib, "Uxtheme.lib")
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL MainWindow_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct);
void MainWindow_OnDestroy(HWND hWnd);
void MainWindow_OnSize(HWND hWnd, UINT state, int cx, int cy);
void MainWindow_OnPaint(HWND hWnd);
int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX wcex = { 0 };
HWND hWnd;
MSG msg;
BOOL ret;
wcex.cbSize = sizeof(wcex);
wcex.lpfnWndProc = WindowProc;
wcex.hInstance = hInstance;
wcex.hIcon = …Run Code Online (Sandbox Code Playgroud) 我有一些使用GDI +绘制到屏幕的自定义(winforms)组件.
为了防止重绘时出现闪烁,我决定启用双缓冲,所以我在构造函数中添加了一行:
public ColourWheel()
{
InitializeComponent();
this.DoubleBuffered = true;
}
Run Code Online (Sandbox Code Playgroud)
哪个适用于此组件(ColourWheel).当我将相同的行添加到我的另外两个(结构相似的)组件的构造函数中时,我会得到一些奇怪的症状:
Application.Run(new Form());.我是否对其中一个或全部进行双缓冲似乎并不重要,它仍然适用于ColourWheel,但不适用于其他.
什么可能导致双缓冲在一个组件上工作,而不是其他组件?
编辑:这是运行时症状的异常细节:
System.ArgumentException未处理Message = Parameter无效.Source = System.Drawing StackTrace:System.Drawing.Graphics.GetHdc(),位于System.Windows.Forms.Control的System.Drawing.BufferedGraphics.Render()的System.Drawing.BufferedGraphics.RenderInternal(HandleRef refTargetDC,BufferedGraphics缓冲区)中.系统中System.Windows.Forms.UserControl.WndProc(Message&m)的System.Windows.Forms.ScrollableControl.WndProc(Message&m)处的System.Windows.Forms.Control.WndProc(Message&m)处的.WmPaint(Message&m) .Windows.Forms.Control.ControlNativeWindow.OnMessage(Message&m)at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message&m)at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,Int32 msg,IntPtr wparam, IntPtr lparam)在System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG&msg)处于System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID,Int32 reason,Int32 pvLoopData)at at System.Windows.Forms.Application.ThreadContext.Run MessageLoopInner(Int32 reason,ApplicationContext context),位于TestForm.Program.Main()的System.Windows.Forms.Application.Run(Form mainForm)的System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason,ApplicationContext context)中D:\ Documents and Settings\Tom Wright\My Documents\Visual Studio 2010\Projects\ColourPicker\TestForm\Program.cs:在System.AppDomain.ExecuteAssembly的System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly,String [] args)的第18行(String assemblyFile,Evidence assemblySecurity,String [] args)在System.Threading.ExecutionContext.Run的System.Threading.ThreadHelper.ThreadStart_Context(Object state)中的Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()(ExecutionContext executionContext,ContextCallback callback) System.Threading.ThreadHelper.ThreadStart()InnerException上的System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回调,对象状态),对象状态,布尔值ignoreSyncCtx):
编辑2:导致问题的两个组件中的一个(更复杂)的OnPaint处理程序:
private void ValueSlider_Paint(object sender, PaintEventArgs e)
{ …Run Code Online (Sandbox Code Playgroud) 我编写了一个简单的Android应用程序,使用派生自定义视图绘制迷宫SurfaceView.它遵循LunarLander示例应用程序的模型,并使用后台线程直接执行所有计算和绘图到SurfaceHolder对象中.
一切都很好,并且它适用于中小型迷宫,但如果我将迷宫单元格大小设置为8像素,则应用程序可以在迷宫中抓取大量单元格.
代码正在做一些我不喜欢的事情,即绘制每个单元格,即使它没有改变,这也是为了避免SurfaceView双缓冲区中的屏幕闪烁(在应用程序的先前迭代中我正在绘制的内容已经改变了导致一个疯狂的混乱).
我想要的是能够使用SurfaceView但更有选择性的东西.这可能吗?如果没有,有哪些替代方案?如何保持屏幕外的位图,并有选择地首先绘制?
编辑:我实现了一个屏幕Bitmap和Canvas组合,由我的定时器驱动状态机写入,只绘制雕刻/解决方案中受影响的区域.我再简单地画整个屏幕外的位图到SurfaceView的内run()方法,这解决了我的问题; 我能够将单元格大小降低到5像素,性能很好.
我们使用以下类在Java应用程序中显示进度条:TextProgressBar
不幸的是,在使用它时,我们遇到了一些闪烁问题(Win 7,Java 7).你有什么提示我们如何避免这种情况吗?我们可以以某种方式重新粉刷它,使用双缓冲或其他什么?任何提示都非常感谢!
我想顺利地在PostScript中运行动画.为了看看我想要什么,让我直接切换到PostScript.调用ghostscript,和
200 dup scale .5 setgray 0 0 3 3 rectfill
Run Code Online (Sandbox Code Playgroud)
我们现在有一个灰色方块.
0 setgray 0 1 3 1 rectfill
Run Code Online (Sandbox Code Playgroud)
带有黑色条纹.我们现在将填充该条纹,连续一次白色和黑色:
{1 setgray 0 1 3 1 rectfill 0 setgray 0 1 3 1 rectfill} loop
Run Code Online (Sandbox Code Playgroud)
您现在将看到一些小于原始黑色条纹的黑色和白色矩形的闪烁.理想情况下,我们会看到原始的灰色方块.或差不多.我今天在哪里可以获得这样的功能?
要查看更有趣的动画序列,搜索大小为5的魔术方块:
wget http://www.complang.tuwien.ac.at/ulrich/gupu/l5.eps.gz
zcat l5.eps.gz | ghostscript -
Run Code Online (Sandbox Code Playgroud)
几年前,我确实试图解决这些问题.但它从未进入过ghostscript或Xfree.看到 这个页面.也许现在有更好的想法?
编辑:到目前为止阅读回复后,让我在这里澄清一个问题.从本质上讲,这个问题有两个独立的问题:
如何从语言层面查看动画?我相信,最好的方法是将每个帧视为一个页面.通过copypage低成本可以实现增量更改.可悲的是,这种语义copypage只出现在1级和2级.在3级,意思copypage改变为showpage.我做了 - 很多年前 - 对ghostscript做了一点修改,将所有可见的变化延迟到copypage或showpage.以这种方式,在服务器(即,显示器)上本地XCopyArea执行包含改变区域的单个.
如何同步视觉显示器上的实际变化以避免所描述的图形中不存在的假象?您看到的不规则闪烁不是PostScript的特权,它似乎存在于我迄今为止看到的任何双缓冲系统中.试着用你认为合适的系统编程.
进一步编辑:
要获得正确的语言级别,即1级或2级(对于ghostscript):
systemdict /.setlanguagelevel known {2 .setlanguagelevel} if …Run Code Online (Sandbox Code Playgroud) 我有一个复杂的绘画要在我的主窗口的WM_PAINT处理程序中实现.
我已经提交了一张图片来说明它:

主窗口具有静态控件,而不是具有样式的按钮SS_NOTIFY.
当用户点击它们时,程序中会发生某些操作,这与现在无关.
下图显示了主窗口中静态控件的位置:

橙色面板上的地图是EMF文件,左上角和右上角的徽标是PNG文件,其他图片是bitmaps.
Visual Styles通过#pragma指令启用.我也GDI+一起使用GDI.
项目是作为空项目创建的,我已经从"临时"编写了所有内容.
为了实现这个任务,我决定将整个画面画出来WM_PAINT,并将透明static control图放在与它们对应的图像上.
为了保持我的代码干净简单,我已经制作了实现上述功能的函数,因此我的WM_PAINT处理程序可以尽可能小.
为了实现从成员arx获得的建议,我发布了一个可以编译的单一源代码,可以重现问题:
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include <gdiplus.h>
#pragma comment( linker, "/manifestdependency:\"type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' \
language='*'\"" )
#pragma comment( lib, "comctl32.lib")
#pragma comment( lib, "Msimg32.lib" )
#pragma comment( lib, "Gdiplus.lib" )
using namespace …Run Code Online (Sandbox Code Playgroud) 我正在Android和原生C++中实现一个用于Android的场景绘图egl 1.1.目前正在使用android's glSurfaceView- 它允许我绘制一个后台缓冲区,它显示在"onDrawFrame"的末尾 - 当后台缓冲区和前台缓冲区交换时.
我的问题是这个 - 我需要能够显示后台缓冲区并继续写入,就像我没有交换一样.这种需求背后的原因是场景非常大,并且每帧构建它是不可能的,也不等待绘图的结束 - 因为用户将不得不等待太长时间.
换句话说-我需要建立现场递增.在渲染过程中的某个时刻,我决定它的时间,我调用eglSwapBuffers哪个显示从后台缓冲区中绘制的内容,但是当我继续写入时,显然我正在写入不同步的"前前缓冲区". (不包含我到目前为止所绘制的内容).
据我所知,我唯一的选择是在交换之前复制后台缓冲区.伪:
我的问题 - 有没有办法做2,4步骤?
glCopyPixels在这种情况下,有用吗?例?glBlitFramebuffer吗?或者我接近这一切都错了?
我已经做过的事情:
EGL_SWAP_BEHAVIOR到EGL_BUFFER_PRESERVED,但它似乎只在某些设备上(如在描述工作Khronos的笔记):某些表面允许应用程序控制是否保留颜色缓冲区内容
我想知道如何正确地双缓冲帧缓冲以避免撕裂.我对这个主题进行了大量的研究,似乎无法找到任何东西.
我试过FBIO_WAITFORVSYNC.但是根据这个帖子:如何在Linux中查询Vsync阶段似乎这不起作用.
我也尝试过每个线程使用FBIOGET_VSCREENINFO和FBIOPAN_DISPLAY:Linux帧缓冲图形和VSync.但由于此线程中讨论的错误导致失败:在fb_var_screeninfo中设置yres_virtual时出现无效参数错误
该线程建议使用不同的驱动程序(vesafb)来解决错误.我设法在我的机器上安装uvesafb,但"无效参数"错误没有消失.
我也尝试过按照这个人的建议调整一个更大的缓冲区:http://betteros.org/tut/graphics1.php#doublebuffer 但mmap一直返回-1.
我还试图实现这里讨论的解决方案:https://pyra-handheld.com/boards/threads/my-frustrating-experiences-with-dev-fb.21062/.然而,线程在没有发布实际解决方案的情况下死亡,我怀疑交换硬件地址的效率(或者甚至可以做到).
任何帮助都会对这个主题非常感激!
由于请求,这里是我想要开始工作的代码:
fb0 = open("/dev/fb0", O_RDWR);
if(fb0 == 0)
error("Could not open framebuffer located in /dev/fb0!");
if (ioctl(fb0, FBIOGET_FSCREENINFO, &screeninfo_fixed) == -1)
error("Could not retrive fixed screen info!");
if (ioctl(fb0, FBIOGET_VSCREENINFO, &screeninfo_var) == -1)
error("Could not retrive variable screen info!");
screeninfo_var.xres_virtual = screeninfo_var.xres;
screeninfo_var.yres_virtual = screeninfo_var.yres * 2;
screeninfo_var.width = screeninfo_var.xres;
screeninfo_var.height = screeninfo_var.yres;
screeninfo_var.xoffset = 0;
screeninfo_var.yoffset = 0;
if (ioctl(fb0, …Run Code Online (Sandbox Code Playgroud) double-buffering ×10
android ×2
c ×2
c++ ×2
winapi ×2
animation ×1
c# ×1
canvas ×1
components ×1
concurrency ×1
egl ×1
flicker ×1
framebuffer ×1
gdi+ ×1
ghostscript ×1
html5 ×1
java ×1
javascript ×1
linux ×1
opengl-es ×1
postscript ×1
progress-bar ×1
real-time ×1
surfaceview ×1
swt ×1
x11 ×1