gpt4 book ai didi

linux - 如果 "pure XCB"OpenGL 是不可能的,那么 xcb/glx.h 中的 XCB/GLX API 有什么用?

转载 作者:IT王子 更新时间:2023-10-29 01:25:49 28 4
gpt4 key购买 nike

官方 XCB 文档告诉我们 using OpenGL purely with XCB is impossible : 还必须使用 Xlib。

This post作者 Bart Massey(XCB 的创建者)并不认为这应该是不可能的。但我确定我遗漏了一些东西。

我花了几个小时浏览 xcb/glx.h,它组织得很好 here .在我看来,它像是一个成熟的 API。但我无法让它工作。

问题

  1. XCB/GLX API 没用吗? xcb/glx.h 的用途是什么?
  2. 如何使用 API?

(注意。这是了解 XCB 工作原理的持续努力的一部分。)

相关SO thread .


次要的、冗长的东西

如果有人愿意破解它,这里是 XCB 邮件列表中原始帖子的源代码,稍微精简并放入一个文件中。

您会注意到 xcb_glx_make_context_current 返回error 169(不知道那是什么意思),但仅当 xcb_glx_create_window 采用 0NULL 作为最后两个参数。这些参数涉及一个属性数组,它似乎是由函数 xcb_glx_create_window_attribs 返回的,但我不知道如何使用它...

int main()之前的长辅助函数只是表示两个返回两个整数,xcb_glx_fbconfig_t fbconfig xcb_visualid_t glx_visual,对应第一个“匹配”帧缓冲区配置。在我的平台上,它们是 0xa70x24。它们正是 Xlib/GLX 例程(实际有效)返回的内容,所以我知道我选择的帧缓冲区配置没问题。

因此,问题似乎发生在 xcb_glx_create_windowxcb_glx_make_context_current 之间的某处......

// gcc main2.c -o main -lxcb -lxcb-glx -lGL && ./main2
// TODO free replies

#include <stdio.h>
#include <stdlib.h>
#include <xcb/glx.h>
#include <GL/gl.h>

#define W 1024
#define H 1024

// parameter types returned by xcb_glx_get_fb_configs
#define GLX_DRAWABLE_TYPE 0x8010
#define GLX_RENDER_TYPE 0x8011
#define GLX_DOUBLEBUFFER 5
#define GLX_RED_SIZE 8
#define GLX_GREEN_SIZE 9
#define GLX_BLUE_SIZE 10
#define GLX_RGBA_BIT 0x00000001
#define GLX_RGBA_TYPE 0x8014
#define GLX_STENCIL_SIZE 13
#define GLX_DEPTH_SIZE 12
#define GLX_BUFFER_SIZE 2
#define GLX_ALPHA_SIZE 11
#define GLX_X_RENDERABLE 0x8012

#define GLX_FBCONFIG_ID 0x8013
#define GLX_VISUAL_ID 0x800b

#define GLX_WINDOW_BIT 0x00000001
#define GLX_PIXMAP_BIT 0x00000002
#define GLX_PBUFFER_BIT 0x00000004


// ------------------------------------------------------------------------------------------------
// fbconfig and visual?
uint32_t glx_attrs[] = {
GLX_DOUBLEBUFFER, 1,
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT|GLX_PIXMAP_BIT|GLX_PBUFFER_BIT,
GLX_X_RENDERABLE, 1,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, 8,
GLX_STENCIL_SIZE, 8,
GLX_DEPTH_SIZE, 24,
GLX_BUFFER_SIZE, 32,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
};

// ------------------------------------------------------------------------------------------------
// This function searches for an @param prop_name in the @param property list of properties of size @param prop. Prop is property count and not buffer size.
uint32_t glx_get_property(const uint32_t* property, const uint props, uint32_t prop_name){
uint i=0;
while(i < props*2){
if(property[i] == prop_name)
return property[i+1];
else i += 2;
}
return -1;
}

// This function chooses and returns specific fbconfig id depending on attributes specified in
// @param attrib list. @param attribsz is the number of properties(not list size)
int32_t glx_choose_fbconfig(xcb_connection_t* connection, uint32_t screen_num, uint32_t* attrib, uint32_t attribsz){
xcb_generic_error_t* xerror;

xcb_glx_get_fb_configs_reply_t* fbconfigs = xcb_glx_get_fb_configs_reply(connection, xcb_glx_get_fb_configs(connection, screen_num), NULL);
uint32_t* prop = xcb_glx_get_fb_configs_property_list(fbconfigs);

uint32_t* fbconfig_line = prop;
uint32_t fbconfig_linesz = fbconfigs->num_properties * 2;

for(uint i=0 ; i<fbconfigs->num_FB_configs; i++){ // for each fbconfig line
uint good_fbconfig = 1;

for(uint j=0 ; j<attribsz*2; j += 2){ // for each attrib
// if property found != property given
if(glx_get_property(fbconfig_line, fbconfigs->num_properties, attrib[j]) != attrib[j+1]) {
good_fbconfig = 0; // invalidate this fbconfig entry, sine one of the attribs doesn't match
break;
}
}

// if all attribs matched, return with fid
if(good_fbconfig){
uint32_t fbconfig_id = glx_get_property(fbconfig_line, fbconfigs->num_properties , GLX_FBCONFIG_ID);
free(fbconfigs);
return fbconfig_id;
}

fbconfig_line += fbconfig_linesz; // next fbconfig line;
}
return -1;
}

