在linux 下用 xcb 基于 共享内存shm 做简单的图像渲染,对接口不太熟悉,折腾不成功。帮我看看哪里出问题,我的代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xcb/xcb.h>
#include <xcb/shm.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <xcb/xproto.h>
#include <unistd.h>
#include <errno.h>
// 定义图像宽度和高度
#define IMAGE_WIDTH 640
#define IMAGE_HEIGHT 480
#define IMAGE_SIZE (IMAGE_WIDTH * IMAGE_HEIGHT * 3) //921,600
int main() {
xcb_void_cookie_t cookie;
xcb_generic_error_t *pError;
char *framebuffer;
// 连接到 X 服务器
xcb_connection_t *connection = xcb_connect(NULL, NULL);
if (xcb_connection_has_error(connection)) {
printf("Error: Failed to connect to X server(%s)\n", strerror(errno));
return 1;
}
// 获取默认屏幕
xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data;
// 创建 XCB 窗口
xcb_window_t windowId = xcb_generate_id(connection);
cookie = xcb_create_window_checked(connection, XCB_COPY_FROM_PARENT, windowId, screen->root,
0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, 0, XCB_WINDOW_CLASS_COPY_FROM_PARENT,
screen->root_visual, 0, NULL);
pError = xcb_request_check(connection, cookie);
if (pError){
printf("xcb_create_window fail(%s)\n", strerror(errno));
free(pError);
goto out;
}
// 获取 XCB 窗口的可视图像
// xcb_visualid_t visual = screen->root_visual;
xcb_gcontext_t gc = xcb_generate_id(connection);
cookie = xcb_create_gc_checked(connection, gc, screen->root, 0, NULL);
pError = xcb_request_check(connection, cookie);
if (pError){
printf("xcb_create_gc fail(%s)\n", strerror(errno));
free(pError);
goto out;
}
// 创建共享内存段
xcb_shm_seg_t shmseg = xcb_generate_id(connection);
xcb_shm_create_segment_cookie_t createSegmentCookie = xcb_shm_create_segment(connection, shmseg, IMAGE_WIDTH * IMAGE_HEIGHT * 3, 0);
xcb_shm_create_segment_reply_t *reply = xcb_shm_create_segment_reply(connection, createSegmentCookie, &pError);
if (!reply){
printf("xcb_shm_create_segment fail(%s)\n", strerror(errno));
goto out;
}
if (pError){
printf("xcb_shm_create_segment_reply fail(%s)\n", strerror(errno));
goto out;
}
int *fds = xcb_shm_create_segment_reply_fds(connection, reply);
if (reply->nfd != 1) {
for (int i = 0; i < reply->nfd; i++){
close(fds[i]);
}
printf("xcb_shm_create_segment_reply_fds fail(%s)\n", strerror(errno));
goto out;
}
printf("nfd = %d, fds[0] = %d\n", reply->nfd, fds[0]);
framebuffer = mmap(NULL, IMAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fds[0], 0);
if (framebuffer == NULL){
printf("mmap fail(%s)\n", strerror(errno));
goto out;
}
cookie = xcb_shm_attach_fd_checked(connection, shmseg, fds[0], 0);
pError = xcb_request_check(connection, cookie);
if (pError){
printf("xcb_shm_attach_fd_checked fail(%s)\n", strerror(errno));
goto out;
}
// 设置 XCB 窗口的属性
uint32_t values[3];
values[0] = XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_BUTTON_RELEASE;
xcb_change_window_attributes(connection, windowId, XCB_CW_EVENT_MASK, values);
// 显示 XCB 窗口
xcb_map_window(connection, windowId);
xcb_flush(connection);
// 绘制图像
while (1) {
// 等待窗口曝光事件
xcb_generic_event_t *event;
event = xcb_wait_for_event(connection);
switch (event->response_type) {
case XCB_KEY_RELEASE: {
xcb_key_release_event_t * key = (xcb_key_release_event_t *)event;
if (key->detail == 10) {
printf("XCB_KEY_RELEASE key detail = %d\n", key->detail);
memset(framebuffer, 0, IMAGE_SIZE);
cookie = xcb_shm_put_image_checked(connection, windowId, gc, IMAGE_WIDTH, IMAGE_HEIGHT, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, 0, 0, 24, XCB_IMAGE_FORMAT_Z_PIXMAP, 0, shmseg, 0);
pError = xcb_request_check(connection, cookie);
if (pError){
printf("xcb_shm_put_image fail(%s)\n", strerror(errno));
}
xcb_flush (connection);
} else if (key->detail == 11) {
printf("XCB_KEY_RELEASE key detail = %d\n", key->detail);
memset(framebuffer, 0xff, IMAGE_SIZE);
cookie = xcb_shm_put_image_checked(connection, windowId, gc, IMAGE_WIDTH, IMAGE_HEIGHT, 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT,
0, 0, 24, XCB_IMAGE_FORMAT_Z_PIXMAP, 0, shmseg, 0);
pError = xcb_request_check(connection, cookie);
if (pError){
printf("xcb_shm_put_image fail(%s)\n", strerror(errno));
}
xcb_flush (connection);
} else if (key->detail == 9) {
printf("out\n");
goto out;
}
break;
}
default:
break;
}
free(event);
}
out:
// 分离共享内存和销毁共享内存段
xcb_shm_detach(connection, shmseg);
// 关闭连接并清理资源
xcb_disconnect(connection);
return 0;
}