1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright © 2017 Red Hat Inc.
3*4882a593Smuzhiyun *
4*4882a593Smuzhiyun * Permission is hereby granted, free of charge, to any person
5*4882a593Smuzhiyun * obtaining a copy of this software and associated documentation
6*4882a593Smuzhiyun * files (the "Software"), to deal in the Software without
7*4882a593Smuzhiyun * restriction, including without limitation the rights to use, copy,
8*4882a593Smuzhiyun * modify, merge, publish, distribute, sublicense, and/or sell copies
9*4882a593Smuzhiyun * of the Software, and to permit persons to whom the Software is
10*4882a593Smuzhiyun * furnished to do so, subject to the following conditions:
11*4882a593Smuzhiyun *
12*4882a593Smuzhiyun * The above copyright notice and this permission notice (including
13*4882a593Smuzhiyun * the next paragraph) shall be included in all copies or substantial
14*4882a593Smuzhiyun * portions of the Software.
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17*4882a593Smuzhiyun * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*4882a593Smuzhiyun * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19*4882a593Smuzhiyun * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20*4882a593Smuzhiyun * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21*4882a593Smuzhiyun * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22*4882a593Smuzhiyun * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23*4882a593Smuzhiyun * DEALINGS IN THE SOFTWARE.
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * Authors:
26*4882a593Smuzhiyun * Lyude Paul <lyude@redhat.com>
27*4882a593Smuzhiyun *
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #include "xwayland.h"
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun #include "wayland-eglstream-client-protocol.h"
33*4882a593Smuzhiyun #include "wayland-eglstream-controller-client-protocol.h"
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define MESA_EGL_NO_X11_HEADERS
36*4882a593Smuzhiyun #define EGL_NO_X11
37*4882a593Smuzhiyun #include <glamor_egl.h>
38*4882a593Smuzhiyun #include <glamor.h>
39*4882a593Smuzhiyun #include <glamor_transform.h>
40*4882a593Smuzhiyun #include <glamor_transfer.h>
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #include <xf86drm.h>
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #include <epoxy/egl.h>
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun struct xwl_eglstream_pending_stream {
47*4882a593Smuzhiyun PixmapPtr pixmap;
48*4882a593Smuzhiyun WindowPtr window;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun struct xwl_pixmap *xwl_pixmap;
51*4882a593Smuzhiyun struct wl_callback *cb;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun Bool is_valid;
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun struct xorg_list link;
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun struct xwl_eglstream_private {
59*4882a593Smuzhiyun EGLDeviceEXT egl_device;
60*4882a593Smuzhiyun struct wl_eglstream_display *display;
61*4882a593Smuzhiyun struct wl_eglstream_controller *controller;
62*4882a593Smuzhiyun uint32_t display_caps;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun EGLConfig config;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun SetWindowPixmapProcPtr SetWindowPixmap;
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun struct xorg_list pending_streams;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun Bool have_egl_damage;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun GLint blit_prog;
73*4882a593Smuzhiyun GLuint blit_vao;
74*4882a593Smuzhiyun GLuint blit_vbo;
75*4882a593Smuzhiyun GLuint blit_is_rgba_pos;
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun
78*4882a593Smuzhiyun struct xwl_pixmap {
79*4882a593Smuzhiyun struct wl_buffer *buffer;
80*4882a593Smuzhiyun struct xwl_screen *xwl_screen;
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun /* The stream and associated resources have their own lifetime seperate
83*4882a593Smuzhiyun * from the pixmap's */
84*4882a593Smuzhiyun int refcount;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun EGLStreamKHR stream;
87*4882a593Smuzhiyun EGLSurface surface;
88*4882a593Smuzhiyun };
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun static DevPrivateKeyRec xwl_eglstream_private_key;
91*4882a593Smuzhiyun static DevPrivateKeyRec xwl_eglstream_window_private_key;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun static inline struct xwl_eglstream_private *
xwl_eglstream_get(struct xwl_screen * xwl_screen)94*4882a593Smuzhiyun xwl_eglstream_get(struct xwl_screen *xwl_screen)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun return dixLookupPrivate(&xwl_screen->screen->devPrivates,
97*4882a593Smuzhiyun &xwl_eglstream_private_key);
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun static inline struct xwl_eglstream_pending_stream *
xwl_eglstream_window_get_pending(WindowPtr window)101*4882a593Smuzhiyun xwl_eglstream_window_get_pending(WindowPtr window)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun return dixLookupPrivate(&window->devPrivates,
104*4882a593Smuzhiyun &xwl_eglstream_window_private_key);
105*4882a593Smuzhiyun }
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun static inline void
xwl_eglstream_window_set_pending(WindowPtr window,struct xwl_eglstream_pending_stream * stream)108*4882a593Smuzhiyun xwl_eglstream_window_set_pending(WindowPtr window,
109*4882a593Smuzhiyun struct xwl_eglstream_pending_stream *stream)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun dixSetPrivate(&window->devPrivates,
112*4882a593Smuzhiyun &xwl_eglstream_window_private_key, stream);
113*4882a593Smuzhiyun }
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun static GLint
xwl_eglstream_compile_glsl_prog(GLenum type,const char * source)116*4882a593Smuzhiyun xwl_eglstream_compile_glsl_prog(GLenum type, const char *source)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun GLint ok;
119*4882a593Smuzhiyun GLint prog;
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun prog = glCreateShader(type);
122*4882a593Smuzhiyun glShaderSource(prog, 1, (const GLchar **) &source, NULL);
123*4882a593Smuzhiyun glCompileShader(prog);
124*4882a593Smuzhiyun glGetShaderiv(prog, GL_COMPILE_STATUS, &ok);
125*4882a593Smuzhiyun if (!ok) {
126*4882a593Smuzhiyun GLchar *info;
127*4882a593Smuzhiyun GLint size;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun glGetShaderiv(prog, GL_INFO_LOG_LENGTH, &size);
130*4882a593Smuzhiyun info = malloc(size);
131*4882a593Smuzhiyun if (info) {
132*4882a593Smuzhiyun glGetShaderInfoLog(prog, size, NULL, info);
133*4882a593Smuzhiyun ErrorF("Failed to compile %s: %s\n",
134*4882a593Smuzhiyun type == GL_FRAGMENT_SHADER ? "FS" : "VS", info);
135*4882a593Smuzhiyun ErrorF("Program source:\n%s", source);
136*4882a593Smuzhiyun free(info);
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun else
139*4882a593Smuzhiyun ErrorF("Failed to get shader compilation info.\n");
140*4882a593Smuzhiyun FatalError("GLSL compile failure\n");
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun return prog;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun static GLuint
xwl_eglstream_build_glsl_prog(GLuint vs,GLuint fs)147*4882a593Smuzhiyun xwl_eglstream_build_glsl_prog(GLuint vs, GLuint fs)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun GLint ok;
150*4882a593Smuzhiyun GLuint prog;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun prog = glCreateProgram();
153*4882a593Smuzhiyun glAttachShader(prog, vs);
154*4882a593Smuzhiyun glAttachShader(prog, fs);
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun glLinkProgram(prog);
157*4882a593Smuzhiyun glGetProgramiv(prog, GL_LINK_STATUS, &ok);
158*4882a593Smuzhiyun if (!ok) {
159*4882a593Smuzhiyun GLchar *info;
160*4882a593Smuzhiyun GLint size;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &size);
163*4882a593Smuzhiyun info = malloc(size);
164*4882a593Smuzhiyun
165*4882a593Smuzhiyun glGetProgramInfoLog(prog, size, NULL, info);
166*4882a593Smuzhiyun ErrorF("Failed to link: %s\n", info);
167*4882a593Smuzhiyun FatalError("GLSL link failure\n");
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun return prog;
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun static void
xwl_eglstream_cleanup(struct xwl_screen * xwl_screen)174*4882a593Smuzhiyun xwl_eglstream_cleanup(struct xwl_screen *xwl_screen)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream =
177*4882a593Smuzhiyun xwl_eglstream_get(xwl_screen);
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun if (xwl_eglstream->display)
180*4882a593Smuzhiyun wl_eglstream_display_destroy(xwl_eglstream->display);
181*4882a593Smuzhiyun if (xwl_eglstream->controller)
182*4882a593Smuzhiyun wl_eglstream_controller_destroy(xwl_eglstream->controller);
183*4882a593Smuzhiyun if (xwl_eglstream->blit_prog) {
184*4882a593Smuzhiyun glDeleteProgram(xwl_eglstream->blit_prog);
185*4882a593Smuzhiyun glDeleteBuffers(1, &xwl_eglstream->blit_vbo);
186*4882a593Smuzhiyun }
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun free(xwl_eglstream);
189*4882a593Smuzhiyun }
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun static Bool
xwl_glamor_egl_supports_device_probing(void)192*4882a593Smuzhiyun xwl_glamor_egl_supports_device_probing(void)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun return epoxy_has_egl_extension(NULL, "EGL_EXT_device_base");
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun static void **
xwl_glamor_egl_get_devices(int * num_devices)198*4882a593Smuzhiyun xwl_glamor_egl_get_devices(int *num_devices)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun EGLDeviceEXT *devices, *tmp;
201*4882a593Smuzhiyun Bool ret;
202*4882a593Smuzhiyun int drm_dev_count = 0;
203*4882a593Smuzhiyun int i;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if (!xwl_glamor_egl_supports_device_probing())
206*4882a593Smuzhiyun return NULL;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun /* Get the number of devices */
209*4882a593Smuzhiyun ret = eglQueryDevicesEXT(0, NULL, num_devices);
210*4882a593Smuzhiyun if (!ret || *num_devices < 1)
211*4882a593Smuzhiyun return NULL;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun devices = calloc(*num_devices, sizeof(EGLDeviceEXT));
214*4882a593Smuzhiyun if (!devices)
215*4882a593Smuzhiyun return NULL;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun ret = eglQueryDevicesEXT(*num_devices, devices, num_devices);
218*4882a593Smuzhiyun if (!ret)
219*4882a593Smuzhiyun goto error;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun /* We're only ever going to care about devices that support
222*4882a593Smuzhiyun * EGL_EXT_device_drm, so filter out the ones that don't
223*4882a593Smuzhiyun */
224*4882a593Smuzhiyun for (i = 0; i < *num_devices; i++) {
225*4882a593Smuzhiyun const char *extension_str =
226*4882a593Smuzhiyun eglQueryDeviceStringEXT(devices[i], EGL_EXTENSIONS);
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun if (!epoxy_extension_in_string(extension_str, "EGL_EXT_device_drm"))
229*4882a593Smuzhiyun continue;
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun devices[drm_dev_count++] = devices[i];
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun if (!drm_dev_count)
234*4882a593Smuzhiyun goto error;
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun *num_devices = drm_dev_count;
237*4882a593Smuzhiyun tmp = realloc(devices, sizeof(EGLDeviceEXT) * drm_dev_count);
238*4882a593Smuzhiyun if (!tmp)
239*4882a593Smuzhiyun goto error;
240*4882a593Smuzhiyun
241*4882a593Smuzhiyun devices = tmp;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun return devices;
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun error:
246*4882a593Smuzhiyun free(devices);
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun return NULL;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun static Bool
xwl_glamor_egl_device_has_egl_extensions(void * device,const char ** ext_list,size_t size)252*4882a593Smuzhiyun xwl_glamor_egl_device_has_egl_extensions(void *device,
253*4882a593Smuzhiyun const char **ext_list, size_t size)
254*4882a593Smuzhiyun {
255*4882a593Smuzhiyun EGLDisplay egl_display;
256*4882a593Smuzhiyun int i;
257*4882a593Smuzhiyun Bool has_exts = TRUE;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun egl_display = glamor_egl_get_display(EGL_PLATFORM_DEVICE_EXT, device);
260*4882a593Smuzhiyun if (!egl_display || !eglInitialize(egl_display, NULL, NULL))
261*4882a593Smuzhiyun return FALSE;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun for (i = 0; i < size; i++) {
264*4882a593Smuzhiyun if (!epoxy_has_egl_extension(egl_display, ext_list[i])) {
265*4882a593Smuzhiyun has_exts = FALSE;
266*4882a593Smuzhiyun break;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun eglTerminate(egl_display);
271*4882a593Smuzhiyun return has_exts;
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun static void
xwl_eglstream_unref_pixmap_stream(struct xwl_pixmap * xwl_pixmap)275*4882a593Smuzhiyun xwl_eglstream_unref_pixmap_stream(struct xwl_pixmap *xwl_pixmap)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun struct xwl_screen *xwl_screen = xwl_pixmap->xwl_screen;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun if (--xwl_pixmap->refcount >= 1)
280*4882a593Smuzhiyun return;
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun /* If we're using this stream in the current egl context, unbind it so the
283*4882a593Smuzhiyun * driver doesn't keep it around until the next eglMakeCurrent()
284*4882a593Smuzhiyun * don't have to keep it around until something else changes the surface
285*4882a593Smuzhiyun */
286*4882a593Smuzhiyun xwl_glamor_egl_make_current(xwl_screen);
287*4882a593Smuzhiyun if (eglGetCurrentSurface(EGL_READ) == xwl_pixmap->surface ||
288*4882a593Smuzhiyun eglGetCurrentSurface(EGL_DRAW) == xwl_pixmap->surface) {
289*4882a593Smuzhiyun eglMakeCurrent(xwl_screen->egl_display,
290*4882a593Smuzhiyun EGL_NO_SURFACE, EGL_NO_SURFACE,
291*4882a593Smuzhiyun xwl_screen->egl_context);
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun if (xwl_pixmap->surface)
295*4882a593Smuzhiyun eglDestroySurface(xwl_screen->egl_display, xwl_pixmap->surface);
296*4882a593Smuzhiyun
297*4882a593Smuzhiyun eglDestroyStreamKHR(xwl_screen->egl_display, xwl_pixmap->stream);
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun wl_buffer_destroy(xwl_pixmap->buffer);
300*4882a593Smuzhiyun free(xwl_pixmap);
301*4882a593Smuzhiyun }
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun static Bool
xwl_glamor_eglstream_destroy_pixmap(PixmapPtr pixmap)304*4882a593Smuzhiyun xwl_glamor_eglstream_destroy_pixmap(PixmapPtr pixmap)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun if (xwl_pixmap && pixmap->refcnt == 1)
309*4882a593Smuzhiyun xwl_eglstream_unref_pixmap_stream(xwl_pixmap);
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun return glamor_destroy_pixmap(pixmap);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun static struct wl_buffer *
xwl_glamor_eglstream_get_wl_buffer_for_pixmap(PixmapPtr pixmap,Bool * created)315*4882a593Smuzhiyun xwl_glamor_eglstream_get_wl_buffer_for_pixmap(PixmapPtr pixmap,
316*4882a593Smuzhiyun Bool *created)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun /* XXX created? */
319*4882a593Smuzhiyun return xwl_pixmap_get(pixmap)->buffer;
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun static void
xwl_eglstream_set_window_pixmap(WindowPtr window,PixmapPtr pixmap)323*4882a593Smuzhiyun xwl_eglstream_set_window_pixmap(WindowPtr window, PixmapPtr pixmap)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun struct xwl_screen *xwl_screen = xwl_screen_get(window->drawable.pScreen);
326*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream =
327*4882a593Smuzhiyun xwl_eglstream_get(xwl_screen);
328*4882a593Smuzhiyun struct xwl_eglstream_pending_stream *pending;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun pending = xwl_eglstream_window_get_pending(window);
331*4882a593Smuzhiyun if (pending) {
332*4882a593Smuzhiyun /* The pixmap for this window has changed before the compositor
333*4882a593Smuzhiyun * finished attaching the consumer for the window's pixmap's original
334*4882a593Smuzhiyun * eglstream. A producer can no longer be attached, so the stream's
335*4882a593Smuzhiyun * useless
336*4882a593Smuzhiyun */
337*4882a593Smuzhiyun pending->is_valid = FALSE;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun /* The compositor may still be using the stream, so we can't destroy
340*4882a593Smuzhiyun * it yet. We'll only have a guarantee that the stream is safe to
341*4882a593Smuzhiyun * destroy once we receive the pending wl_display_sync() for this
342*4882a593Smuzhiyun * stream
343*4882a593Smuzhiyun */
344*4882a593Smuzhiyun pending->xwl_pixmap->refcount++;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun xwl_screen->screen->SetWindowPixmap = xwl_eglstream->SetWindowPixmap;
348*4882a593Smuzhiyun (*xwl_screen->screen->SetWindowPixmap)(window, pixmap);
349*4882a593Smuzhiyun xwl_eglstream->SetWindowPixmap = xwl_screen->screen->SetWindowPixmap;
350*4882a593Smuzhiyun xwl_screen->screen->SetWindowPixmap = xwl_eglstream_set_window_pixmap;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun /* Because we run asynchronously with our wayland compositor, it's possible
354*4882a593Smuzhiyun * that an X client event could cause us to begin creating a stream for a
355*4882a593Smuzhiyun * pixmap/window combo before the stream for the pixmap this window
356*4882a593Smuzhiyun * previously used has been fully initialized. An example:
357*4882a593Smuzhiyun *
358*4882a593Smuzhiyun * - Start processing X client events.
359*4882a593Smuzhiyun * - X window receives resize event, causing us to create a new pixmap and
360*4882a593Smuzhiyun * begin creating the corresponding eglstream. This pixmap is known as
361*4882a593Smuzhiyun * pixmap A.
362*4882a593Smuzhiyun * - X window receives another resize event, and again changes it's current
363*4882a593Smuzhiyun * pixmap causing us to create another corresponding eglstream for the same
364*4882a593Smuzhiyun * window. This pixmap is known as pixmap B.
365*4882a593Smuzhiyun * - Start handling events from the wayland compositor.
366*4882a593Smuzhiyun *
367*4882a593Smuzhiyun * Since both pixmap A and B will have scheduled wl_display_sync events to
368*4882a593Smuzhiyun * indicate when their respective streams are connected, we will receive each
369*4882a593Smuzhiyun * callback in the original order the pixmaps were created. This means the
370*4882a593Smuzhiyun * following would happen:
371*4882a593Smuzhiyun *
372*4882a593Smuzhiyun * - Receive pixmap A's stream callback, attach it's stream to the surface of
373*4882a593Smuzhiyun * the window that just orphaned it.
374*4882a593Smuzhiyun * - Receive pixmap B's stream callback, fall over and fail because the
375*4882a593Smuzhiyun * window's surface now incorrectly has pixmap A's stream attached to it.
376*4882a593Smuzhiyun *
377*4882a593Smuzhiyun * We work around this problem by keeping a queue of pending streams, and
378*4882a593Smuzhiyun * only allowing one queue entry to exist for each window. In the scenario
379*4882a593Smuzhiyun * listed above, this should happen:
380*4882a593Smuzhiyun *
381*4882a593Smuzhiyun * - Begin processing X events...
382*4882a593Smuzhiyun * - A window is resized, causing us to add an eglstream (known as eglstream
383*4882a593Smuzhiyun * A) waiting for it's consumer to finish attachment to be added to the
384*4882a593Smuzhiyun * queue.
385*4882a593Smuzhiyun * - Resize on same window happens. We invalidate the previously pending
386*4882a593Smuzhiyun * stream and add another one to the pending queue (known as eglstream B).
387*4882a593Smuzhiyun * - Begin processing Wayland events...
388*4882a593Smuzhiyun * - Receive invalidated callback from compositor for eglstream A, destroy
389*4882a593Smuzhiyun * stream.
390*4882a593Smuzhiyun * - Receive callback from compositor for eglstream B, create producer.
391*4882a593Smuzhiyun * - Success!
392*4882a593Smuzhiyun */
393*4882a593Smuzhiyun static void
xwl_eglstream_consumer_ready_callback(void * data,struct wl_callback * callback,uint32_t time)394*4882a593Smuzhiyun xwl_eglstream_consumer_ready_callback(void *data,
395*4882a593Smuzhiyun struct wl_callback *callback,
396*4882a593Smuzhiyun uint32_t time)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun struct xwl_screen *xwl_screen = data;
399*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream =
400*4882a593Smuzhiyun xwl_eglstream_get(xwl_screen);
401*4882a593Smuzhiyun struct xwl_pixmap *xwl_pixmap;
402*4882a593Smuzhiyun struct xwl_eglstream_pending_stream *pending;
403*4882a593Smuzhiyun Bool found = FALSE;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun wl_callback_destroy(callback);
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun xorg_list_for_each_entry(pending, &xwl_eglstream->pending_streams, link) {
408*4882a593Smuzhiyun if (pending->cb == callback) {
409*4882a593Smuzhiyun found = TRUE;
410*4882a593Smuzhiyun break;
411*4882a593Smuzhiyun }
412*4882a593Smuzhiyun }
413*4882a593Smuzhiyun assert(found);
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun if (!pending->is_valid) {
416*4882a593Smuzhiyun xwl_eglstream_unref_pixmap_stream(pending->xwl_pixmap);
417*4882a593Smuzhiyun goto out;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun xwl_glamor_egl_make_current(xwl_screen);
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun xwl_pixmap = pending->xwl_pixmap;
423*4882a593Smuzhiyun xwl_pixmap->surface = eglCreateStreamProducerSurfaceKHR(
424*4882a593Smuzhiyun xwl_screen->egl_display, xwl_eglstream->config,
425*4882a593Smuzhiyun xwl_pixmap->stream, (int[]) {
426*4882a593Smuzhiyun EGL_WIDTH, pending->pixmap->drawable.width,
427*4882a593Smuzhiyun EGL_HEIGHT, pending->pixmap->drawable.height,
428*4882a593Smuzhiyun EGL_NONE
429*4882a593Smuzhiyun });
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun DebugF("eglstream: win %d completes eglstream for pixmap %p, congrats!\n",
432*4882a593Smuzhiyun pending->window->drawable.id, pending->pixmap);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun out:
435*4882a593Smuzhiyun xwl_eglstream_window_set_pending(pending->window, NULL);
436*4882a593Smuzhiyun xorg_list_del(&pending->link);
437*4882a593Smuzhiyun free(pending);
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun
440*4882a593Smuzhiyun static const struct wl_callback_listener consumer_ready_listener = {
441*4882a593Smuzhiyun xwl_eglstream_consumer_ready_callback
442*4882a593Smuzhiyun };
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun static void
xwl_eglstream_queue_pending_stream(struct xwl_screen * xwl_screen,WindowPtr window,PixmapPtr pixmap)445*4882a593Smuzhiyun xwl_eglstream_queue_pending_stream(struct xwl_screen *xwl_screen,
446*4882a593Smuzhiyun WindowPtr window, PixmapPtr pixmap)
447*4882a593Smuzhiyun {
448*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream =
449*4882a593Smuzhiyun xwl_eglstream_get(xwl_screen);
450*4882a593Smuzhiyun struct xwl_eglstream_pending_stream *pending_stream;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun #ifdef DEBUG
453*4882a593Smuzhiyun if (!xwl_eglstream_window_get_pending(window))
454*4882a593Smuzhiyun DebugF("eglstream: win %d begins new eglstream for pixmap %p\n",
455*4882a593Smuzhiyun window->drawable.id, pixmap);
456*4882a593Smuzhiyun else
457*4882a593Smuzhiyun DebugF("eglstream: win %d interrupts and replaces pending eglstream for pixmap %p\n",
458*4882a593Smuzhiyun window->drawable.id, pixmap);
459*4882a593Smuzhiyun #endif
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun pending_stream = malloc(sizeof(*pending_stream));
462*4882a593Smuzhiyun pending_stream->window = window;
463*4882a593Smuzhiyun pending_stream->pixmap = pixmap;
464*4882a593Smuzhiyun pending_stream->xwl_pixmap = xwl_pixmap_get(pixmap);
465*4882a593Smuzhiyun pending_stream->is_valid = TRUE;
466*4882a593Smuzhiyun xorg_list_init(&pending_stream->link);
467*4882a593Smuzhiyun xorg_list_add(&pending_stream->link, &xwl_eglstream->pending_streams);
468*4882a593Smuzhiyun xwl_eglstream_window_set_pending(window, pending_stream);
469*4882a593Smuzhiyun
470*4882a593Smuzhiyun pending_stream->cb = wl_display_sync(xwl_screen->display);
471*4882a593Smuzhiyun wl_callback_add_listener(pending_stream->cb, &consumer_ready_listener,
472*4882a593Smuzhiyun xwl_screen);
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun
475*4882a593Smuzhiyun static void
xwl_eglstream_buffer_release_callback(void * data,struct wl_buffer * wl_buffer)476*4882a593Smuzhiyun xwl_eglstream_buffer_release_callback(void *data, struct wl_buffer *wl_buffer)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun xwl_eglstream_unref_pixmap_stream(data);
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun static const struct wl_buffer_listener xwl_eglstream_buffer_release_listener = {
482*4882a593Smuzhiyun xwl_eglstream_buffer_release_callback
483*4882a593Smuzhiyun };
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun static void
xwl_eglstream_create_pending_stream(struct xwl_screen * xwl_screen,WindowPtr window,PixmapPtr pixmap)486*4882a593Smuzhiyun xwl_eglstream_create_pending_stream(struct xwl_screen *xwl_screen,
487*4882a593Smuzhiyun WindowPtr window, PixmapPtr pixmap)
488*4882a593Smuzhiyun {
489*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream =
490*4882a593Smuzhiyun xwl_eglstream_get(xwl_screen);
491*4882a593Smuzhiyun struct xwl_pixmap *xwl_pixmap;
492*4882a593Smuzhiyun struct xwl_window *xwl_window = xwl_window_from_window(window);
493*4882a593Smuzhiyun struct wl_array stream_attribs;
494*4882a593Smuzhiyun int stream_fd = -1;
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun xwl_pixmap = calloc(sizeof(*xwl_pixmap), 1);
497*4882a593Smuzhiyun if (!xwl_pixmap)
498*4882a593Smuzhiyun FatalError("Not enough memory to create pixmap\n");
499*4882a593Smuzhiyun xwl_pixmap_set_private(pixmap, xwl_pixmap);
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun xwl_glamor_egl_make_current(xwl_screen);
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun xwl_pixmap->xwl_screen = xwl_screen;
504*4882a593Smuzhiyun xwl_pixmap->refcount = 1;
505*4882a593Smuzhiyun xwl_pixmap->stream = eglCreateStreamKHR(xwl_screen->egl_display, NULL);
506*4882a593Smuzhiyun stream_fd = eglGetStreamFileDescriptorKHR(xwl_screen->egl_display,
507*4882a593Smuzhiyun xwl_pixmap->stream);
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun wl_array_init(&stream_attribs);
510*4882a593Smuzhiyun xwl_pixmap->buffer =
511*4882a593Smuzhiyun wl_eglstream_display_create_stream(xwl_eglstream->display,
512*4882a593Smuzhiyun pixmap->drawable.width,
513*4882a593Smuzhiyun pixmap->drawable.height,
514*4882a593Smuzhiyun stream_fd,
515*4882a593Smuzhiyun WL_EGLSTREAM_HANDLE_TYPE_FD,
516*4882a593Smuzhiyun &stream_attribs);
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun wl_buffer_add_listener(xwl_pixmap->buffer,
519*4882a593Smuzhiyun &xwl_eglstream_buffer_release_listener,
520*4882a593Smuzhiyun xwl_pixmap);
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun wl_eglstream_controller_attach_eglstream_consumer(
523*4882a593Smuzhiyun xwl_eglstream->controller, xwl_window->surface, xwl_pixmap->buffer);
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun xwl_eglstream_queue_pending_stream(xwl_screen, window, pixmap);
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun close(stream_fd);
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun static Bool
xwl_glamor_eglstream_allow_commits(struct xwl_window * xwl_window)531*4882a593Smuzhiyun xwl_glamor_eglstream_allow_commits(struct xwl_window *xwl_window)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
534*4882a593Smuzhiyun struct xwl_eglstream_pending_stream *pending =
535*4882a593Smuzhiyun xwl_eglstream_window_get_pending(xwl_window->window);
536*4882a593Smuzhiyun PixmapPtr pixmap =
537*4882a593Smuzhiyun (*xwl_screen->screen->GetWindowPixmap)(xwl_window->window);
538*4882a593Smuzhiyun struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun if (xwl_pixmap) {
541*4882a593Smuzhiyun if (pending) {
542*4882a593Smuzhiyun /* Wait for the compositor to finish connecting the consumer for
543*4882a593Smuzhiyun * this eglstream */
544*4882a593Smuzhiyun if (pending->is_valid)
545*4882a593Smuzhiyun return FALSE;
546*4882a593Smuzhiyun
547*4882a593Smuzhiyun /* The pixmap for this window was changed before the compositor
548*4882a593Smuzhiyun * finished connecting the eglstream for the window's previous
549*4882a593Smuzhiyun * pixmap. Begin creating a new eglstream. */
550*4882a593Smuzhiyun } else {
551*4882a593Smuzhiyun return TRUE;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
555*4882a593Smuzhiyun /* Glamor pixmap has no backing stream yet; begin making one and disallow
556*4882a593Smuzhiyun * commits until then
557*4882a593Smuzhiyun */
558*4882a593Smuzhiyun xwl_eglstream_create_pending_stream(xwl_screen, xwl_window->window,
559*4882a593Smuzhiyun pixmap);
560*4882a593Smuzhiyun
561*4882a593Smuzhiyun return FALSE;
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun
564*4882a593Smuzhiyun static void
xwl_glamor_eglstream_post_damage(struct xwl_window * xwl_window,PixmapPtr pixmap,RegionPtr region)565*4882a593Smuzhiyun xwl_glamor_eglstream_post_damage(struct xwl_window *xwl_window,
566*4882a593Smuzhiyun PixmapPtr pixmap, RegionPtr region)
567*4882a593Smuzhiyun {
568*4882a593Smuzhiyun struct xwl_screen *xwl_screen = xwl_window->xwl_screen;
569*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream =
570*4882a593Smuzhiyun xwl_eglstream_get(xwl_screen);
571*4882a593Smuzhiyun struct xwl_pixmap *xwl_pixmap = xwl_pixmap_get(pixmap);
572*4882a593Smuzhiyun BoxPtr box = RegionExtents(region);
573*4882a593Smuzhiyun EGLint egl_damage[] = {
574*4882a593Smuzhiyun box->x1, box->y1,
575*4882a593Smuzhiyun box->x2 - box->x1, box->y2 - box->y1
576*4882a593Smuzhiyun };
577*4882a593Smuzhiyun GLint saved_vao;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun /* Unbind the framebuffer BEFORE binding the EGLSurface, otherwise we
580*4882a593Smuzhiyun * won't actually draw to it
581*4882a593Smuzhiyun */
582*4882a593Smuzhiyun xwl_glamor_egl_make_current(xwl_screen);
583*4882a593Smuzhiyun glBindFramebuffer(GL_FRAMEBUFFER, 0);
584*4882a593Smuzhiyun
585*4882a593Smuzhiyun if (eglGetCurrentSurface(EGL_READ) != xwl_pixmap->surface ||
586*4882a593Smuzhiyun eglGetCurrentSurface(EGL_DRAW) != xwl_pixmap->surface)
587*4882a593Smuzhiyun eglMakeCurrent(xwl_screen->egl_display,
588*4882a593Smuzhiyun xwl_pixmap->surface, xwl_pixmap->surface,
589*4882a593Smuzhiyun xwl_screen->egl_context);
590*4882a593Smuzhiyun
591*4882a593Smuzhiyun /* Save current GL state */
592*4882a593Smuzhiyun glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &saved_vao);
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun /* Setup our GL state */
595*4882a593Smuzhiyun glUseProgram(xwl_eglstream->blit_prog);
596*4882a593Smuzhiyun glViewport(0, 0, pixmap->drawable.width, pixmap->drawable.height);
597*4882a593Smuzhiyun glActiveTexture(GL_TEXTURE0);
598*4882a593Smuzhiyun glBindVertexArray(xwl_eglstream->blit_vao);
599*4882a593Smuzhiyun glBindTexture(GL_TEXTURE_2D, glamor_get_pixmap_texture(pixmap));
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun glUniform1i(xwl_eglstream->blit_is_rgba_pos,
602*4882a593Smuzhiyun pixmap->drawable.depth >= 32);
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun /* Blit rendered image into EGLStream surface */
605*4882a593Smuzhiyun glDrawBuffer(GL_BACK);
606*4882a593Smuzhiyun glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun if (xwl_eglstream->have_egl_damage)
609*4882a593Smuzhiyun eglSwapBuffersWithDamageKHR(xwl_screen->egl_display,
610*4882a593Smuzhiyun xwl_pixmap->surface, egl_damage, 1);
611*4882a593Smuzhiyun else
612*4882a593Smuzhiyun eglSwapBuffers(xwl_screen->egl_display, xwl_pixmap->surface);
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun /* Restore previous state */
615*4882a593Smuzhiyun glBindVertexArray(saved_vao);
616*4882a593Smuzhiyun glBindTexture(GL_TEXTURE_2D, 0);
617*4882a593Smuzhiyun
618*4882a593Smuzhiyun /* After this we will hand off the eglstream's wl_buffer to the
619*4882a593Smuzhiyun * compositor, which will own it until it sends a release() event. */
620*4882a593Smuzhiyun xwl_pixmap->refcount++;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun static void
xwl_eglstream_display_handle_caps(void * data,struct wl_eglstream_display * disp,int32_t caps)624*4882a593Smuzhiyun xwl_eglstream_display_handle_caps(void *data,
625*4882a593Smuzhiyun struct wl_eglstream_display *disp,
626*4882a593Smuzhiyun int32_t caps)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun xwl_eglstream_get(data)->display_caps = caps;
629*4882a593Smuzhiyun }
630*4882a593Smuzhiyun
631*4882a593Smuzhiyun static void
xwl_eglstream_display_handle_swapinterval_override(void * data,struct wl_eglstream_display * disp,int32_t swapinterval,struct wl_buffer * stream)632*4882a593Smuzhiyun xwl_eglstream_display_handle_swapinterval_override(void *data,
633*4882a593Smuzhiyun struct wl_eglstream_display *disp,
634*4882a593Smuzhiyun int32_t swapinterval,
635*4882a593Smuzhiyun struct wl_buffer *stream)
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun
639*4882a593Smuzhiyun const struct wl_eglstream_display_listener eglstream_display_listener = {
640*4882a593Smuzhiyun .caps = xwl_eglstream_display_handle_caps,
641*4882a593Smuzhiyun .swapinterval_override = xwl_eglstream_display_handle_swapinterval_override,
642*4882a593Smuzhiyun };
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun static Bool
xwl_glamor_eglstream_init_wl_registry(struct xwl_screen * xwl_screen,struct wl_registry * wl_registry,uint32_t id,const char * name,uint32_t version)645*4882a593Smuzhiyun xwl_glamor_eglstream_init_wl_registry(struct xwl_screen *xwl_screen,
646*4882a593Smuzhiyun struct wl_registry *wl_registry,
647*4882a593Smuzhiyun uint32_t id, const char *name,
648*4882a593Smuzhiyun uint32_t version)
649*4882a593Smuzhiyun {
650*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream =
651*4882a593Smuzhiyun xwl_eglstream_get(xwl_screen);
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun if (strcmp(name, "wl_eglstream_display") == 0) {
654*4882a593Smuzhiyun xwl_eglstream->display = wl_registry_bind(
655*4882a593Smuzhiyun wl_registry, id, &wl_eglstream_display_interface, version);
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun wl_eglstream_display_add_listener(xwl_eglstream->display,
658*4882a593Smuzhiyun &eglstream_display_listener,
659*4882a593Smuzhiyun xwl_screen);
660*4882a593Smuzhiyun return TRUE;
661*4882a593Smuzhiyun } else if (strcmp(name, "wl_eglstream_controller") == 0) {
662*4882a593Smuzhiyun xwl_eglstream->controller = wl_registry_bind(
663*4882a593Smuzhiyun wl_registry, id, &wl_eglstream_controller_interface, version);
664*4882a593Smuzhiyun return TRUE;
665*4882a593Smuzhiyun }
666*4882a593Smuzhiyun
667*4882a593Smuzhiyun /* no match */
668*4882a593Smuzhiyun return FALSE;
669*4882a593Smuzhiyun }
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun static Bool
xwl_glamor_eglstream_has_wl_interfaces(struct xwl_screen * xwl_screen)672*4882a593Smuzhiyun xwl_glamor_eglstream_has_wl_interfaces(struct xwl_screen *xwl_screen)
673*4882a593Smuzhiyun {
674*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream =
675*4882a593Smuzhiyun xwl_eglstream_get(xwl_screen);
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun if (xwl_eglstream->display == NULL) {
678*4882a593Smuzhiyun ErrorF("glamor: 'wl_eglstream_display' not supported\n");
679*4882a593Smuzhiyun return FALSE;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun if (xwl_eglstream->controller == NULL) {
683*4882a593Smuzhiyun ErrorF("glamor: 'wl_eglstream_controller' not supported\n");
684*4882a593Smuzhiyun return FALSE;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun return TRUE;
688*4882a593Smuzhiyun }
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun static inline void
xwl_eglstream_init_shaders(struct xwl_screen * xwl_screen)691*4882a593Smuzhiyun xwl_eglstream_init_shaders(struct xwl_screen *xwl_screen)
692*4882a593Smuzhiyun {
693*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream =
694*4882a593Smuzhiyun xwl_eglstream_get(xwl_screen);
695*4882a593Smuzhiyun GLint fs, vs, attrib;
696*4882a593Smuzhiyun GLuint vbo;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun const char *blit_vs_src =
699*4882a593Smuzhiyun "attribute vec2 texcoord;\n"
700*4882a593Smuzhiyun "attribute vec2 position;\n"
701*4882a593Smuzhiyun "varying vec2 t;\n"
702*4882a593Smuzhiyun "void main() {\n"
703*4882a593Smuzhiyun " t = texcoord;\n"
704*4882a593Smuzhiyun " gl_Position = vec4(position, 0, 1);\n"
705*4882a593Smuzhiyun "}";
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun const char *blit_fs_src =
708*4882a593Smuzhiyun "varying vec2 t;\n"
709*4882a593Smuzhiyun "uniform sampler2D s;\n"
710*4882a593Smuzhiyun "uniform bool is_rgba;\n"
711*4882a593Smuzhiyun "void main() {\n"
712*4882a593Smuzhiyun " if (is_rgba)\n"
713*4882a593Smuzhiyun " gl_FragColor = texture2D(s, t);\n"
714*4882a593Smuzhiyun " else\n"
715*4882a593Smuzhiyun " gl_FragColor = vec4(texture2D(s, t).rgb, 1.0);\n"
716*4882a593Smuzhiyun "}";
717*4882a593Smuzhiyun
718*4882a593Smuzhiyun static const float position[] = {
719*4882a593Smuzhiyun /* position */
720*4882a593Smuzhiyun -1, -1,
721*4882a593Smuzhiyun 1, -1,
722*4882a593Smuzhiyun 1, 1,
723*4882a593Smuzhiyun -1, 1,
724*4882a593Smuzhiyun /* texcoord */
725*4882a593Smuzhiyun 0, 1,
726*4882a593Smuzhiyun 1, 1,
727*4882a593Smuzhiyun 1, 0,
728*4882a593Smuzhiyun 0, 0,
729*4882a593Smuzhiyun };
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun vs = xwl_eglstream_compile_glsl_prog(GL_VERTEX_SHADER, blit_vs_src);
732*4882a593Smuzhiyun fs = xwl_eglstream_compile_glsl_prog(GL_FRAGMENT_SHADER, blit_fs_src);
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun xwl_eglstream->blit_prog = xwl_eglstream_build_glsl_prog(vs, fs);
735*4882a593Smuzhiyun glDeleteShader(vs);
736*4882a593Smuzhiyun glDeleteShader(fs);
737*4882a593Smuzhiyun
738*4882a593Smuzhiyun /* Create the blitter's vao */
739*4882a593Smuzhiyun glGenVertexArrays(1, &xwl_eglstream->blit_vao);
740*4882a593Smuzhiyun glBindVertexArray(xwl_eglstream->blit_vao);
741*4882a593Smuzhiyun
742*4882a593Smuzhiyun /* Set the data for both position and texcoord in the vbo */
743*4882a593Smuzhiyun glGenBuffers(1, &vbo);
744*4882a593Smuzhiyun glBindBuffer(GL_ARRAY_BUFFER, vbo);
745*4882a593Smuzhiyun glBufferData(GL_ARRAY_BUFFER, sizeof(position), position, GL_STATIC_DRAW);
746*4882a593Smuzhiyun xwl_eglstream->blit_vbo = vbo;
747*4882a593Smuzhiyun
748*4882a593Smuzhiyun /* Define each shader attribute's data location in our vbo */
749*4882a593Smuzhiyun attrib = glGetAttribLocation(xwl_eglstream->blit_prog, "position");
750*4882a593Smuzhiyun glVertexAttribPointer(attrib, 2, GL_FLOAT, TRUE, 0, NULL);
751*4882a593Smuzhiyun glEnableVertexAttribArray(attrib);
752*4882a593Smuzhiyun
753*4882a593Smuzhiyun attrib = glGetAttribLocation(xwl_eglstream->blit_prog, "texcoord");
754*4882a593Smuzhiyun glVertexAttribPointer(attrib, 2, GL_FLOAT, TRUE, 0,
755*4882a593Smuzhiyun (void*)(sizeof(float) * 8));
756*4882a593Smuzhiyun glEnableVertexAttribArray(attrib);
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun /* Save the location of uniforms we'll set later */
759*4882a593Smuzhiyun xwl_eglstream->blit_is_rgba_pos =
760*4882a593Smuzhiyun glGetUniformLocation(xwl_eglstream->blit_prog, "is_rgba");
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun
763*4882a593Smuzhiyun static Bool
xwl_glamor_eglstream_init_egl(struct xwl_screen * xwl_screen)764*4882a593Smuzhiyun xwl_glamor_eglstream_init_egl(struct xwl_screen *xwl_screen)
765*4882a593Smuzhiyun {
766*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream =
767*4882a593Smuzhiyun xwl_eglstream_get(xwl_screen);
768*4882a593Smuzhiyun EGLConfig config;
769*4882a593Smuzhiyun const EGLint attrib_list[] = {
770*4882a593Smuzhiyun EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR,
771*4882a593Smuzhiyun EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
772*4882a593Smuzhiyun EGL_CONTEXT_MAJOR_VERSION_KHR,
773*4882a593Smuzhiyun GLAMOR_GL_CORE_VER_MAJOR,
774*4882a593Smuzhiyun EGL_CONTEXT_MINOR_VERSION_KHR,
775*4882a593Smuzhiyun GLAMOR_GL_CORE_VER_MINOR,
776*4882a593Smuzhiyun EGL_CONTEXT_PRIORITY_LEVEL_IMG, EGL_CONTEXT_PRIORITY_HIGH_IMG,
777*4882a593Smuzhiyun EGL_NONE
778*4882a593Smuzhiyun };
779*4882a593Smuzhiyun const EGLint config_attribs[] = {
780*4882a593Smuzhiyun EGL_SURFACE_TYPE, EGL_STREAM_BIT_KHR,
781*4882a593Smuzhiyun EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
782*4882a593Smuzhiyun EGL_RED_SIZE, 8,
783*4882a593Smuzhiyun EGL_GREEN_SIZE, 8,
784*4882a593Smuzhiyun EGL_BLUE_SIZE, 8,
785*4882a593Smuzhiyun EGL_ALPHA_SIZE, 8,
786*4882a593Smuzhiyun EGL_NONE,
787*4882a593Smuzhiyun };
788*4882a593Smuzhiyun int n;
789*4882a593Smuzhiyun
790*4882a593Smuzhiyun xwl_screen->egl_display = glamor_egl_get_display(
791*4882a593Smuzhiyun EGL_PLATFORM_DEVICE_EXT, xwl_eglstream->egl_device);
792*4882a593Smuzhiyun if (!xwl_screen->egl_display)
793*4882a593Smuzhiyun goto error;
794*4882a593Smuzhiyun
795*4882a593Smuzhiyun if (!eglInitialize(xwl_screen->egl_display, NULL, NULL)) {
796*4882a593Smuzhiyun xwl_screen->egl_display = NULL;
797*4882a593Smuzhiyun goto error;
798*4882a593Smuzhiyun }
799*4882a593Smuzhiyun
800*4882a593Smuzhiyun if (!epoxy_has_egl_extension(xwl_screen->egl_display,
801*4882a593Smuzhiyun "EGL_IMG_context_priority")) {
802*4882a593Smuzhiyun ErrorF("EGL_IMG_context_priority not available\n");
803*4882a593Smuzhiyun goto error;
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun eglChooseConfig(xwl_screen->egl_display, config_attribs, &config, 1, &n);
807*4882a593Smuzhiyun if (!n) {
808*4882a593Smuzhiyun ErrorF("No acceptable EGL configs found\n");
809*4882a593Smuzhiyun goto error;
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun xwl_eglstream->config = config;
813*4882a593Smuzhiyun #if 0
814*4882a593Smuzhiyun xwl_screen->formats =
815*4882a593Smuzhiyun XWL_FORMAT_RGB565 | XWL_FORMAT_XRGB8888 | XWL_FORMAT_ARGB8888;
816*4882a593Smuzhiyun #endif
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun eglBindAPI(EGL_OPENGL_API);
819*4882a593Smuzhiyun xwl_screen->egl_context = eglCreateContext(
820*4882a593Smuzhiyun xwl_screen->egl_display, config, EGL_NO_CONTEXT, attrib_list);
821*4882a593Smuzhiyun if (xwl_screen->egl_context == EGL_NO_CONTEXT) {
822*4882a593Smuzhiyun ErrorF("Failed to create main EGL context: 0x%x\n", eglGetError());
823*4882a593Smuzhiyun goto error;
824*4882a593Smuzhiyun }
825*4882a593Smuzhiyun
826*4882a593Smuzhiyun if (!eglMakeCurrent(xwl_screen->egl_display,
827*4882a593Smuzhiyun EGL_NO_SURFACE, EGL_NO_SURFACE,
828*4882a593Smuzhiyun xwl_screen->egl_context)) {
829*4882a593Smuzhiyun ErrorF("Failed to make EGL context current\n");
830*4882a593Smuzhiyun goto error;
831*4882a593Smuzhiyun }
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun xwl_eglstream->have_egl_damage =
834*4882a593Smuzhiyun epoxy_has_egl_extension(xwl_screen->egl_display,
835*4882a593Smuzhiyun "EGL_KHR_swap_buffers_with_damage");
836*4882a593Smuzhiyun if (!xwl_eglstream->have_egl_damage)
837*4882a593Smuzhiyun ErrorF("Driver lacks EGL_KHR_swap_buffers_with_damage, performance "
838*4882a593Smuzhiyun "will be affected\n");
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun xwl_eglstream_init_shaders(xwl_screen);
841*4882a593Smuzhiyun
842*4882a593Smuzhiyun return TRUE;
843*4882a593Smuzhiyun error:
844*4882a593Smuzhiyun xwl_eglstream_cleanup(xwl_screen);
845*4882a593Smuzhiyun return FALSE;
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun static Bool
xwl_glamor_eglstream_init_screen(struct xwl_screen * xwl_screen)849*4882a593Smuzhiyun xwl_glamor_eglstream_init_screen(struct xwl_screen *xwl_screen)
850*4882a593Smuzhiyun {
851*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream =
852*4882a593Smuzhiyun xwl_eglstream_get(xwl_screen);
853*4882a593Smuzhiyun ScreenPtr screen = xwl_screen->screen;
854*4882a593Smuzhiyun
855*4882a593Smuzhiyun /* We can just let glamor handle CreatePixmap */
856*4882a593Smuzhiyun screen->DestroyPixmap = xwl_glamor_eglstream_destroy_pixmap;
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun xwl_eglstream->SetWindowPixmap = screen->SetWindowPixmap;
859*4882a593Smuzhiyun screen->SetWindowPixmap = xwl_eglstream_set_window_pixmap;
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun if (!dixRegisterPrivateKey(&xwl_eglstream_window_private_key,
862*4882a593Smuzhiyun PRIVATE_WINDOW, 0))
863*4882a593Smuzhiyun return FALSE;
864*4882a593Smuzhiyun
865*4882a593Smuzhiyun return TRUE;
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun static EGLDeviceEXT
xwl_eglstream_get_device(struct xwl_screen * xwl_screen)869*4882a593Smuzhiyun xwl_eglstream_get_device(struct xwl_screen *xwl_screen)
870*4882a593Smuzhiyun {
871*4882a593Smuzhiyun void **devices = NULL;
872*4882a593Smuzhiyun const char *exts[] = {
873*4882a593Smuzhiyun "EGL_KHR_stream",
874*4882a593Smuzhiyun "EGL_KHR_stream_producer_eglsurface",
875*4882a593Smuzhiyun };
876*4882a593Smuzhiyun int num_devices, i;
877*4882a593Smuzhiyun EGLDeviceEXT device = EGL_NO_DEVICE_EXT;
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun /* No device specified by the user, so find one ourselves */
880*4882a593Smuzhiyun devices = xwl_glamor_egl_get_devices(&num_devices);
881*4882a593Smuzhiyun if (!devices)
882*4882a593Smuzhiyun goto out;
883*4882a593Smuzhiyun
884*4882a593Smuzhiyun for (i = 0; i < num_devices; i++) {
885*4882a593Smuzhiyun if (xwl_glamor_egl_device_has_egl_extensions(devices[i], exts,
886*4882a593Smuzhiyun ARRAY_SIZE(exts))) {
887*4882a593Smuzhiyun device = devices[i];
888*4882a593Smuzhiyun break;
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun free(devices);
893*4882a593Smuzhiyun out:
894*4882a593Smuzhiyun if (!device)
895*4882a593Smuzhiyun ErrorF("glamor: No eglstream capable devices found\n");
896*4882a593Smuzhiyun return device;
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun void
xwl_glamor_init_eglstream(struct xwl_screen * xwl_screen)900*4882a593Smuzhiyun xwl_glamor_init_eglstream(struct xwl_screen *xwl_screen)
901*4882a593Smuzhiyun {
902*4882a593Smuzhiyun struct xwl_eglstream_private *xwl_eglstream;
903*4882a593Smuzhiyun EGLDeviceEXT egl_device;
904*4882a593Smuzhiyun
905*4882a593Smuzhiyun xwl_screen->eglstream_backend.is_available = FALSE;
906*4882a593Smuzhiyun egl_device = xwl_eglstream_get_device(xwl_screen);
907*4882a593Smuzhiyun if (egl_device == EGL_NO_DEVICE_EXT)
908*4882a593Smuzhiyun return;
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun if (!dixRegisterPrivateKey(&xwl_eglstream_private_key, PRIVATE_SCREEN, 0))
911*4882a593Smuzhiyun return;
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun xwl_eglstream = calloc(sizeof(*xwl_eglstream), 1);
914*4882a593Smuzhiyun if (!xwl_eglstream) {
915*4882a593Smuzhiyun ErrorF("Failed to allocate memory required to init EGLStream support\n");
916*4882a593Smuzhiyun return;
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun
919*4882a593Smuzhiyun dixSetPrivate(&xwl_screen->screen->devPrivates,
920*4882a593Smuzhiyun &xwl_eglstream_private_key, xwl_eglstream);
921*4882a593Smuzhiyun
922*4882a593Smuzhiyun xwl_eglstream->egl_device = egl_device;
923*4882a593Smuzhiyun xorg_list_init(&xwl_eglstream->pending_streams);
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun xwl_screen->eglstream_backend.init_egl = xwl_glamor_eglstream_init_egl;
926*4882a593Smuzhiyun xwl_screen->eglstream_backend.init_wl_registry = xwl_glamor_eglstream_init_wl_registry;
927*4882a593Smuzhiyun xwl_screen->eglstream_backend.has_wl_interfaces = xwl_glamor_eglstream_has_wl_interfaces;
928*4882a593Smuzhiyun xwl_screen->eglstream_backend.init_screen = xwl_glamor_eglstream_init_screen;
929*4882a593Smuzhiyun xwl_screen->eglstream_backend.get_wl_buffer_for_pixmap = xwl_glamor_eglstream_get_wl_buffer_for_pixmap;
930*4882a593Smuzhiyun xwl_screen->eglstream_backend.post_damage = xwl_glamor_eglstream_post_damage;
931*4882a593Smuzhiyun xwl_screen->eglstream_backend.allow_commits = xwl_glamor_eglstream_allow_commits;
932*4882a593Smuzhiyun xwl_screen->eglstream_backend.is_available = TRUE;
933*4882a593Smuzhiyun }
934