xref: /OK3568_Linux_fs/external/xserver/hw/xwayland/xwayland-glamor-eglstream.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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