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

XCB的创建者Bart Massey的This post并不暗示这应该是不可能的。但是我确定我会丢失一些东西。

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

问题

  • XCB/GLX API没有用吗? xcb/glx.h的目的是什么?
  • 如何使用API​​?

  • (注意。这是了解XCB的工作方式的一部分。)

    相关的SO thread

    次要的,stuff绕的东西

    如果有人愿意对此进行破解,请引用XCB邮件列表中原始帖子的来源,将其中的内容精简并放入一个文件中。

    您会注意到xcb_glx_make_context_current返回错误169 (不知道那是什么意思),但是仅在 xcb_glx_create_window的最后两个参数采用0NULL的情况下。这些参数涉及一个属性数组,似乎由xcb_glx_create_window_attribs函数返回,但我不知道如何使用它。
    int main()之前的long helper函数仅意味着两个返回两个整数,xcb_glx_fbconfig_t fbconfig xcb_visualid_t glx_visual,对应于第一个“匹配”帧缓冲区配置。在我的平台上,这些是0xa70x24。它们正是Xlib/GLX例程(实际上有效)返回的内容,因此我知道我选择的framebuffer配置很好。

    因此,问题似乎发生在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规范中,您可以读取请求的内容。



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

    硬件初始化和其他GL东西由openGL lib完成。这就是实现规范的“另一半”的地方。在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]。



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

    因此,要获得纯XCB GLX,需要有人在openGL lib中重新实现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/

    10-11 16:10