xref: /OK3568_Linux_fs/external/xserver/hw/kdrive/ephyr/ephyr_glamor_glx.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 it's 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
ephyr_glamor_compile_glsl_prog(GLenum type,const char * source)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
ephyr_glamor_build_glsl_prog(GLuint vs,GLuint fs)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
ephyr_glamor_setup_texturing_shader(struct ephyr_glamor * glamor)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 #ifdef GLES_USE_HIGHP
158         "precision highp float;\n"
159 #else
160         "precision mediump float;\n"
161 #endif
162         "#endif\n"
163         "\n"
164         "varying vec2 t;\n"
165         "uniform sampler2D s; /* initially 0 */\n"
166         "\n"
167         "void main()\n"
168         "{\n"
169         "    gl_FragColor = texture2D(s, t);\n"
170         "}\n";
171 
172     GLuint fs, vs, prog;
173 
174     vs = ephyr_glamor_compile_glsl_prog(GL_VERTEX_SHADER, vs_source);
175     fs = ephyr_glamor_compile_glsl_prog(GL_FRAGMENT_SHADER, fs_source);
176     prog = ephyr_glamor_build_glsl_prog(vs, fs);
177 
178     glamor->texture_shader = prog;
179     glamor->texture_shader_position_loc = glGetAttribLocation(prog, "position");
180     assert(glamor->texture_shader_position_loc != -1);
181     glamor->texture_shader_texcoord_loc = glGetAttribLocation(prog, "texcoord");
182     assert(glamor->texture_shader_texcoord_loc != -1);
183 }
184 
185 xcb_connection_t *
ephyr_glamor_connect(void)186 ephyr_glamor_connect(void)
187 {
188     dpy = XOpenDisplay(NULL);
189     if (!dpy)
190         return NULL;
191 
192     XSetEventQueueOwner(dpy, XCBOwnsEventQueue);
193 
194     return XGetXCBConnection(dpy);
195 }
196 
197 void
ephyr_glamor_set_texture(struct ephyr_glamor * glamor,uint32_t tex)198 ephyr_glamor_set_texture(struct ephyr_glamor *glamor, uint32_t tex)
199 {
200     glamor->tex = tex;
201 }
202 
203 static void
ephyr_glamor_set_vertices(struct ephyr_glamor * glamor)204 ephyr_glamor_set_vertices(struct ephyr_glamor *glamor)
205 {
206     glVertexAttribPointer(glamor->texture_shader_position_loc,
207                           2, GL_FLOAT, FALSE, 0, (void *) 0);
208     glVertexAttribPointer(glamor->texture_shader_texcoord_loc,
209                           2, GL_FLOAT, FALSE, 0, (void *) (sizeof (float) * 8));
210 
211     glEnableVertexAttribArray(glamor->texture_shader_position_loc);
212     glEnableVertexAttribArray(glamor->texture_shader_texcoord_loc);
213 }
214 
215 void
ephyr_glamor_damage_redisplay(struct ephyr_glamor * glamor,struct pixman_region16 * damage)216 ephyr_glamor_damage_redisplay(struct ephyr_glamor *glamor,
217                               struct pixman_region16 *damage)
218 {
219     GLint old_vao;
220 
221     /* Skip presenting the output in this mode.  Presentation is
222      * expensive, and if we're just running the X Test suite headless,
223      * nobody's watching.
224      */
225     if (ephyr_glamor_skip_present)
226         return;
227 
228     glXMakeCurrent(dpy, glamor->glx_win, glamor->ctx);
229 
230     glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
231     glBindVertexArray(glamor->vao);
232 
233     glBindFramebuffer(GL_FRAMEBUFFER, 0);
234     glUseProgram(glamor->texture_shader);
235     glViewport(0, 0, glamor->width, glamor->height);
236     if (!ephyr_glamor_gles2)
237         glDisable(GL_COLOR_LOGIC_OP);
238 
239     glActiveTexture(GL_TEXTURE0);
240     glBindTexture(GL_TEXTURE_2D, glamor->tex);
241     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
242 
243     glBindVertexArray(old_vao);
244 
245     glXSwapBuffers(dpy, glamor->glx_win);
246 }
247 
248 /**
249  * Xlib-based handling of xcb events for glamor.
250  *
251  * We need to let the Xlib event filtering run on the event so that
252  * Mesa's dri2_glx.c userspace event mangling gets run, and we
253  * correctly get our invalidate events propagated into the driver.
254  */
255 void
ephyr_glamor_process_event(xcb_generic_event_t * xev)256 ephyr_glamor_process_event(xcb_generic_event_t *xev)
257 {
258 
259     uint32_t response_type = xev->response_type & 0x7f;
260     /* Note the types on wire_to_event: there's an Xlib XEvent (with
261      * the broken types) that it returns, and a protocol xEvent that
262      * it inspects.
263      */
264     Bool (*wire_to_event)(Display *dpy, XEvent *ret, xEvent *event);
265 
266     XLockDisplay(dpy);
267     /* Set the event handler to NULL to get access to the current one. */
268     wire_to_event = XESetWireToEvent(dpy, response_type, NULL);
269     if (wire_to_event) {
270         XEvent processed_event;
271 
272         /* OK they had an event handler.  Plug it back in, and call
273          * through to it.
274          */
275         XESetWireToEvent(dpy, response_type, wire_to_event);
276         xev->sequence = LastKnownRequestProcessed(dpy);
277         wire_to_event(dpy, &processed_event, (xEvent *)xev);
278     }
279     XUnlockDisplay(dpy);
280 }
281 
282 static int
ephyr_glx_error_handler(Display * _dpy,XErrorEvent * ev)283 ephyr_glx_error_handler(Display * _dpy, XErrorEvent * ev)
284 {
285     return 0;
286 }
287 
288 struct ephyr_glamor *
ephyr_glamor_glx_screen_init(xcb_window_t win)289 ephyr_glamor_glx_screen_init(xcb_window_t win)
290 {
291     int (*oldErrorHandler) (Display *, XErrorEvent *);
292     static const float position[] = {
293         -1, -1,
294          1, -1,
295          1,  1,
296         -1,  1,
297         0, 1,
298         1, 1,
299         1, 0,
300         0, 0,
301     };
302     GLint old_vao;
303 
304     GLXContext ctx;
305     struct ephyr_glamor *glamor;
306     GLXWindow glx_win;
307 
308     glamor = calloc(1, sizeof(struct ephyr_glamor));
309     if (!glamor) {
310         FatalError("malloc");
311         return NULL;
312     }
313 
314     glx_win = glXCreateWindow(dpy, fb_config, win, NULL);
315 
316     if (ephyr_glamor_gles2) {
317         static const int context_attribs[] = {
318             GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
319             GLX_CONTEXT_MINOR_VERSION_ARB, 0,
320             GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES_PROFILE_BIT_EXT,
321             0,
322         };
323         if (epoxy_has_glx_extension(dpy, DefaultScreen(dpy),
324                                     "GLX_EXT_create_context_es2_profile")) {
325             ctx = glXCreateContextAttribsARB(dpy, fb_config, NULL, True,
326                                              context_attribs);
327         } else {
328             FatalError("Xephyr -glamor_gles2 rquires "
329                        "GLX_EXT_create_context_es2_profile\n");
330         }
331     } else {
332         if (epoxy_has_glx_extension(dpy, DefaultScreen(dpy),
333                                     "GLX_ARB_create_context")) {
334             static const int context_attribs[] = {
335                 GLX_CONTEXT_PROFILE_MASK_ARB,
336                 GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
337                 GLX_CONTEXT_MAJOR_VERSION_ARB,
338                 GLAMOR_GL_CORE_VER_MAJOR,
339                 GLX_CONTEXT_MINOR_VERSION_ARB,
340                 GLAMOR_GL_CORE_VER_MINOR,
341                 0,
342             };
343             oldErrorHandler = XSetErrorHandler(ephyr_glx_error_handler);
344             ctx = glXCreateContextAttribsARB(dpy, fb_config, NULL, True,
345                                              context_attribs);
346             XSync(dpy, False);
347             XSetErrorHandler(oldErrorHandler);
348         } else {
349             ctx = NULL;
350         }
351 
352         if (!ctx)
353             ctx = glXCreateContext(dpy, visual_info, NULL, True);
354     }
355     if (ctx == NULL)
356         FatalError("glXCreateContext failed\n");
357 
358     if (!glXMakeCurrent(dpy, glx_win, ctx))
359         FatalError("glXMakeCurrent failed\n");
360 
361     glamor->ctx = ctx;
362     glamor->win = win;
363     glamor->glx_win = glx_win;
364     ephyr_glamor_setup_texturing_shader(glamor);
365 
366     glGenVertexArrays(1, &glamor->vao);
367     glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &old_vao);
368     glBindVertexArray(glamor->vao);
369 
370     glGenBuffers(1, &glamor->vbo);
371 
372     glBindBuffer(GL_ARRAY_BUFFER, glamor->vbo);
373     glBufferData(GL_ARRAY_BUFFER, sizeof (position), position, GL_STATIC_DRAW);
374 
375     ephyr_glamor_set_vertices(glamor);
376     glBindVertexArray(old_vao);
377 
378     return glamor;
379 }
380 
381 void
ephyr_glamor_glx_screen_fini(struct ephyr_glamor * glamor)382 ephyr_glamor_glx_screen_fini(struct ephyr_glamor *glamor)
383 {
384     glXMakeCurrent(dpy, None, NULL);
385     glXDestroyContext(dpy, glamor->ctx);
386     glXDestroyWindow(dpy, glamor->glx_win);
387 
388     free(glamor);
389 }
390 
391 xcb_visualtype_t *
ephyr_glamor_get_visual(void)392 ephyr_glamor_get_visual(void)
393 {
394     xcb_screen_t *xscreen =
395         xcb_aux_get_screen(XGetXCBConnection(dpy), DefaultScreen(dpy));
396     int attribs[] = {
397         GLX_RENDER_TYPE, GLX_RGBA_BIT,
398         GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
399         GLX_RED_SIZE, 1,
400         GLX_GREEN_SIZE, 1,
401         GLX_BLUE_SIZE, 1,
402         GLX_DOUBLEBUFFER, 1,
403         None
404     };
405     int event_base = 0, error_base = 0, nelements;
406     GLXFBConfig *fbconfigs;
407 
408     if (!glXQueryExtension (dpy, &error_base, &event_base))
409         FatalError("Couldn't find GLX extension\n");
410 
411     fbconfigs = glXChooseFBConfig(dpy, DefaultScreen(dpy), attribs, &nelements);
412     if (!nelements)
413         FatalError("Couldn't choose an FBConfig\n");
414     fb_config = fbconfigs[0];
415     free(fbconfigs);
416 
417     visual_info = glXGetVisualFromFBConfig(dpy, fb_config);
418     if (visual_info == NULL)
419         FatalError("Couldn't get RGB visual\n");
420 
421     return xcb_aux_find_visual_by_id(xscreen, visual_info->visualid);
422 }
423 
424 void
ephyr_glamor_set_window_size(struct ephyr_glamor * glamor,unsigned width,unsigned height)425 ephyr_glamor_set_window_size(struct ephyr_glamor *glamor,
426                              unsigned width, unsigned height)
427 {
428     if (!glamor)
429         return;
430 
431     glamor->width = width;
432     glamor->height = height;
433 }
434