// This function returns @param attrib value from a line containing GLX_FBCONFIG_ID of @param fid
// It kind of queries particular fbconfig line for a specific property.
uint32_t glx_get_attrib_from_fbconfig(xcb_connection_t* connection, uint32_t screen_num, uint32_t fid, uint32_t attrib){
xcb_glx_get_fb_configs_reply_t* fbconfigs = xcb_glx_get_fb_configs_reply(connection, xcb_glx_get_fb_configs(connection, screen_num), NULL);
uint32_t* prop = xcb_glx_get_fb_configs_property_list(fbconfigs);

uint i = 0;
uint fid_found = 0;
while(i < fbconfigs->length){
if(prop[i] == GLX_FBCONFIG_ID) {
if(prop[i+1] == fid){
fid_found = 1;
i -= i%(fbconfigs->num_properties * 2); // going to start of the fbconfig line
uint32_t attrib_value = glx_get_property(&prop[i], fbconfigs->num_properties, attrib);
free(fbconfigs);
return attrib_value;
}
}
i+=2;
}
if(fid_found) printf("glx_get_attrib_from_fbconfig: no attrib %u was found in a fbconfig with GLX_FBCONFIG_ID %u\n", attrib, fid);
else printf("glx_get_attrib_from_fbconfig: GLX_FBCONFIG_ID %u was not found!\n", fid);
return -1;
}

// ------------------------------------------------------------------------------------------------
int main(){
xcb_generic_error_t* xerror; // To hold errors!
int screen_number;

xcb_connection_t* connection = xcb_connect(NULL, &screen_number);
xcb_screen_t* screen = xcb_setup_roots_iterator(xcb_get_setup(connection)).data; // getting the default screen
printf("screen %d root %d\n", screen_number, screen->root);

xcb_colormap_t colormap = xcb_generate_id(connection); // generating XID's for our objects!
xcb_window_t window = xcb_generate_id(connection);
xcb_glx_context_t glx_context = xcb_generate_id(connection);
xcb_glx_window_t glx_window = xcb_generate_id(connection);

// ----------------------------------------------------------------------------------------------
xcb_glx_query_version_reply_t* glx_version = xcb_glx_query_version_reply(connection, xcb_glx_query_version(connection, 0, 0), NULL);
printf("glx %d.%d response_type %x pad0 %x sequence %x length %d\n",
glx_version->major_version, glx_version->minor_version, glx_version->response_type,
glx_version->pad0, glx_version->sequence, glx_version->length);

// ----------------------------------------------------------------------------------------------
xcb_glx_fbconfig_t fbconfig = glx_choose_fbconfig(connection, screen_number, glx_attrs, sizeof(glx_attrs)/2/sizeof(uint32_t));
xcb_visualid_t glx_visual = glx_get_attrib_from_fbconfig(connection, screen_number, fbconfig, GLX_VISUAL_ID);
printf("fbconfig %x glx_visual %x\n", fbconfig, glx_visual);

// ----------------------------------------------------------------------------------------------
xcb_glx_create_new_context(connection, glx_context, fbconfig, screen_number, GLX_RGBA_TYPE, 0, 1); // New-style context?
// xcb_glx_create_context(connection, glx_context, glx_visual, 0, 0, 1); // Alt method! Old-style context?

if(!(xcb_glx_is_direct_reply(connection, xcb_glx_is_direct(connection, glx_context), NULL)->is_direct))
puts("glx context is not direct!");

// ----------------------------------------------------------------------------------------------
xcb_create_colormap(connection , XCB_COLORMAP_ALLOC_NONE, colormap, screen->root, glx_visual); // creating colormap

// creating a window, using our new colormap
uint32_t window_mask = XCB_CW_BACK_PIXEL|XCB_CW_EVENT_MASK|XCB_CW_COLORMAP;
uint32_t window_attrs[] = {0x444444, XCB_EVENT_MASK_EXPOSURE|XCB_EVENT_MASK_KEY_PRESS, colormap};

xcb_create_window(connection, screen->root_depth, window, screen->root, 0,0, W,H, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, glx_visual, window_mask, window_attrs);
xcb_map_window(connection, window);

xcb_glx_create_window(connection, screen_number, fbconfig, window, glx_window, 0, NULL);
xcb_flush(connection);

// ----------------------------------------------------------------------------------------------
xcb_glx_make_context_current_reply_t* reply_ctx = xcb_glx_make_context_current_reply(connection, xcb_glx_make_context_current(connection, 0, glx_window, glx_window, glx_context), NULL);
if(!reply_ctx) puts("ERROR xcb_glx_make_context_current returned NULL!");
xcb_glx_context_tag_t glx_context_tag = reply_ctx->context_tag;

// alternative ?
// xcb_glx_make_current_reply_t* reply_mc = xcb_glx_make_current_reply(connection, xcb_glx_make_current(connection, glx_window, glx_context, 0), NULL);
// xcb_glx_context_tag_t glx_context_tag = reply_mc->context_tag;

// ----------------------------------------------------------------------------------------------
xcb_glx_get_error_reply(connection, xcb_glx_get_error(connection, glx_context_tag), &xerror);
if(xerror) printf("\nERROR xcb_glx_get_error %d\n", xerror->error_code);

// ----------------------------------------------------------------------------------------------
xcb_generic_event_t* event;
uint running = 1;
while(running){
event = xcb_poll_for_event(connection);
if(event){
switch (event->response_type) {
case XCB_EXPOSE:
glClearColor(0, .5, 1, 1); // Blue
glFlush();
xcb_glx_swap_buffers(connection, glx_context_tag, glx_window);
puts("Expose!");
break;
case XCB_KEY_PRESS: // exit on key press
running = 0;
break;
}
}
free(event);
}

xcb_disconnect(connection);
}

