summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gl-renderer.c257
-rw-r--r--src/gl-renderer.h19
-rw-r--r--src/weston-egl-ext.h34
3 files changed, 307 insertions, 3 deletions
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 098440ce..9380371a 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -84,6 +84,8 @@ struct gl_output_state {
struct gl_border_image borders[4];
enum gl_border_status border_status;
+ EGLStreamKHR egl_stream;
+
struct weston_matrix output_matrix;
};
@@ -202,6 +204,28 @@ struct gl_renderer {
int has_configless_context;
+ PFNEGLGETOUTPUTLAYERSEXTPROC get_output_layers;
+ PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC query_output_layer_attrib;
+ int has_egl_output_base;
+ int has_egl_output_drm;
+ int has_egl_output_drm_flip_event;
+
+ PFNEGLCREATESTREAMKHRPROC create_stream;
+ PFNEGLDESTROYSTREAMKHRPROC destroy_stream;
+ int has_egl_stream;
+
+ PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC create_stream_producer_surface;
+ int has_egl_stream_producer_eglsurface;
+
+ PFNEGLSTREAMCONSUMEROUTPUTEXTPROC stream_consumer_output;
+ int has_egl_stream_consumer_egloutput;
+
+#ifdef EGL_NV_stream_attrib
+ PFNEGLSTREAMCONSUMERACQUIREATTRIBNVPROC stream_consumer_acquire_attrib;
+#endif
+ int has_egl_stream_attrib;
+ int has_egl_stream_acquire_mode;
+
int has_dmabuf_import;
struct wl_list dmabuf_images;
@@ -1193,6 +1217,37 @@ gl_renderer_repaint_output(struct weston_output *output,
}
static int
+gl_renderer_output_stream_flip(struct weston_output *output,
+ void *flip_data)
+{
+#if defined(EGL_NV_stream_attrib) && defined(EGL_EXT_stream_acquire_mode)
+ struct gl_output_state *go = get_output_state(output);
+ struct weston_compositor *compositor = output->compositor;
+ struct gl_renderer *gr = get_renderer(compositor);
+
+ EGLAttrib acquire_attribs[3] = { EGL_NONE };
+
+#ifdef EGL_NV_output_drm_flip_event
+ if (gr->has_egl_output_drm_flip_event) {
+ acquire_attribs[0] = EGL_DRM_FLIP_EVENT_DATA_NV;
+ acquire_attribs[1] = (EGLAttrib)flip_data;
+ acquire_attribs[2] = EGL_NONE;
+ }
+#endif
+
+ if (go->egl_stream != EGL_NO_STREAM_KHR)
+ if (EGL_TRUE != gr->stream_consumer_acquire_attrib(gr->egl_display,
+ go->egl_stream,
+ acquire_attribs))
+ return -1;
+
+ return 0;
+#else
+ return -1;
+#endif
+}
+
+static int
gl_renderer_read_pixels(struct weston_output *output,
pixman_format_code_t format, void *pixels,
uint32_t x, uint32_t y,
@@ -2587,9 +2642,92 @@ gl_renderer_create_window_surface(struct gl_renderer *gr,
return egl_surface;
}
+static EGLSurface
+gl_renderer_create_stream_surface(struct gl_renderer *gr,
+ uint32_t plane_id,
+ uint32_t crtc_id,
+ EGLint width, EGLint height,
+ EGLStreamKHR *egl_stream)
+{
+ EGLint stream_attribs[] = {
+ EGL_STREAM_FIFO_LENGTH_KHR, 1,
+#ifdef EGL_EXT_stream_acquire_mode
+ EGL_CONSUMER_AUTO_ACQUIRE_EXT, EGL_FALSE,
+#endif
+ EGL_NONE
+ };
+ EGLAttrib output_attribs[3];
+ EGLint stream_producer_attribs[] = {
+ EGL_WIDTH, width,
+ EGL_HEIGHT, height,
+ EGL_NONE
+ };
+
+ EGLint num_layers;
+ EGLOutputLayerEXT output_layer;
+ EGLSurface egl_surface = EGL_NO_SURFACE;
+
+ *egl_stream = gr->create_stream(gr->egl_display, stream_attribs);
+
+ if (*egl_stream == EGL_NO_STREAM_KHR) {
+ weston_log("Failed to create EGL stream.\n");
+ goto err_egl_create_surf_base;
+ }
+
+ if (plane_id != ~0u) {
+ output_attribs[0] = EGL_DRM_PLANE_EXT;
+ output_attribs[1] = plane_id;
+ } else {
+ assert(crtc_id != ~0u);
+ output_attribs[0] = EGL_DRM_CRTC_EXT;
+ output_attribs[1] = crtc_id;
+ }
+ output_attribs[2] = EGL_NONE;
+
+ if (gr->get_output_layers(gr->egl_display,
+ output_attribs,
+ &output_layer,
+ 1, &num_layers) != EGL_TRUE) {
+ weston_log("Failed to get output layer.\n");
+ goto err_egl_create_surf_stream;
+ }
+
+ if (num_layers < 1) {
+ weston_log("Unable to find output layers.\n");
+ goto err_egl_create_surf_stream;
+ }
+
+ if (gr->stream_consumer_output(gr->egl_display, *egl_stream,
+ output_layer) != EGL_TRUE) {
+ weston_log("Failed to set EGL stream consumer.\n");
+ goto err_egl_create_surf_stream;
+ }
+
+ egl_surface = gr->create_stream_producer_surface(gr->egl_display,
+ gr->egl_config,
+ *egl_stream,
+ stream_producer_attribs);
+
+ if (egl_surface == EGL_NO_SURFACE) {
+ weston_log("Failed to create EGL producer surface.\n");
+ goto err_egl_create_surf_stream;
+ }
+
+ return egl_surface;
+
+err_egl_create_surf_stream:
+ gr->destroy_stream(gr->egl_display, *egl_stream);
+ *egl_stream = EGL_NO_STREAM_KHR;
+
+err_egl_create_surf_base:
+ gl_renderer_print_egl_error_state();
+ return EGL_NO_SURFACE;
+}
+
static int
gl_renderer_output_create(struct weston_output *output,
- EGLSurface surface)
+ EGLSurface surface,
+ EGLStreamKHR stream)
{
struct weston_compositor *ec = output->compositor;
struct gl_renderer *gr = get_renderer(ec);
@@ -2606,6 +2744,7 @@ gl_renderer_output_create(struct weston_output *output,
return -1;
go->egl_surface = surface;
+ go->egl_stream = stream;
for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
pixman_region32_init(&go->buffer_damage[i]);
@@ -2638,13 +2777,41 @@ gl_renderer_output_window_create(struct weston_output *output,
return -1;
}
- ret = gl_renderer_output_create(output, egl_surface);
+ ret = gl_renderer_output_create(output, egl_surface, EGL_NO_STREAM_KHR);
if (ret < 0)
eglDestroySurface(gr->egl_display, egl_surface);
return ret;
}
+static int
+gl_renderer_output_stream_create(struct weston_output *output,
+ uint32_t plane_id, uint32_t crtc_id)
+{
+ struct weston_compositor *ec = output->compositor;
+ struct gl_renderer *gr = get_renderer(ec);
+ EGLSurface egl_surface = EGL_NO_SURFACE;
+ EGLStreamKHR egl_stream = EGL_NO_STREAM_KHR;
+ int ret;
+
+ egl_surface =
+ gl_renderer_create_stream_surface(gr,
+ plane_id, crtc_id,
+ output->current_mode->width,
+ output->current_mode->height,
+ &egl_stream);
+ if (egl_surface == EGL_NO_SURFACE)
+ return -1;
+
+ ret = gl_renderer_output_create(output, egl_surface, egl_stream);
+ if (ret < 0) {
+ eglDestroySurface(gr->egl_display, egl_surface);
+ gr->destroy_stream(gr->egl_display, egl_stream);
+ }
+
+ return ret;
+}
+
static void
gl_renderer_output_destroy(struct weston_output *output)
{
@@ -2657,6 +2824,9 @@ gl_renderer_output_destroy(struct weston_output *output)
eglDestroySurface(gr->egl_display, go->egl_surface);
+ if (go->egl_stream != EGL_NO_STREAM_KHR)
+ gr->destroy_stream(gr->egl_display, go->egl_stream);
+
free(go);
}
@@ -2761,6 +2931,19 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
(void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
gr->query_buffer =
(void *) eglGetProcAddress("eglQueryWaylandBufferWL");
+ gr->get_output_layers = (void *) eglGetProcAddress("eglGetOutputLayersEXT");
+ gr->query_output_layer_attrib =
+ (void *) eglGetProcAddress("eglQueryOutputLayerAttribEXT");
+ gr->create_stream = (void *) eglGetProcAddress("eglCreateStreamKHR");
+ gr->destroy_stream = (void *) eglGetProcAddress("eglDestroyStreamKHR");
+ gr->create_stream_producer_surface =
+ (void *) eglGetProcAddress("eglCreateStreamProducerSurfaceKHR");
+ gr->stream_consumer_output =
+ (void *) eglGetProcAddress("eglStreamConsumerOutputEXT");
+#ifdef EGL_NV_stream_attrib
+ gr->stream_consumer_acquire_attrib =
+ (void *) eglGetProcAddress("eglStreamConsumerAcquireAttribNV");
+#endif
extensions =
(const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
@@ -2802,6 +2985,30 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
gr->has_dmabuf_import = 1;
#endif
+ if (check_extension(extensions, "EGL_EXT_output_base"))
+ gr->has_egl_output_base = 1;
+
+ if (check_extension(extensions, "EGL_EXT_output_drm"))
+ gr->has_egl_output_drm = 1;
+
+ if (check_extension(extensions, "EGL_NV_output_drm_flip_event"))
+ gr->has_egl_output_drm_flip_event = 1;
+
+ if (check_extension(extensions, "EGL_KHR_stream"))
+ gr->has_egl_stream = 1;
+
+ if (check_extension(extensions, "EGL_KHR_stream_producer_eglsurface"))
+ gr->has_egl_stream_producer_eglsurface = 1;
+
+ if (check_extension(extensions, "EGL_EXT_stream_consumer_egloutput"))
+ gr->has_egl_stream_consumer_egloutput = 1;
+
+ if (check_extension(extensions, "EGL_NV_stream_attrib"))
+ gr->has_egl_stream_attrib = 1;
+
+ if (check_extension(extensions, "EGL_EXT_stream_acquire_mode"))
+ gr->has_egl_stream_acquire_mode = 1;
+
renderer_setup_egl_client_extensions(gr);
return 0;
@@ -2827,6 +3034,16 @@ static const EGLint gl_renderer_alpha_attribs[] = {
EGL_NONE
};
+static const EGLint gl_renderer_opaque_stream_attribs[] = {
+ EGL_SURFACE_TYPE, EGL_STREAM_BIT_KHR,
+ EGL_RED_SIZE, 1,
+ EGL_GREEN_SIZE, 1,
+ EGL_BLUE_SIZE, 1,
+ EGL_ALPHA_SIZE, 0,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+};
+
/** Checks whether a platform EGL client extension is supported
*
* \param ec The weston compositor
@@ -2899,6 +3116,8 @@ platform_to_extension(EGLenum platform)
return "wayland";
case EGL_PLATFORM_X11_KHR:
return "x11";
+ case EGL_PLATFORM_DEVICE_EXT:
+ return "device";
default:
assert(0 && "bad EGL platform enum");
}
@@ -2984,6 +3203,34 @@ gl_renderer_display_create(struct weston_compositor *ec, EGLenum platform,
if (gl_renderer_setup_egl_extensions(ec) < 0)
goto fail_with_error;
+ if (platform == EGL_PLATFORM_DEVICE_EXT) {
+ if (!gr->has_egl_output_base ||
+ !gr->has_egl_output_drm ||
+ !gr->has_egl_stream ||
+ !gr->has_egl_stream_producer_eglsurface ||
+ !gr->has_egl_stream_consumer_egloutput ||
+ !gr->has_egl_stream_attrib ||
+ !gr->has_egl_stream_acquire_mode) {
+ weston_log("following required extensions not supported:\n"
+ "%s%s%s%s%s%s%s",
+ (gr->has_egl_output_base ? "" : " EGL_EXT_output_base\n"),
+ (gr->has_egl_output_drm ? "" : " EGL_EXT_output_drm\n"),
+ (gr->has_egl_stream ? "" : " EGL_KHR_stream\n"),
+ (gr->has_egl_stream_producer_eglsurface ?
+ "" : " EGL_KHR_stream_producer_eglsurface\n"),
+ (gr->has_egl_stream_consumer_egloutput ?
+ "" : " EGL_EXT_stream_consumer_egloutput\n"),
+ (gr->has_egl_stream_attrib ? "" : " EGL_NV_stream_attrib\n"),
+ (gr->has_egl_stream_acquire_mode ?
+ "" : " EGL_EXT_stream_acquire_mode\n"));
+ goto fail_terminate;
+ }
+
+ if (!gr->has_egl_output_drm_flip_event)
+ weston_log("warning: EGL page flip event notification not"
+ " supported\n");
+ }
+
wl_list_init(&gr->dmabuf_images);
if (gr->has_dmabuf_import)
gr->base.import_dmabuf = gl_renderer_import_dmabuf;
@@ -3260,15 +3507,19 @@ gl_renderer_get_drm_device_file(EGLDeviceEXT device,
WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
.opaque_attribs = gl_renderer_opaque_attribs,
.alpha_attribs = gl_renderer_alpha_attribs,
+ .opaque_stream_attribs = gl_renderer_opaque_stream_attribs,
.display_create = gl_renderer_display_create,
.display = gl_renderer_display,
.output_window_create = gl_renderer_output_window_create,
+ .output_stream_create = gl_renderer_output_stream_create,
.output_destroy = gl_renderer_output_destroy,
.output_surface = gl_renderer_output_surface,
.output_set_border = gl_renderer_output_set_border,
.print_egl_error_state = gl_renderer_print_egl_error_state,
.get_devices = gl_renderer_get_devices,
- .get_drm_device_file = gl_renderer_get_drm_device_file
+ .get_drm_device_file = gl_renderer_get_drm_device_file,
+
+ .output_stream_flip = gl_renderer_output_stream_flip
};
diff --git a/src/gl-renderer.h b/src/gl-renderer.h
index f376edd8..958caa19 100644
--- a/src/gl-renderer.h
+++ b/src/gl-renderer.h
@@ -62,6 +62,10 @@ typedef EGLSurface (*PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy,
#define EGL_PLATFORM_X11_KHR 0x31D5
#endif
+#ifndef EGL_PLATFORM_DEVICE_EXT
+#define EGL_PLATFORM_DEVICE_EXT 0x313F
+#endif
+
#define NO_EGL_PLATFORM 0
enum gl_renderer_border_side {
@@ -74,6 +78,7 @@ enum gl_renderer_border_side {
struct gl_renderer_interface {
const EGLint *opaque_attribs;
const EGLint *alpha_attribs;
+ const EGLint *opaque_stream_attribs;
int (*display_create)(struct weston_compositor *ec,
EGLenum platform,
@@ -92,6 +97,9 @@ struct gl_renderer_interface {
const EGLint *visual_id,
const int n_ids);
+ int (*output_stream_create)(struct weston_output *output,
+ uint32_t plane_id, uint32_t crtc_id);
+
void (*output_destroy)(struct weston_output *output);
EGLSurface (*output_surface)(struct weston_output *output);
@@ -136,5 +144,16 @@ struct gl_renderer_interface {
int (*get_drm_device_file)(EGLDeviceEXT device,
const char **drm_device_file);
+
+ /*
+ * output_stream_flip() makes the EGLOutput consumer attached to the
+ * corresponding <output> stream acquire the new available frame
+ * (repaint_output() has been called previously) and queue a page flip.
+ * Whenever DRM is the underlying API and EGL_NV_output_drm_flip_event is
+ * supported, page flip notification can be requested by passing a non-NULL
+ * <flip_data> pointer. Otherwise, compositors should rely on a different
+ * mechanism in order to re-schedule output repaints.
+ */
+ int (*output_stream_flip)(struct weston_output *output, void *flip_data);
};
diff --git a/src/weston-egl-ext.h b/src/weston-egl-ext.h
index 32f6108f..ab010303 100644
--- a/src/weston-egl-ext.h
+++ b/src/weston-egl-ext.h
@@ -116,5 +116,39 @@ typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (
#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
#endif
+/*
+ * FIXME: Remove both EGL_EXT_stream_acquire_mode and
+ * EGL_NV_output_drm_flip_event definitions below once both extensions
+ * get published by Khronos and incorportated into Khronos' header files
+ */
+#ifndef EGL_NV_stream_attrib
+#define EGL_NV_stream_attrib 1
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamAttribNV(EGLDisplay dpy, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglSetStreamAttribNV(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamAttribNV(EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireAttribNV(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseAttribNV(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#endif
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMATTRIBNVPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSTREAMATTRIBNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMATTRIBNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREATTRIBNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEATTRIBNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#endif /* EGL_NV_stream_attrib */
+
+#ifndef EGL_EXT_stream_acquire_mode
+#define EGL_EXT_stream_acquire_mode 1
+#define EGL_CONSUMER_AUTO_ACQUIRE_EXT 0x332B
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREATTRIBEXTPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireAttribEXT (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_EXT_stream_acquire_mode */
+
+#ifndef EGL_NV_output_drm_flip_event
+#define EGL_NV_output_drm_flip_event 1
+#define EGL_DRM_FLIP_EVENT_DATA_NV 0x333E
+#endif /* EGL_NV_output_drm_flip_event */
#endif