C语言 如何在XCB上为软件图形制作动画?



>我正在尝试在XCB上显示软件渲染的图形,但面临以下问题:

  • 它不进行动画处理(不经常调用 EXPOSE 事件(
  • 如果我从 Expose 事件处理中提取绘图代码,它会动画化,但闪烁就像没有 Vsync 一样。我的桌面环境(GNOME,AMD Radeon(有VSync,其他应用程序不会闪烁。

这是我的代码:

#include <stdlib.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <xcb/xcb.h>
#include <xcb/shm.h>
#include <xcb/xcb_image.h>
int main()
{
xcb_gcontext_t       gcontext;
xcb_generic_event_t *e;
uint32_t             value_mask = 0;
uint32_t             value_list[ 2 ];
const int width = 1200;
const int height = 675;
xcb_connection_t* c = xcb_connect( NULL, NULL );
xcb_screen_t* screen = xcb_setup_roots_iterator( xcb_get_setup( c ) ).data;
value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
value_list[ 0 ] = screen->black_pixel;
value_list[ 1 ] = XCB_EVENT_MASK_EXPOSURE;
xcb_window_t win = xcb_generate_id( c );
xcb_create_window( c,                             
XCB_COPY_FROM_PARENT,         
win,                          
screen->root,              
0, 0,                    
width, height,           
10,                      
XCB_WINDOW_CLASS_INPUT_OUTPUT, 
screen->root_visual,           
value_mask, value_list );      
value_mask = XCB_GC_FOREGROUND | XCB_GC_GRAPHICS_EXPOSURES;
value_list[ 0 ] = screen->black_pixel;
value_list[ 1 ] = 0;
gcontext = xcb_generate_id( c );
xcb_create_gc( c, gcontext, win, value_mask, value_list );
xcb_map_window( c, win );
xcb_flush( c );
xcb_shm_query_version_reply_t* reply = xcb_shm_query_version_reply(
c,
xcb_shm_query_version( c ),
NULL
);
xcb_shm_segment_info_t info;
info.shmid   = shmget( IPC_PRIVATE, width * height * 4, IPC_CREAT | 0777 );
info.shmaddr = shmat( info.shmid, 0, 0 );
info.shmseg = xcb_generate_id( c );
xcb_shm_attach( c, info.shmseg, info.shmid, 0 );
shmctl( info.shmid, IPC_RMID, 0 );
uint32_t* data = info.shmaddr;    
xcb_pixmap_t pix = xcb_generate_id( c );
xcb_shm_create_pixmap(
c,
pix,
win,
width, height,
screen->root_depth,
info.shmseg,
0
);
int ry = 0;
while ((e = xcb_wait_for_event( c )))
{        
switch (e->response_type & ~0x80)
{
case XCB_EXPOSE:
{
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
data[ y * width + x ] = 0x0000FF00;
}
}
++ry;
if (ry > 400) ry = 0;
for (int y = ry; y < ry + 50; ++y)
{
for (int x = 0; x < 50; ++x)
{
data[ y * width + x ] = 0x00FF0000;
}
}
xcb_copy_area(
c,
pix,
win,
gcontext,
0, 0, 0, 0,
width, height
);
xcb_flush( c );
}
break;
}
default: break;
}
free( e );
}
return 0;
}

代码垂直移动一个小矩形。

如何将此代码转换为无闪烁动画?

它不进行动画处理(不经常调用 EXPOSE 事件(

EXPOSE 事件仅在必须重绘时发送到窗口(例如:变得可见或调整为更大的大小,或者此窗口上方的窗口已关闭(。

如果窗口的内容发生更改,则必须自己重绘。例如,可以使用select()等待 X11 事件一段时间,然后绘制新版本的动画。

如果我从 Expose 事件处理中提取绘图代码,它会动画化,但闪烁 [...]

在使您的示例代码工作后,我在这里看到一些闪烁,窗口切换到黑色并返回。发生这种情况是因为您将窗口的背景色设置为黑色。因此,在发送 EXPOSE 事件之前,X11 服务器会用黑色填充暴露区域。如果我删除背景像素值,那么闪烁在这里消失。

[...]就像没有Vsync一样。

X11 中没有比 Vsync 更好的了。X11 是即时模式绘图,无法告诉 X11 服务器您已完成帧的制作。

但是,您在这里通过让 CopyArea 请求更新窗口来做正确的事情。这保证以原子方式更新窗口,但我不确定它是否同步到垂直刷新。

顺便说一句:您的动画只是向下移动一个矩形。这里不能有撕裂。

最新更新