xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

ephyr_glamor_glx.c (12355B)


      1 /*
      2  * Copyright © 2013 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 /** @file ephyr_glamor_glx.c
     25  *
     26  * Separate file for hiding Xlib and GLX-using parts of xephyr from
     27  * the rest of the server-struct-aware build.
     28  */
     29 
     30 #include <stdlib.h>
     31 #include <X11/Xlib.h>
     32 #include <X11/Xlibint.h>
     33 #undef Xcalloc
     34 #undef Xrealloc
     35 #undef Xfree
     36 #include <X11/Xlib-xcb.h>
     37 #include <xcb/xcb_aux.h>
     38 #include <pixman.h>
     39 #include <epoxy/glx.h>
     40 #include "ephyr_glamor_glx.h"
     41 #include "os.h"
     42 #include <X11/Xproto.h>
     43 
     44 /* until we need geometry shaders GL3.1 should suffice. */
     45 /* Xephyr has its own copy of this for build reasons */
     46 #define GLAMOR_GL_CORE_VER_MAJOR 3
     47 #define GLAMOR_GL_CORE_VER_MINOR 1
     48 /** @{
     49  *
     50  * global state for Xephyr with glamor.
     51  *
     52  * Xephyr can render with multiple windows, but all the windows have
     53  * to be on the same X connection and all have to have the same
     54  * visual.
     55  */
     56 static Display *dpy;
     57 static XVisualInfo *visual_info;
     58 static GLXFBConfig fb_config;
     59 Bool ephyr_glamor_gles2;
     60 Bool ephyr_glamor_skip_present;
     61 /** @} */
     62 
     63 /**
     64  * Per-screen state for Xephyr with glamor.
     65  */
     66 struct ephyr_glamor {
     67     GLXContext ctx;
     68     Window win;
     69     GLXWindow glx_win;
     70 
     71     GLuint tex;
     72 
     73     GLuint texture_shader;
     74     GLuint texture_shader_position_loc;
     75     GLuint texture_shader_texcoord_loc;
     76 
     77     /* Size of the window that we're rendering to. */
     78     unsigned width, height;
     79 
     80     GLuint vao, vbo;
     81 };
     82 
     83 static GLint
     84 ephyr_glamor_compile_glsl_prog(GLenum type, const char *source)
     85 {
     86     GLint ok;
     87     GLint prog;
     88 
     89     prog = glCreateShader(type);
     90     glShaderSource(prog, 1, (const GLchar **) &source, NULL);
     91     glCompileShader(prog);
     92     glGetShaderiv(prog, GL_COMPILE_STATUS, &ok);
     93     if (!ok) {
     94         GLchar *info;
     95         GLint size;
     96 
     97         glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size);
     98         info = malloc(size);
     99         if (info) {
    100             glGetShaderInfoLog(prog, size, NULL, info);
    101             ErrorF("Failed to compile %s: %s\n",
    102                    type == GL_FRAGMENT_SHADER ? "FS" : "VS", info);
    103             ErrorF("Program source:\n%s", source);
    104             free(info);
    105         }
    106         else
    107             ErrorF("Failed to get shader compilation info.\n");
    108         FatalError("GLSL compile failure\n");
    109     }
    110 
    111     return prog;
    112 }
    113 
    114 static GLuint
    115 ephyr_glamor_build_glsl_prog(GLuint vs, GLuint fs)
    116 {
    117     GLint ok;
    118     GLuint prog;
    119 
    120     prog = glCreateProgram();
    121     glAttachShader(prog, vs);
    122     glAttachShader(prog, fs);
    123 
    124     glLinkProgram(prog);
    125     glGetProgramiv(prog, GL_LINK_STATUS, &ok);
    126     if (!ok) {
    127         GLchar *info;
    128         GLint size;
    129 
    130         glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
    131         info = malloc(size);
    132 
    133         glGetProgramInfoLog(prog, size, NULL, info);
    134         ErrorF("Failed to link: %s\n", info);
    135         FatalError("GLSL link failure\n");
    136     }
    137 
    138     return prog;
    139 }
    140 
    141 static void
    142 ephyr_glamor_setup_texturing_shader(struct ephyr_glamor *glamor)
    143 {
    144     const char *vs_source =
    145         "attribute vec2 texcoord;\n"
    146         "attribute vec2 position;\n"
    147         "varying vec2 t;\n"
    148         "\n"
    149         "void main()\n"
    150         "{\n"
    151         "    t = texcoord;\n"
    152         "    gl_Position = vec4(position, 0, 1);\n"
    153         "}\n";
    154 
    155     const char *fs_source =
    156         "#ifdef GL_ES\n"
    157         "precision mediump float;\n"
    158         "#endif\n"
    159         "\n"
    160         "varying vec2 t;\n"
    161         "uniform sampler2D s; /* initially 0 */\n"
    162         "\n"
    163         "void main()\n"
    164         "{\n"
    165         "    gl_FragColor = texture2D(s, t);\n"
    166         "}\n";
    167 
    168     GLuint fs, vs, prog;
    169 
    170     vs = ephyr_glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_source);
    171     fs = ephyr_glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_source);
    172     prog = ephyr_glamor_build_glsl_prog(vs, fs);
    173 
    174     glamor->texture_shader = prog;
    175     glamor->texture_shader_position_loc = glGetAttribLocation(prog, "position");
    176     assert(glamor->texture_shader_position_loc != -1);
    177     glamor->texture_shader_texcoord_loc = glGetAttribLocation(prog, "texcoord");
    178     assert(glamor->texture_shader_texcoord_loc != -1);
    179 }
    180 
    181 xcb_connection_t *
    182 ephyr_glamor_connect(void)
    183 {
    184     dpy = XOpenDisplay(NULL);
    185     if (!dpy)
    186         return NULL;
    187 
    188     XSetEventQueueOwner(dpy, XCBOwnsEventQueue);
    189 
    190     return XGetXCBConnection(dpy);
    191 }
    192 
    193 void
    194 ephyr_glamor_set_texture(struct ephyr_glamor *glamor, uint32_t tex)
    195 {
    196     glamor->tex = tex;
    197 }
    198 
    199 static void
    200 ephyr_glamor_set_vertices(struct ephyr_glamor *glamor)
    201 {
    202     glVertexAttribPointer(glamor->texture_shader_position_loc,
    203                           2, GL_FLOAT, FALSE, 0, (void *) 0);
    204     glVertexAttribPointer(glamor->texture_shader_texcoord_loc,
    205                           2, GL_FLOAT, FALSE, 0, (void *) (sizeof (float) * 8));
    206 
    207     glEnableVertexAttribArray(glamor->texture_shader_position_loc);
    208     glEnableVertexAttribArray(glamor->texture_shader_texcoord_loc);
    209 }
    210 
    211 void
    212 ephyr_glamor_damage_redisplay(struct ephyr_glamor *glamor,
    213                               struct pixman_region16 *damage)
    214 {
    215     GLint old_vao;
    216 
    217     /* Skip presenting the output in this mode.  Presentation is
    218      * expensive, and if we're just running the X Test suite headless,
    219      * nobody's watching.
    220      */
    221     if (ephyr_glamor_skip_present)
    222         return;
    223 
    224     glXMakeCurrent(dpy, glamor->glx_win, glamor->ctx);
    225 
    226     glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
    227     glBindVertexArray(glamor->vao);
    228 
    229     glBindFramebuffer(GL_FRAMEBUFFER, 0);
    230     glUseProgram(glamor->texture_shader);
    231     glViewport(0, 0, glamor->width, glamor->height);
    232     if (!ephyr_glamor_gles2)
    233         glDisable(GL_COLOR_LOGIC_OP);
    234 
    235     glActiveTexture(GL_TEXTURE0);
    236     glBindTexture(GL_TEXTURE_2D, glamor->tex);
    237     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
    238 
    239     glBindVertexArray(old_vao);
    240 
    241     glXSwapBuffers(dpy, glamor->glx_win);
    242 }
    243 
    244 /**
    245  * Xlib-based handling of xcb events for glamor.
    246  *
    247  * We need to let the Xlib event filtering run on the event so that
    248  * Mesa's dri2_glx.c userspace event mangling gets run, and we
    249  * correctly get our invalidate events propagated into the driver.
    250  */
    251 void
    252 ephyr_glamor_process_event(xcb_generic_event_t *xev)
    253 {
    254 
    255     uint32_t response_type = xev->response_type & 0x7f;
    256     /* Note the types on wire_to_event: there's an Xlib XEvent (with
    257      * the broken types) that it returns, and a protocol xEvent that
    258      * it inspects.
    259      */
    260     Bool (*wire_to_event)(Display *dpy, XEvent *ret, xEvent *event);
    261 
    262     XLockDisplay(dpy);
    263     /* Set the event handler to NULL to get access to the current one. */
    264     wire_to_event = XESetWireToEvent(dpy, response_type, NULL);
    265     if (wire_to_event) {
    266         XEvent processed_event;
    267 
    268         /* OK they had an event handler.  Plug it back in, and call
    269          * through to it.
    270          */
    271         XESetWireToEvent(dpy, response_type, wire_to_event);
    272         xev->sequence = LastKnownRequestProcessed(dpy);
    273         wire_to_event(dpy, &processed_event, (xEvent *)xev);
    274     }
    275     XUnlockDisplay(dpy);
    276 }
    277 
    278 static int
    279 ephyr_glx_error_handler(Display * _dpy, XErrorEvent * ev)
    280 {
    281     return 0;
    282 }
    283 
    284 struct ephyr_glamor *
    285 ephyr_glamor_glx_screen_init(xcb_window_t win)
    286 {
    287     int (*oldErrorHandler) (Display *, XErrorEvent *);
    288     static const float position[] = {
    289         -1, -1,
    290          1, -1,
    291          1,  1,
    292         -1,  1,
    293         0, 1,
    294         1, 1,
    295         1, 0,
    296         0, 0,
    297     };
    298     GLint old_vao;
    299 
    300     GLXContext ctx;
    301     struct ephyr_glamor *glamor;
    302     GLXWindow glx_win;
    303 
    304     glamor = calloc(1, sizeof(struct ephyr_glamor));
    305     if (!glamor) {
    306         FatalError("malloc");
    307         return NULL;
    308     }
    309 
    310     glx_win = glXCreateWindow(dpy, fb_config, win, NULL);
    311 
    312     if (ephyr_glamor_gles2) {
    313         static const int context_attribs[] = {
    314             GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
    315             GLX_CONTEXT_MINOR_VERSION_ARB, 0,
    316             GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES_PROFILE_BIT_EXT,
    317             0,
    318         };
    319         if (epoxy_has_glx_extension(dpy, DefaultScreen(dpy),
    320                                     "GLX_EXT_create_context_es2_profile")) {
    321             ctx = glXCreateContextAttribsARB(dpy, fb_config, NULL, True,
    322                                              context_attribs);
    323         } else {
    324             FatalError("Xephyr -glamor_gles2 requires "
    325                        "GLX_EXT_create_context_es2_profile\n");
    326         }
    327     } else {
    328         if (epoxy_has_glx_extension(dpy, DefaultScreen(dpy),
    329                                     "GLX_ARB_create_context")) {
    330             static const int context_attribs[] = {
    331                 GLX_CONTEXT_PROFILE_MASK_ARB,
    332                 GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
    333                 GLX_CONTEXT_MAJOR_VERSION_ARB,
    334                 GLAMOR_GL_CORE_VER_MAJOR,
    335                 GLX_CONTEXT_MINOR_VERSION_ARB,
    336                 GLAMOR_GL_CORE_VER_MINOR,
    337                 0,
    338             };
    339             oldErrorHandler = XSetErrorHandler(ephyr_glx_error_handler);
    340             ctx = glXCreateContextAttribsARB(dpy, fb_config, NULL, True,
    341                                              context_attribs);
    342             XSync(dpy, False);
    343             XSetErrorHandler(oldErrorHandler);
    344         } else {
    345             ctx = NULL;
    346         }
    347 
    348         if (!ctx)
    349             ctx = glXCreateContext(dpy, visual_info, NULL, True);
    350     }
    351     if (ctx == NULL)
    352         FatalError("glXCreateContext failed\n");
    353 
    354     if (!glXMakeCurrent(dpy, glx_win, ctx))
    355         FatalError("glXMakeCurrent failed\n");
    356 
    357     glamor->ctx = ctx;
    358     glamor->win = win;
    359     glamor->glx_win = glx_win;
    360     ephyr_glamor_setup_texturing_shader(glamor);
    361 
    362     glGenVertexArrays(1, &glamor->vao);
    363     glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
    364     glBindVertexArray(glamor->vao);
    365 
    366     glGenBuffers(1, &glamor->vbo);
    367 
    368     glBindBuffer(GL_ARRAY_BUFFER, glamor->vbo);
    369     glBufferData(GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW);
    370 
    371     ephyr_glamor_set_vertices(glamor);
    372     glBindVertexArray(old_vao);
    373 
    374     return glamor;
    375 }
    376 
    377 void
    378 ephyr_glamor_glx_screen_fini(struct ephyr_glamor *glamor)
    379 {
    380     glXMakeCurrent(dpy, None, NULL);
    381     glXDestroyContext(dpy, glamor->ctx);
    382     glXDestroyWindow(dpy, glamor->glx_win);
    383 
    384     free(glamor);
    385 }
    386 
    387 xcb_visualtype_t *
    388 ephyr_glamor_get_visual(void)
    389 {
    390     xcb_screen_t *xscreen =
    391         xcb_aux_get_screen(XGetXCBConnection(dpy), DefaultScreen(dpy));
    392     int attribs[] = {
    393         GLX_RENDER_TYPE, GLX_RGBA_BIT,
    394         GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
    395         GLX_RED_SIZE, 1,
    396         GLX_GREEN_SIZE, 1,
    397         GLX_BLUE_SIZE, 1,
    398         GLX_DOUBLEBUFFER, 1,
    399         None
    400     };
    401     int event_base = 0, error_base = 0, nelements;
    402     GLXFBConfig *fbconfigs;
    403 
    404     if (!glXQueryExtension (dpy, &error_base, &event_base))
    405         FatalError("Couldn't find GLX extension\n");
    406 
    407     fbconfigs = glXChooseFBConfig(dpy, DefaultScreen(dpy), attribs, &nelements);
    408     if (!nelements)
    409         FatalError("Couldn't choose an FBConfig\n");
    410     fb_config = fbconfigs[0];
    411     free(fbconfigs);
    412 
    413     visual_info = glXGetVisualFromFBConfig(dpy, fb_config);
    414     if (visual_info == NULL)
    415         FatalError("Couldn't get RGB visual\n");
    416 
    417     return xcb_aux_find_visual_by_id(xscreen, visual_info->visualid);
    418 }
    419 
    420 void
    421 ephyr_glamor_set_window_size(struct ephyr_glamor *glamor,
    422                              unsigned width, unsigned height)
    423 {
    424     if (!glamor)
    425         return;
    426 
    427     glamor->width = width;
    428     glamor->height = height;
    429 }