最佳答案

此处需要了解的重要一点是,XCB 函数直接映射到 X11 协议(protocol)请求。这意味着 xcb_glx_* 函数直接映射到 X11 GLX 协议(protocol)请求。请参阅 https://www.khronos.org/registry/OpenGL/specs/gl/glx1.4.pdf 中的“第 4 章”它列出了所有可用的 GLX 请求。例如,glAreTexturesResident 映射到 xcb/glx.h (https://xcb.freedesktop.org/manual/glx_8h_source.html) 中的 xcb_glx_are_textures_resident_* API。在 Khronos 规范中,您可以阅读什么请求做什么。

What's the purpose of xcb/glx.h?

XCB-GLX 仅与 X 服务器通信,它执行任何硬件初始化或触及 OpenGL 客户端状态。因此,XCB-GLX 不能用作 GLX API 的替代品。 [1]

硬件初始化和其他 GL 内容由 openGL 库完成。这就是实现规范的“另一半”的地方。在 Linux 上,libGL 由 mesa ( https://cgit.freedesktop.org/mesa/mesa/tree/src/glx) 提供。您可以看到 glx 目录中的文件包含 Xlib.h,所以我猜这就是 Xlib 依赖项的来源。这解释了“GLX API 与 Xlib 紧密结合。因此,X Windows 上的 OpenGL 应用程序必须使用 Xlib,因此不能仅使用 XCB 来完成。” [1].

Is the XCB/GLX API useless?

虽然 XCB-GLX API 对最终用户 XCB 应用程序开发人员没有什么值(value),但它可能用于开发新的基于 XCB 的 OpenGL 和 GLX 实现。 XCB 可能会提高 OpenGL 库的速度和质量。 [1]

因此,为了获得纯 XCB GLX,有人需要在 openGL 库中重新实现 GLX:

  • 公开基于 XCB 的 API 以初始化硬件等。
  • 应利用 xcb_glx API 与 X 服务器而非 Xlib 通信。

来自 [1] 的文档说“GLX 系统有两个角色,它与 X 服务器通信并初始化客户端和硬件状态。”

xcb-glx 负责通信角色。另一个角色(基于 XCB 的 OpenGL 和 GLX 实现)目前尚未实现,而且不太可能实现。

“GLX API 是根据 Xlib 指定的,glX 函数使用 Xlib Displays、Windows、Visuals 等。GLX 实现也是使用 Xlib 构建的。” (参见 libGL.so 的导出符号)。为了完成第二个角色,我们需要一个使用 XCB 连接、窗口、视觉效果的同等 API。

编辑:如果目标是编写一个不依赖于 Xlib 的 X11 应用程序,那么也许可以使用 Vulkan 进行渲染。

[1] https://xcb.freedesktop.org/opengl/

免责声明:这是我从我收集到的理解。

关于linux - 如果 "pure XCB"OpenGL 是不可能的,那么 xcb/glx.h 中的 XCB/GLX API 有什么用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41069032/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com