parent
35c2c81667
commit
1146fc49bb
|
@ -0,0 +1,156 @@
|
|||
From d178c1add79d48cd639bf5c387067c0e4d5fae09 Mon Sep 17 00:00:00 2001
|
||||
From: "Miguel A. Vico" <mvicomoya@nvidia.com>
|
||||
Date: Mon, 2 May 2016 15:56:37 +0200
|
||||
Subject: [PATCH 1/7] gl-renderer: Add EGLDevice enumeration support
|
||||
X-NVConfidentiality: public
|
||||
|
||||
EGLDevice provides means to enumerate native devices.
|
||||
|
||||
In preparation for follow-on changes to support frame presentation
|
||||
through EGLDevice+EGLOutput, this change adds both
|
||||
gl_renderer_get_devices() and gl_renderer_get_drm_device_file()
|
||||
functions which will help to enumerate EGLDevices and match them to DRM
|
||||
devices.
|
||||
|
||||
Signed-off-by: Miguel A Vico Moya <mvicomoya@nvidia.com>
|
||||
Reviewed-by: Andy Ritger <aritger@nvidia.com>
|
||||
Reviewed-by: Adam Cheney <acheney@nvidia.com>
|
||||
Reviewed-by: James Jones <jajones@nvidia.com>
|
||||
---
|
||||
libweston/gl-renderer.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
libweston/gl-renderer.h | 8 +++++
|
||||
2 files changed, 96 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libweston/gl-renderer.c b/libweston/gl-renderer.c
|
||||
index c6091af0..7a840a35 100644
|
||||
--- libweston/gl-renderer.c
|
||||
+++ libweston/gl-renderer.c
|
||||
@@ -3357,6 +3357,90 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int
|
||||
+gl_renderer_get_devices(EGLint max_devices, EGLDeviceEXT *devices,
|
||||
+ EGLint *num_devices)
|
||||
+{
|
||||
+ const char *extensions;
|
||||
+ PFNEGLQUERYDEVICESEXTPROC query_devices;
|
||||
+
|
||||
+ extensions = (const char *)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
|
||||
+ if (!extensions) {
|
||||
+ weston_log("Retrieving EGL extension string failed.\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (!weston_check_egl_extension(extensions, "EGL_EXT_device_base") &&
|
||||
+ (!weston_check_egl_extension(extensions, "EGL_EXT_device_query") ||
|
||||
+ !weston_check_egl_extension(extensions, "EGL_EXT_device_enumeration"))) {
|
||||
+ weston_log("EGL_EXT_device_base not supported\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ query_devices = (void *) eglGetProcAddress("eglQueryDevicesEXT");
|
||||
+ if (!query_devices) {
|
||||
+ weston_log("Failed to get eglQueryDevicesEXT function\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (query_devices(max_devices, devices, num_devices) != EGL_TRUE) {
|
||||
+ weston_log("Failed to query EGL Devices\n");
|
||||
+ gl_renderer_print_egl_error_state();
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+gl_renderer_get_drm_device_file(EGLDeviceEXT device,
|
||||
+ const char **drm_device_file)
|
||||
+{
|
||||
+ const char *exts;
|
||||
+ PFNEGLQUERYDEVICESTRINGEXTPROC query_device_string;
|
||||
+
|
||||
+ exts = (const char *)eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
|
||||
+ if (!exts) {
|
||||
+ weston_log("Retrieving EGL extension string failed.\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (!weston_check_egl_extension(exts, "EGL_EXT_device_base") &&
|
||||
+ (!weston_check_egl_extension(exts, "EGL_EXT_device_query") ||
|
||||
+ !weston_check_egl_extension(exts, "EGL_EXT_device_enumeration"))) {
|
||||
+ weston_log("EGL_EXT_device_base not supported.\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ query_device_string =
|
||||
+ (void *) eglGetProcAddress("eglQueryDeviceStringEXT");
|
||||
+ if (!query_device_string) {
|
||||
+ weston_log("Failed to get eglQueryDeviceStringEXT function\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ exts = query_device_string(device, EGL_EXTENSIONS);
|
||||
+ if (!exts) {
|
||||
+ weston_log("Retrieving EGL extension string failed.\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ if (!weston_check_egl_extension(exts, "EGL_EXT_device_drm")) {
|
||||
+ weston_log("EGL_EXT_device_drm not supported.\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ (*drm_device_file) = query_device_string(device,
|
||||
+ EGL_DRM_DEVICE_FILE_EXT);
|
||||
+ if (*drm_device_file == NULL) {
|
||||
+ weston_log("Failed to query DRM device name.\n");
|
||||
+ gl_renderer_print_egl_error_state();
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
|
||||
.opaque_attribs = gl_renderer_opaque_attribs,
|
||||
.alpha_attribs = gl_renderer_alpha_attribs,
|
||||
@@ -3367,5 +3451,8 @@ WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
|
||||
.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
|
||||
+ .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
|
||||
};
|
||||
diff --git a/libweston/gl-renderer.h b/libweston/gl-renderer.h
|
||||
index b47ea07f..9ff4e21e 100644
|
||||
--- libweston/gl-renderer.h
|
||||
+++ libweston/gl-renderer.h
|
||||
@@ -38,6 +38,7 @@
|
||||
|
||||
typedef int EGLint;
|
||||
typedef int EGLenum;
|
||||
+typedef void *EGLDeviceEXT;
|
||||
typedef void *EGLDisplay;
|
||||
typedef void *EGLSurface;
|
||||
typedef void *EGLConfig;
|
||||
@@ -114,5 +115,12 @@ struct gl_renderer_interface {
|
||||
int32_t tex_width, unsigned char *data);
|
||||
|
||||
void (*print_egl_error_state)(void);
|
||||
+
|
||||
+ int (*get_devices)(EGLint max_devices,
|
||||
+ EGLDeviceEXT *devices,
|
||||
+ EGLint *num_devices);
|
||||
+
|
||||
+ int (*get_drm_device_file)(EGLDeviceEXT device,
|
||||
+ const char **drm_device_file);
|
||||
};
|
||||
|
||||
--
|
||||
2.11.1
|
||||
|
|
@ -0,0 +1,522 @@
|
|||
From b67b64f6c7565a88558f1398895830394b887ee3 Mon Sep 17 00:00:00 2001
|
||||
From: "Miguel A. Vico" <mvicomoya@nvidia.com>
|
||||
Date: Mon, 2 May 2016 16:34:01 +0200
|
||||
Subject: [PATCH 2/7] gl-renderer: Add support for EGLDevice composited frame
|
||||
presentation
|
||||
X-NVConfidentiality: public
|
||||
|
||||
EGLDevice provides means to enumerate native devices, and then create
|
||||
an EGL display connection from them.
|
||||
|
||||
Similarly, EGLOutput will provide means to access different
|
||||
portions of display control hardware associated with an EGLDevice.
|
||||
|
||||
For instance, EGLOutputLayer represents a portion of display
|
||||
control hardware that accepts an image as input and processes it
|
||||
for presentation on a display device.
|
||||
|
||||
EGLStream implements a mechanism to communicate frame producers and
|
||||
frame consumers. By attaching an EGLOutputLayer consumer to a stream,
|
||||
a producer will be able to present frames on a display device.
|
||||
|
||||
Thus, a compositor could produce frames and feed them to an
|
||||
EGLOutputLayer through an EGLStream for presentation on a display
|
||||
device.
|
||||
|
||||
This change adds required logic to support presentation approach
|
||||
described above.
|
||||
|
||||
Note that some unpublished EGL extensions were needed:
|
||||
|
||||
- EGL_NV_stream_attrib:
|
||||
https://github.com/aritger/eglstreams-kms-example/blob/master/proposed-extensions/EGL_NV_stream_attrib.txt
|
||||
|
||||
- EGL_EXT_stream_acquire_mode:
|
||||
https://github.com/aritger/eglstreams-kms-example/blob/master/proposed-extensions/EGL_EXT_stream_acquire_mode.txt
|
||||
|
||||
- EGL_NV_output_drm_flip_event:
|
||||
https://github.com/aritger/eglstreams-kms-example/blob/master/proposed-extensions/EGL_NV_output_drm_flip_event.txt
|
||||
|
||||
Signed-off-by: Miguel A Vico Moya <mvicomoya@nvidia.com>
|
||||
Reviewed-by: Andy Ritger <aritger@nvidia.com>
|
||||
Reviewed-by: Adam Cheney <acheney@nvidia.com>
|
||||
Reviewed-by: James Jones <jajones@nvidia.com>
|
||||
---
|
||||
libweston/gl-renderer.c | 262 +++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
libweston/gl-renderer.h | 16 +++
|
||||
shared/weston-egl-ext.h | 40 ++++++++
|
||||
3 files changed, 315 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libweston/gl-renderer.c b/libweston/gl-renderer.c
|
||||
index 7a840a35..498a14bd 100644
|
||||
--- libweston/gl-renderer.c
|
||||
+++ libweston/gl-renderer.c
|
||||
@@ -86,6 +86,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;
|
||||
};
|
||||
|
||||
@@ -209,6 +211,28 @@ struct gl_renderer {
|
||||
|
||||
int has_surfaceless_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;
|
||||
|
||||
@@ -1196,6 +1220,38 @@ 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 (gr->stream_consumer_acquire_attrib(
|
||||
+ gr->egl_display,
|
||||
+ go->egl_stream,
|
||||
+ acquire_attribs) != EGL_TRUE)
|
||||
+ 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,
|
||||
@@ -2699,9 +2755,93 @@ 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 gl_output_state *go;
|
||||
int i;
|
||||
@@ -2711,6 +2851,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]);
|
||||
@@ -2743,13 +2884,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)
|
||||
weston_platform_destroy_egl_surface(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)
|
||||
{
|
||||
@@ -2766,6 +2935,9 @@ gl_renderer_output_destroy(struct weston_output *output)
|
||||
|
||||
weston_platform_destroy_egl_surface(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);
|
||||
}
|
||||
|
||||
@@ -2861,6 +3033,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);
|
||||
@@ -2911,6 +3096,30 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
|
||||
if (weston_check_egl_extension(extensions, "GL_EXT_texture_rg"))
|
||||
gr->has_gl_texture_rg = 1;
|
||||
|
||||
+ if (weston_check_egl_extension(extensions, "EGL_EXT_output_base"))
|
||||
+ gr->has_egl_output_base = 1;
|
||||
+
|
||||
+ if (weston_check_egl_extension(extensions, "EGL_EXT_output_drm"))
|
||||
+ gr->has_egl_output_drm = 1;
|
||||
+
|
||||
+ if (weston_check_egl_extension(extensions, "EGL_NV_output_drm_flip_event"))
|
||||
+ gr->has_egl_output_drm_flip_event = 1;
|
||||
+
|
||||
+ if (weston_check_egl_extension(extensions, "EGL_KHR_stream"))
|
||||
+ gr->has_egl_stream = 1;
|
||||
+
|
||||
+ if (weston_check_egl_extension(extensions, "EGL_KHR_stream_producer_eglsurface"))
|
||||
+ gr->has_egl_stream_producer_eglsurface = 1;
|
||||
+
|
||||
+ if (weston_check_egl_extension(extensions, "EGL_EXT_stream_consumer_egloutput"))
|
||||
+ gr->has_egl_stream_consumer_egloutput = 1;
|
||||
+
|
||||
+ if (weston_check_egl_extension(extensions, "EGL_NV_stream_attrib"))
|
||||
+ gr->has_egl_stream_attrib = 1;
|
||||
+
|
||||
+ if (weston_check_egl_extension(extensions, "EGL_EXT_stream_acquire_mode"))
|
||||
+ gr->has_egl_stream_acquire_mode = 1;
|
||||
+
|
||||
renderer_setup_egl_client_extensions(gr);
|
||||
|
||||
return 0;
|
||||
@@ -2936,6 +3145,15 @@ 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
|
||||
*
|
||||
@@ -3009,6 +3227,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");
|
||||
}
|
||||
@@ -3145,6 +3365,38 @@ 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;
|
||||
@@ -3444,15 +3696,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/libweston/gl-renderer.h b/libweston/gl-renderer.h
|
||||
index 9ff4e21e..39ea3b42 100644
|
||||
--- libweston/gl-renderer.h
|
||||
+++ libweston/gl-renderer.h
|
||||
@@ -60,6 +60,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,
|
||||
@@ -78,6 +79,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);
|
||||
@@ -122,5 +126,17 @@ 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/shared/weston-egl-ext.h b/shared/weston-egl-ext.h
|
||||
index f3e6dcea..1c3fec1c 100644
|
||||
--- shared/weston-egl-ext.h
|
||||
+++ shared/weston-egl-ext.h
|
||||
@@ -158,12 +158,52 @@ typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLD
|
||||
#define EGL_PLATFORM_X11_KHR 0x31D5
|
||||
#endif
|
||||
|
||||
+#ifndef EGL_PLATFORM_DEVICE_EXT
|
||||
+#define EGL_PLATFORM_DEVICE_EXT 0x313F
|
||||
+#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 */
|
||||
+
|
||||
#else /* ENABLE_EGL */
|
||||
|
||||
/* EGL platform definition are keept to allow compositor-xx.c to build */
|
||||
#define EGL_PLATFORM_GBM_KHR 0x31D7
|
||||
#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
|
||||
#define EGL_PLATFORM_X11_KHR 0x31D5
|
||||
+#define EGL_PLATFORM_DEVICE_EXT 0x313F
|
||||
|
||||
#endif /* ENABLE_EGL */
|
||||
|
||||
--
|
||||
2.11.1
|
||||
|
|
@ -0,0 +1,326 @@
|
|||
From aa3aee0503249a0d667dba1001b292b3907fad18 Mon Sep 17 00:00:00 2001
|
||||
From: "Miguel A. Vico" <mvicomoya@nvidia.com>
|
||||
Date: Mon, 2 May 2016 18:22:47 +0200
|
||||
Subject: [PATCH 3/7] gl-renderer: Add EGL client support for EGLStream frame
|
||||
presentation
|
||||
X-NVConfidentiality: public
|
||||
|
||||
By attaching a GLTexture consumer to a stream, a producer (wayland EGL
|
||||
client) could feed frames to a texture, which in turn can be used by a
|
||||
compositor to prepare the final frame to be presented.
|
||||
|
||||
This change adds required logic to support presentation approach
|
||||
described above.
|
||||
|
||||
Note that some unpublished EGL extensions were needed:
|
||||
|
||||
- EGL_NV_stream_attrib:
|
||||
https://github.com/aritger/eglstreams-kms-example/blob/master/proposed-extensions/EGL_NV_stream_attrib.txt
|
||||
|
||||
- EGL_WL_wayland_eglstream:
|
||||
https://github.com/aritger/eglstreams-kms-example/blob/master/proposed-extensions/EGL_WL_wayland_eglstream.txt
|
||||
|
||||
Signed-off-by: Miguel A Vico Moya <mvicomoya@nvidia.com>
|
||||
Reviewed-by: Adam Cheney <acheney@nvidia.com>
|
||||
Reviewed-by: James Jones <jajones@nvidia.com>
|
||||
---
|
||||
libweston/gl-renderer.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
shared/weston-egl-ext.h | 5 ++
|
||||
2 files changed, 187 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libweston/gl-renderer.c b/libweston/gl-renderer.c
|
||||
index 498a14bd..6bcfe40f 100644
|
||||
--- libweston/gl-renderer.c
|
||||
+++ libweston/gl-renderer.c
|
||||
@@ -168,6 +168,9 @@ struct gl_surface_state {
|
||||
int hsub[3]; /* horizontal subsampling per plane */
|
||||
int vsub[3]; /* vertical subsampling per plane */
|
||||
|
||||
+ EGLStreamKHR egl_stream;
|
||||
+ bool new_stream;
|
||||
+
|
||||
struct weston_surface *surface;
|
||||
|
||||
struct wl_listener surface_destroy_listener;
|
||||
@@ -219,6 +222,7 @@ struct gl_renderer {
|
||||
|
||||
PFNEGLCREATESTREAMKHRPROC create_stream;
|
||||
PFNEGLDESTROYSTREAMKHRPROC destroy_stream;
|
||||
+ PFNEGLQUERYSTREAMKHRPROC query_stream;
|
||||
int has_egl_stream;
|
||||
|
||||
PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC create_stream_producer_surface;
|
||||
@@ -228,11 +232,16 @@ struct gl_renderer {
|
||||
int has_egl_stream_consumer_egloutput;
|
||||
|
||||
#ifdef EGL_NV_stream_attrib
|
||||
+ PFNEGLCREATESTREAMATTRIBNVPROC create_stream_attrib;
|
||||
PFNEGLSTREAMCONSUMERACQUIREATTRIBNVPROC stream_consumer_acquire_attrib;
|
||||
#endif
|
||||
int has_egl_stream_attrib;
|
||||
int has_egl_stream_acquire_mode;
|
||||
|
||||
+ PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC stream_consumer_gltexture;
|
||||
+ int has_egl_stream_consumer_gltexture;
|
||||
+ int has_egl_wayland_eglstream;
|
||||
+
|
||||
int has_dmabuf_import;
|
||||
struct wl_list dmabuf_images;
|
||||
|
||||
@@ -2050,6 +2059,145 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
|
||||
gs->y_inverted = buffer->y_inverted;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * gl_renderer_attach_stream_texture
|
||||
+ *
|
||||
+ * Try to bind given <buffer> to an EGLStream. If the given buffer was already
|
||||
+ * bound, it will acquire next frame on the stream.
|
||||
+ *
|
||||
+ * Return true if the given <buffer> corresponds to an EGLStream; otherwise,
|
||||
+ * return false (if might be another kind of buffer).
|
||||
+ */
|
||||
+static bool
|
||||
+gl_renderer_attach_stream_texture(struct weston_surface *es,
|
||||
+ struct weston_buffer *buffer)
|
||||
+{
|
||||
+#ifdef EGL_NV_stream_attrib
|
||||
+ struct weston_compositor *ec = es->compositor;
|
||||
+ struct gl_renderer *gr = get_renderer(ec);
|
||||
+ struct gl_surface_state *gs = get_surface_state(es);
|
||||
+ EGLStreamKHR stream = EGL_NO_STREAM_KHR;
|
||||
+ EGLAttrib stream_attribs[] = {
|
||||
+#ifdef EGL_WL_wayland_eglstream
|
||||
+ EGL_WAYLAND_EGLSTREAM_WL, (EGLAttrib)buffer->resource,
|
||||
+#endif
|
||||
+ EGL_NONE
|
||||
+ };
|
||||
+ EGLint stream_state = EGL_STREAM_STATE_EMPTY_KHR;
|
||||
+
|
||||
+ /* Check for required extensions. If they arent supported, there's no
|
||||
+ * way the given buffer corresponds to an EGLStream */
|
||||
+ if (!gr->has_egl_stream_attrib ||
|
||||
+ !gr->has_egl_stream_consumer_gltexture ||
|
||||
+ !gr->has_egl_wayland_eglstream)
|
||||
+ return false;
|
||||
+
|
||||
+ stream = gr->create_stream_attrib(gr->egl_display, stream_attribs);
|
||||
+ if (stream == EGL_NO_STREAM_KHR) {
|
||||
+ EGLint err = eglGetError();
|
||||
+
|
||||
+ switch (err) {
|
||||
+ case EGL_BAD_ACCESS:
|
||||
+ /* EGL_BAD_ACCESS is generated whenever buffer->resource
|
||||
+ * does not corresponds to a stream */
|
||||
+ return false;
|
||||
+
|
||||
+ case EGL_BAD_STREAM_KHR:
|
||||
+ /* EGL_BAD_STREAM_KHR is generated whenever
|
||||
+ * buffer->resource corresponds to a previously created
|
||||
+ * stream so we must have a valid stream handle already
|
||||
+ * we can use to acquire next frame */
|
||||
+ break;
|
||||
+
|
||||
+ default:
|
||||
+ /* An unknown error was generated */
|
||||
+ assert(0);
|
||||
+ return false;
|
||||
+ }
|
||||
+ } else {
|
||||
+ /* Clean up current stream resources if needed */
|
||||
+ if (gs->egl_stream != EGL_NO_STREAM_KHR)
|
||||
+ gr->destroy_stream(gr->egl_display, gs->egl_stream);
|
||||
+
|
||||
+ gs->egl_stream = stream;
|
||||
+ gs->shader = &gr->texture_shader_egl_external;
|
||||
+ gs->target = GL_TEXTURE_EXTERNAL_OES;
|
||||
+
|
||||
+ glActiveTexture(GL_TEXTURE0);
|
||||
+ ensure_textures(gs, 2);
|
||||
+ glBindTexture(gs->target, gs->textures[1]);
|
||||
+
|
||||
+ gs->new_stream = (gr->stream_consumer_gltexture(
|
||||
+ gr->egl_display,
|
||||
+ gs->egl_stream) == EGL_TRUE);
|
||||
+
|
||||
+ if (!gs->new_stream) {
|
||||
+ weston_log("failed to set stream consumer\n");
|
||||
+ gl_renderer_print_egl_error_state();
|
||||
+ gr->destroy_stream(gr->egl_display, gs->egl_stream);
|
||||
+ gs->egl_stream = EGL_NO_STREAM_KHR;
|
||||
+ return true; /* buffer->resource is EGLStream */
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* At this point we should have a valid stream handle */
|
||||
+ assert(gs->egl_stream != EGL_NO_STREAM_KHR);
|
||||
+
|
||||
+ /* Check whether there are new frames available */
|
||||
+ if (gr->query_stream(gr->egl_display,
|
||||
+ gs->egl_stream,
|
||||
+ EGL_STREAM_STATE_KHR,
|
||||
+ &stream_state) != EGL_TRUE) {
|
||||
+ weston_log("failed to query stream state\n");
|
||||
+ gl_renderer_print_egl_error_state();
|
||||
+ return true; /* buffer->resource is EGLStream */
|
||||
+ }
|
||||
+
|
||||
+ /* If no new frame available, re-use last one */
|
||||
+ if (stream_state != EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR) {
|
||||
+ /* Fake size of last frame */
|
||||
+ buffer->width = gs->pitch;
|
||||
+ buffer->height = gs->height;
|
||||
+ return true; /* buffer->resource is EGLStream */
|
||||
+ }
|
||||
+
|
||||
+ if (gr->stream_consumer_acquire_attrib(gr->egl_display,
|
||||
+ gs->egl_stream,
|
||||
+ NULL) != EGL_TRUE) {
|
||||
+ weston_log("failed to acquire buffer\n");
|
||||
+ gl_renderer_print_egl_error_state();
|
||||
+ return true; /* buffer->resource is EGLStream */
|
||||
+ }
|
||||
+
|
||||
+ /* Swap textures if new stream was created */
|
||||
+ if (gs->new_stream) {
|
||||
+ GLuint tmp = gs->textures[0];
|
||||
+
|
||||
+ gs->textures[0] = gs->textures[1];
|
||||
+ gs->textures[1] = tmp;
|
||||
+ gs->new_stream = false;
|
||||
+ }
|
||||
+
|
||||
+ /* Update buffer and surface data */
|
||||
+ buffer->legacy_buffer = (void *)buffer->resource;
|
||||
+ gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
|
||||
+ EGL_WIDTH, &buffer->width);
|
||||
+ gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
|
||||
+ EGL_HEIGHT, &buffer->height);
|
||||
+ gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
|
||||
+ EGL_WAYLAND_Y_INVERTED_WL, &buffer->y_inverted);
|
||||
+
|
||||
+ gs->pitch = buffer->width;
|
||||
+ gs->height = buffer->height;
|
||||
+ gs->buffer_type = BUFFER_TYPE_EGL;
|
||||
+ gs->y_inverted = buffer->y_inverted;
|
||||
+
|
||||
+ return true; /* buffer->resource is EGLStream */
|
||||
+#else
|
||||
+ return false;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
static void
|
||||
gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
|
||||
{
|
||||
@@ -2073,6 +2221,12 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
|
||||
gs->num_textures = 0;
|
||||
gs->buffer_type = BUFFER_TYPE_NULL;
|
||||
gs->y_inverted = 1;
|
||||
+
|
||||
+ if (gs->egl_stream != EGL_NO_STREAM_KHR) {
|
||||
+ gr->destroy_stream(gr->egl_display, gs->egl_stream);
|
||||
+ gs->egl_stream = EGL_NO_STREAM_KHR;
|
||||
+ }
|
||||
+
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2086,7 +2240,7 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
|
||||
gl_renderer_attach_egl(es, buffer, format);
|
||||
else if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource)))
|
||||
gl_renderer_attach_dmabuf(es, buffer, dmabuf);
|
||||
- else {
|
||||
+ else if (!gl_renderer_attach_stream_texture(es, buffer)) {
|
||||
weston_log("unhandled buffer type!\n");
|
||||
weston_buffer_reference(&gs->buffer_ref, NULL);
|
||||
gs->buffer_type = BUFFER_TYPE_NULL;
|
||||
@@ -2274,6 +2428,10 @@ surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
|
||||
|
||||
weston_buffer_reference(&gs->buffer_ref, NULL);
|
||||
pixman_region32_fini(&gs->texture_damage);
|
||||
+
|
||||
+ if (gs->egl_stream != EGL_NO_STREAM_KHR)
|
||||
+ gr->destroy_stream(gr->egl_display, gs->egl_stream);
|
||||
+
|
||||
free(gs);
|
||||
}
|
||||
|
||||
@@ -2324,6 +2482,8 @@ gl_renderer_create_surface(struct weston_surface *surface)
|
||||
|
||||
gs->surface = surface;
|
||||
|
||||
+ gs->egl_stream = EGL_NO_STREAM_KHR;
|
||||
+
|
||||
pixman_region32_init(&gs->texture_damage);
|
||||
surface->renderer_state = gs;
|
||||
|
||||
@@ -3038,14 +3198,19 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
|
||||
(void *) eglGetProcAddress("eglQueryOutputLayerAttribEXT");
|
||||
gr->create_stream = (void *) eglGetProcAddress("eglCreateStreamKHR");
|
||||
gr->destroy_stream = (void *) eglGetProcAddress("eglDestroyStreamKHR");
|
||||
+ gr->query_stream = (void *) eglGetProcAddress("eglQueryStreamKHR");
|
||||
gr->create_stream_producer_surface =
|
||||
(void *) eglGetProcAddress("eglCreateStreamProducerSurfaceKHR");
|
||||
gr->stream_consumer_output =
|
||||
(void *) eglGetProcAddress("eglStreamConsumerOutputEXT");
|
||||
#ifdef EGL_NV_stream_attrib
|
||||
+ gr->create_stream_attrib =
|
||||
+ (void *) eglGetProcAddress("eglCreateStreamAttribNV");
|
||||
gr->stream_consumer_acquire_attrib =
|
||||
(void *) eglGetProcAddress("eglStreamConsumerAcquireAttribNV");
|
||||
#endif
|
||||
+ gr->stream_consumer_gltexture =
|
||||
+ (void *) eglGetProcAddress("eglStreamConsumerGLTextureExternalKHR");
|
||||
|
||||
extensions =
|
||||
(const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
|
||||
@@ -3120,6 +3285,12 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
|
||||
if (weston_check_egl_extension(extensions, "EGL_EXT_stream_acquire_mode"))
|
||||
gr->has_egl_stream_acquire_mode = 1;
|
||||
|
||||
+ if (weston_check_egl_extension(extensions, "EGL_KHR_stream_consumer_gltexture"))
|
||||
+ gr->has_egl_stream_consumer_gltexture = 1;
|
||||
+
|
||||
+ if (weston_check_egl_extension(extensions, "EGL_WL_wayland_eglstream"))
|
||||
+ gr->has_egl_wayland_eglstream = 1;
|
||||
+
|
||||
renderer_setup_egl_client_extensions(gr);
|
||||
|
||||
return 0;
|
||||
@@ -3392,6 +3563,16 @@ gl_renderer_display_create(struct weston_compositor *ec, EGLenum platform,
|
||||
goto fail_terminate;
|
||||
}
|
||||
|
||||
+ if (!gr->has_egl_stream_consumer_gltexture ||
|
||||
+ !gr->has_egl_wayland_eglstream)
|
||||
+ weston_log("warning: following required extensions for "
|
||||
+ "EGL client frame presentation through "
|
||||
+ "EGLDevice not supported:\n%s%s",
|
||||
+ (gr->has_egl_stream_consumer_gltexture ? "" :
|
||||
+ " EGL_KHR_stream_consumer_gltexture\n"),
|
||||
+ (gr->has_egl_wayland_eglstream ? "" :
|
||||
+ " EGL_WL_wayland_eglstream\n"));
|
||||
+
|
||||
if (!gr->has_egl_output_drm_flip_event)
|
||||
weston_log("warning: EGL page flip event notification "
|
||||
"not supported\n");
|
||||
diff --git a/shared/weston-egl-ext.h b/shared/weston-egl-ext.h
|
||||
index 1c3fec1c..11e9ccc1 100644
|
||||
--- shared/weston-egl-ext.h
|
||||
+++ shared/weston-egl-ext.h
|
||||
@@ -197,6 +197,11 @@ EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireAttribEXT (EGLDisplay dpy,
|
||||
#define EGL_DRM_FLIP_EVENT_DATA_NV 0x333E
|
||||
#endif /* EGL_NV_output_drm_flip_event */
|
||||
|
||||
+#ifndef EGL_WL_wayland_eglstream
|
||||
+#define EGL_WL_wayland_eglstream 1
|
||||
+#define EGL_WAYLAND_EGLSTREAM_WL 0x334B
|
||||
+#endif /* EGL_WL_wayland_eglstream */
|
||||
+
|
||||
#else /* ENABLE_EGL */
|
||||
|
||||
/* EGL platform definition are keept to allow compositor-xx.c to build */
|
||||
--
|
||||
2.11.1
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
From d89c874ea121b6855c7bdf2e757fa13d0b04661f Mon Sep 17 00:00:00 2001
|
||||
From: "Miguel A. Vico" <mvicomoya@nvidia.com>
|
||||
Date: Tue, 1 Mar 2016 22:19:14 +0100
|
||||
Subject: [PATCH 4/7] compositor-drm: Gracefully handle vblank and flip invalid
|
||||
timestamps
|
||||
X-NVConfidentiality: public
|
||||
|
||||
Instant query for vblank timestamp may always fail, resulting in
|
||||
never scheduling a full repaint in drm_output_start_repaint_loop().
|
||||
|
||||
Additionally, timestamp provided in page_flip_handler() may also be
|
||||
invalid.
|
||||
|
||||
This change makes both drm_output_start_repaint_loop() and
|
||||
page_flip_handler() to schedule a full repaint in any of the
|
||||
situations above.
|
||||
|
||||
Signed-off-by: Miguel A Vico Moya <mvicomoya@nvidia.com>
|
||||
Reviewed-by: Andy Ritger <aritger@nvidia.com>
|
||||
---
|
||||
libweston/compositor-drm.c | 28 +++++++++++++++++++++++++---
|
||||
1 file changed, 25 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
|
||||
index 1d38f051..12c1b8b5 100644
|
||||
--- libweston/compositor-drm.c
|
||||
+++ libweston/compositor-drm.c
|
||||
@@ -1,6 +1,7 @@
|
||||
/*
|
||||
* Copyright © 2008-2011 Kristian Høgsberg
|
||||
* Copyright © 2011 Intel Corporation
|
||||
+ * Copyright © 2016 NVIDIA Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
@@ -825,8 +826,16 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
|
||||
vbl.request.type |= drm_waitvblank_pipe(output);
|
||||
ret = drmWaitVBlank(backend->drm.fd, &vbl);
|
||||
|
||||
- /* Error ret or zero timestamp means failure to get valid timestamp */
|
||||
- if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
|
||||
+ if (ret) {
|
||||
+ /* Immediate query failed. It may always fail so we'll never get
|
||||
+ * a valid timestamp to update msc and call into finish frame.
|
||||
+ * Hence, jump to finish frame here.
|
||||
+ */
|
||||
+ goto finish_frame;
|
||||
+ }
|
||||
+
|
||||
+ /* Zero timestamp means failure to get valid timestamp */
|
||||
+ if (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0) {
|
||||
ts.tv_sec = vbl.reply.tval_sec;
|
||||
ts.tv_nsec = vbl.reply.tval_usec * 1000;
|
||||
|
||||
@@ -847,7 +856,7 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
|
||||
}
|
||||
}
|
||||
|
||||
- /* Immediate query didn't provide valid timestamp.
|
||||
+ /* Immediate query succeeded, but didn't provide valid timestamp.
|
||||
* Use pageflip fallback.
|
||||
*/
|
||||
fb_id = output->current->fb_id;
|
||||
@@ -935,6 +944,19 @@ page_flip_handler(int fd, unsigned int frame,
|
||||
else if (!output->vblank_pending) {
|
||||
ts.tv_sec = sec;
|
||||
ts.tv_nsec = usec * 1000;
|
||||
+
|
||||
+ /* Zero timestamp means failure to get valid timestamp, so
|
||||
+ * immediately finish frame
|
||||
+ *
|
||||
+ * FIXME: Driver should never return an invalid page flip
|
||||
+ * timestamp */
|
||||
+ if (ts.tv_sec == 0 && ts.tv_nsec == 0) {
|
||||
+ weston_compositor_read_presentation_clock(
|
||||
+ output->base.compositor,
|
||||
+ &ts);
|
||||
+ flags = WP_PRESENTATION_FEEDBACK_INVALID;
|
||||
+ }
|
||||
+
|
||||
weston_output_finish_frame(&output->base, &ts, flags);
|
||||
|
||||
/* We can't call this from frame_notify, because the output's
|
||||
--
|
||||
2.11.1
|
||||
|
|
@ -0,0 +1,542 @@
|
|||
From b1db106d3c91c1b35a01573a455c5661a17a06ee Mon Sep 17 00:00:00 2001
|
||||
From: "Miguel A. Vico" <mvicomoya@nvidia.com>
|
||||
Date: Thu, 28 Jan 2016 19:37:10 +0100
|
||||
Subject: [PATCH 5/7] compositor-drm: Add support for EGLDevice+EGLOutput
|
||||
X-NVConfidentiality: public
|
||||
|
||||
As previously stated, EGLDevice and EGLOutput will provide means
|
||||
to access native device objects and different portions of display
|
||||
control hardware respectively.
|
||||
|
||||
Whenever EGL_EXT_device_drm extension is present, EGLDevice can
|
||||
be used to enumerate and access DRM KMS devices, and EGLOutputLayer
|
||||
to enumerate and access DRM KMS crtcs and planes.
|
||||
|
||||
By using EGLStreams and attaching an EGLOutputLayer consumer
|
||||
(representing a DRM KMS crtc or plane) to it, compositor-drm can
|
||||
produce final composition frames and present them on a DRM device.
|
||||
|
||||
This change adds required logic to support presentation through
|
||||
EGLDevice+EGLOutput+EGLStream. Whether GBM or EGLDevice should be
|
||||
used can be controlled by --use-egldevice backend argument.
|
||||
|
||||
Signed-off-by: Miguel A Vico Moya <mvicomoya@nvidia.com>
|
||||
Reviewed-by: Andy Ritger <aritger@nvidia.com>
|
||||
Reviewed-by: Adam Cheney <acheney@nvidia.com>
|
||||
Reviewed-by: James Jones <jajones@nvidia.com>
|
||||
---
|
||||
compositor/main.c | 2 +
|
||||
libweston/compositor-drm.c | 303 ++++++++++++++++++++++++++++++++-------------
|
||||
libweston/compositor-drm.h | 4 +
|
||||
libweston/gl-renderer.h | 1 +
|
||||
shared/weston-egl-ext.h | 9 ++
|
||||
5 files changed, 230 insertions(+), 89 deletions(-)
|
||||
|
||||
diff --git a/compositor/main.c b/compositor/main.c
|
||||
index 72c3cd10..ad348d82 100644
|
||||
--- compositor/main.c
|
||||
+++ compositor/main.c
|
||||
@@ -566,6 +566,7 @@ usage(int error_code)
|
||||
" --seat=SEAT\t\tThe seat that weston should run on\n"
|
||||
" --tty=TTY\t\tThe tty to use\n"
|
||||
" --use-pixman\t\tUse the pixman (CPU) renderer\n"
|
||||
+ " --use-egldevice\tUse EGLDevice and EGLOutput with the GL renderer\n"
|
||||
" --current-mode\tPrefer current KMS mode over EDID preferred mode\n\n");
|
||||
#endif
|
||||
|
||||
@@ -1227,6 +1228,7 @@ load_drm_backend(struct weston_compositor *c,
|
||||
{ WESTON_OPTION_INTEGER, "tty", 0, &config.tty },
|
||||
{ WESTON_OPTION_BOOLEAN, "current-mode", 0, &wet->drm_use_current_mode },
|
||||
{ WESTON_OPTION_BOOLEAN, "use-pixman", 0, &config.use_pixman },
|
||||
+ { WESTON_OPTION_BOOLEAN, "use-egldevice", 0, &config.use_egldevice },
|
||||
};
|
||||
|
||||
parse_options(options, ARRAY_LENGTH(options), argc, argv);
|
||||
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
|
||||
index 12c1b8b5..0236d196 100644
|
||||
--- libweston/compositor-drm.c
|
||||
+++ libweston/compositor-drm.c
|
||||
@@ -94,7 +94,10 @@ struct drm_backend {
|
||||
int fd;
|
||||
char *filename;
|
||||
} drm;
|
||||
+
|
||||
+ EGLDeviceEXT egldevice;
|
||||
struct gbm_device *gbm;
|
||||
+
|
||||
struct wl_listener session_listener;
|
||||
uint32_t gbm_format;
|
||||
|
||||
@@ -113,6 +116,7 @@ struct drm_backend {
|
||||
int cursors_are_broken;
|
||||
|
||||
int use_pixman;
|
||||
+ int use_egldevice;
|
||||
|
||||
struct udev_input input;
|
||||
|
||||
@@ -595,17 +599,21 @@ drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
|
||||
output->base.compositor->renderer->repaint_output(&output->base,
|
||||
damage);
|
||||
|
||||
- bo = gbm_surface_lock_front_buffer(output->gbm_surface);
|
||||
- if (!bo) {
|
||||
- weston_log("failed to lock front buffer: %m\n");
|
||||
- return;
|
||||
- }
|
||||
+ if (b->use_egldevice)
|
||||
+ output->next = output->dumb[0];
|
||||
+ else {
|
||||
+ bo = gbm_surface_lock_front_buffer(output->gbm_surface);
|
||||
+ if (!bo) {
|
||||
+ weston_log("failed to lock front buffer: %m\n");
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
- output->next = drm_fb_get_from_bo(bo, b, output->gbm_format);
|
||||
- if (!output->next) {
|
||||
- weston_log("failed to get drm_fb for bo\n");
|
||||
- gbm_surface_release_buffer(output->gbm_surface, bo);
|
||||
- return;
|
||||
+ output->next = drm_fb_get_from_bo(bo, b, output->gbm_format);
|
||||
+ if (!output->next) {
|
||||
+ weston_log("failed to get drm_fb for bo\n");
|
||||
+ gbm_surface_release_buffer(output->gbm_surface, bo);
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -730,9 +738,14 @@ drm_output_repaint(struct weston_output *output_base,
|
||||
output_base->set_dpms(output_base, WESTON_DPMS_ON);
|
||||
}
|
||||
|
||||
- if (drmModePageFlip(backend->drm.fd, output->crtc_id,
|
||||
- output->next->fb_id,
|
||||
- DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
|
||||
+ if (backend->use_egldevice)
|
||||
+ ret = gl_renderer->output_stream_flip(&output->base, output);
|
||||
+ else
|
||||
+ ret = drmModePageFlip(backend->drm.fd, output->crtc_id,
|
||||
+ output->next->fb_id,
|
||||
+ DRM_MODE_PAGE_FLIP_EVENT, output);
|
||||
+
|
||||
+ if (ret < 0) {
|
||||
weston_log("queueing pageflip failed: %m\n");
|
||||
goto err_pageflip;
|
||||
}
|
||||
@@ -803,7 +816,6 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
|
||||
struct drm_output *output = to_drm_output(output_base);
|
||||
struct drm_backend *backend =
|
||||
to_drm_backend(output_base->compositor);
|
||||
- uint32_t fb_id;
|
||||
struct timespec ts, tnow;
|
||||
struct timespec vbl2now;
|
||||
int64_t refresh_nsec;
|
||||
@@ -859,10 +871,14 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
|
||||
/* Immediate query succeeded, but didn't provide valid timestamp.
|
||||
* Use pageflip fallback.
|
||||
*/
|
||||
- fb_id = output->current->fb_id;
|
||||
+ if (backend->use_egldevice)
|
||||
+ ret = gl_renderer->output_stream_flip(&output->base, output);
|
||||
+ else
|
||||
+ ret = drmModePageFlip(backend->drm.fd, output->crtc_id,
|
||||
+ output->current->fb_id,
|
||||
+ DRM_MODE_PAGE_FLIP_EVENT, output);
|
||||
|
||||
- if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
|
||||
- DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
|
||||
+ if (ret < 0) {
|
||||
weston_log("queueing pageflip failed: %m\n");
|
||||
goto finish_frame;
|
||||
}
|
||||
@@ -1589,11 +1605,6 @@ create_gbm_device(int fd)
|
||||
{
|
||||
struct gbm_device *gbm;
|
||||
|
||||
- gl_renderer = weston_load_module("gl-renderer.so",
|
||||
- "gl_renderer_interface");
|
||||
- if (!gl_renderer)
|
||||
- return NULL;
|
||||
-
|
||||
/* GBM will load a dri driver, but even though they need symbols from
|
||||
* libglapi, in some version of Mesa they are not linked to it. Since
|
||||
* only the gl-renderer module links to it, the call above won't make
|
||||
@@ -1606,6 +1617,40 @@ create_gbm_device(int fd)
|
||||
return gbm;
|
||||
}
|
||||
|
||||
+static EGLDeviceEXT
|
||||
+find_egldevice(const char *filename)
|
||||
+{
|
||||
+ EGLDeviceEXT egldevice = EGL_NO_DEVICE_EXT;
|
||||
+ EGLDeviceEXT *devices;
|
||||
+ EGLint num_devices;
|
||||
+ const char *drm_path;
|
||||
+ int i;
|
||||
+
|
||||
+ if (gl_renderer->get_devices(0, NULL, &num_devices) < 0 ||
|
||||
+ num_devices < 1)
|
||||
+ return EGL_NO_DEVICE_EXT;
|
||||
+
|
||||
+ devices = zalloc(num_devices * sizeof *devices);
|
||||
+ if (!devices)
|
||||
+ return EGL_NO_DEVICE_EXT;
|
||||
+
|
||||
+ if (gl_renderer->get_devices(num_devices, devices, &num_devices) < 0) {
|
||||
+ free(devices);
|
||||
+ return EGL_NO_DEVICE_EXT;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < num_devices; i++)
|
||||
+ if (gl_renderer->get_drm_device_file(devices[i],
|
||||
+ &drm_path) == 0 &&
|
||||
+ strcmp(filename, drm_path) == 0) {
|
||||
+ egldevice = devices[i];
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ free(devices);
|
||||
+ return egldevice;
|
||||
+}
|
||||
+
|
||||
/* When initializing EGL, if the preferred buffer format isn't available
|
||||
* we may be able to substitute an ARGB format for an XRGB one.
|
||||
*
|
||||
@@ -1632,38 +1677,62 @@ fallback_format_for(uint32_t format)
|
||||
static int
|
||||
drm_backend_create_gl_renderer(struct drm_backend *b)
|
||||
{
|
||||
- EGLint format[3] = {
|
||||
- b->gbm_format,
|
||||
- fallback_format_for(b->gbm_format),
|
||||
- 0,
|
||||
- };
|
||||
- int n_formats = 2;
|
||||
+ if (b->use_egldevice) {
|
||||
+ EGLint device_platform_attribs[] = {
|
||||
+ EGL_DRM_MASTER_FD_EXT, b->drm.fd,
|
||||
+ EGL_NONE
|
||||
+ };
|
||||
|
||||
- if (format[1])
|
||||
- n_formats = 3;
|
||||
- if (gl_renderer->display_create(b->compositor,
|
||||
- EGL_PLATFORM_GBM_KHR,
|
||||
- (void *)b->gbm,
|
||||
+ return gl_renderer->display_create(
|
||||
+ b->compositor,
|
||||
+ EGL_PLATFORM_DEVICE_EXT,
|
||||
+ (void *)b->egldevice,
|
||||
+ device_platform_attribs,
|
||||
+ gl_renderer->opaque_stream_attribs,
|
||||
NULL,
|
||||
- gl_renderer->opaque_attribs,
|
||||
- format,
|
||||
- n_formats) < 0) {
|
||||
- return -1;
|
||||
- }
|
||||
+ 0);
|
||||
+ } else {
|
||||
+ EGLint format[3] = {
|
||||
+ b->gbm_format,
|
||||
+ fallback_format_for(b->gbm_format),
|
||||
+ 0,
|
||||
+ };
|
||||
+ int n_formats = 2;
|
||||
|
||||
- return 0;
|
||||
+ if (format[1])
|
||||
+ n_formats = 3;
|
||||
+
|
||||
+ return gl_renderer->display_create(b->compositor,
|
||||
+ EGL_PLATFORM_GBM_KHR,
|
||||
+ (void *)b->gbm,
|
||||
+ NULL,
|
||||
+ gl_renderer->opaque_attribs,
|
||||
+ format,
|
||||
+ n_formats);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int
|
||||
init_egl(struct drm_backend *b)
|
||||
{
|
||||
- b->gbm = create_gbm_device(b->drm.fd);
|
||||
-
|
||||
- if (!b->gbm)
|
||||
+ gl_renderer = weston_load_module("gl-renderer.so",
|
||||
+ "gl_renderer_interface");
|
||||
+ if (!gl_renderer)
|
||||
return -1;
|
||||
|
||||
+ if (b->use_egldevice) {
|
||||
+ b->egldevice = find_egldevice(b->drm.filename);
|
||||
+ if (b->egldevice == EGL_NO_DEVICE_EXT)
|
||||
+ return -1;
|
||||
+ } else {
|
||||
+ b->gbm = create_gbm_device(b->drm.fd);
|
||||
+ if (!b->gbm)
|
||||
+ return -1;
|
||||
+ }
|
||||
+
|
||||
if (drm_backend_create_gl_renderer(b) < 0) {
|
||||
- gbm_device_destroy(b->gbm);
|
||||
+ if (b->gbm)
|
||||
+ gbm_device_destroy(b->gbm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1894,50 +1963,83 @@ find_crtc_for_connector(struct drm_backend *b,
|
||||
static int
|
||||
drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
|
||||
{
|
||||
- EGLint format[2] = {
|
||||
- output->gbm_format,
|
||||
- fallback_format_for(output->gbm_format),
|
||||
- };
|
||||
- int i, flags, n_formats = 1;
|
||||
-
|
||||
- output->gbm_surface = gbm_surface_create(b->gbm,
|
||||
- output->base.current_mode->width,
|
||||
- output->base.current_mode->height,
|
||||
- format[0],
|
||||
- GBM_BO_USE_SCANOUT |
|
||||
- GBM_BO_USE_RENDERING);
|
||||
- if (!output->gbm_surface) {
|
||||
- weston_log("failed to create gbm surface\n");
|
||||
- return -1;
|
||||
- }
|
||||
+ if (b->use_egldevice) {
|
||||
+ int w = output->base.current_mode->width;
|
||||
+ int h = output->base.current_mode->height;
|
||||
|
||||
- if (format[1])
|
||||
- n_formats = 2;
|
||||
- if (gl_renderer->output_window_create(&output->base,
|
||||
- (EGLNativeWindowType)output->gbm_surface,
|
||||
- output->gbm_surface,
|
||||
- gl_renderer->opaque_attribs,
|
||||
- format,
|
||||
- n_formats) < 0) {
|
||||
- weston_log("failed to create gl renderer output state\n");
|
||||
- gbm_surface_destroy(output->gbm_surface);
|
||||
- return -1;
|
||||
- }
|
||||
+ /* Create a black dumb fb for modesetting */
|
||||
+ output->dumb[0] = drm_fb_create_dumb(b, w, h,
|
||||
+ DRM_FORMAT_XRGB8888);
|
||||
+ if (!output->dumb[0]) {
|
||||
+ weston_log("failed to create dumb framebuffer\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
+ memset(output->dumb[0]->map, 0, output->dumb[0]->size);
|
||||
+
|
||||
+ if (gl_renderer->output_stream_create(&output->base, ~0u,
|
||||
+ output->crtc_id) < 0) {
|
||||
+ weston_log("failed to create gl renderer output stream "
|
||||
+ "state\n");
|
||||
+ drm_fb_destroy_dumb(output->dumb[0]);
|
||||
+ output->dumb[0] = NULL;
|
||||
+ return -1;
|
||||
+ }
|
||||
|
||||
- flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
|
||||
+ /* FIXME: Add hw planes and cursors for EGL device when supported */
|
||||
+ b->sprites_are_broken = 1;
|
||||
+ b->cursors_are_broken = 1;
|
||||
+ } else {
|
||||
+ EGLint format[2] = {
|
||||
+ output->gbm_format,
|
||||
+ fallback_format_for(output->gbm_format),
|
||||
+ };
|
||||
+ int i, flags, n_formats = 1;
|
||||
+
|
||||
+ output->gbm_surface = gbm_surface_create(
|
||||
+ b->gbm,
|
||||
+ output->base.current_mode->width,
|
||||
+ output->base.current_mode->height,
|
||||
+ format[0],
|
||||
+ GBM_BO_USE_SCANOUT |
|
||||
+ GBM_BO_USE_RENDERING);
|
||||
+ if (!output->gbm_surface) {
|
||||
+ weston_log("failed to create gbm surface\n");
|
||||
+ return -1;
|
||||
+ }
|
||||
|
||||
- for (i = 0; i < 2; i++) {
|
||||
- if (output->gbm_cursor_bo[i])
|
||||
- continue;
|
||||
+ if (format[1])
|
||||
+ n_formats = 2;
|
||||
+ if (gl_renderer->output_window_create(
|
||||
+ &output->base,
|
||||
+ (EGLNativeWindowType)output->gbm_surface,
|
||||
+ output->gbm_surface,
|
||||
+ gl_renderer->opaque_attribs,
|
||||
+ format,
|
||||
+ n_formats) < 0) {
|
||||
+ weston_log("failed to create gl renderer output "
|
||||
+ "state\n");
|
||||
+ gbm_surface_destroy(output->gbm_surface);
|
||||
+ return -1;
|
||||
+ }
|
||||
|
||||
- output->gbm_cursor_bo[i] =
|
||||
- gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
|
||||
- GBM_FORMAT_ARGB8888, flags);
|
||||
- }
|
||||
+ flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
|
||||
|
||||
- if (output->gbm_cursor_bo[0] == NULL || output->gbm_cursor_bo[1] == NULL) {
|
||||
- weston_log("cursor buffers unavailable, using gl cursors\n");
|
||||
- b->cursors_are_broken = 1;
|
||||
+ for (i = 0; i < 2; i++) {
|
||||
+ if (output->gbm_cursor_bo[i])
|
||||
+ continue;
|
||||
+
|
||||
+ output->gbm_cursor_bo[i] =
|
||||
+ gbm_bo_create(b->gbm,
|
||||
+ b->cursor_width,
|
||||
+ b->cursor_height,
|
||||
+ GBM_FORMAT_ARGB8888,
|
||||
+ flags);
|
||||
+ }
|
||||
+
|
||||
+ if (output->gbm_cursor_bo[0] == NULL || output->gbm_cursor_bo[1] == NULL) {
|
||||
+ weston_log("cursor buffers unavailable, using gl cursors\n");
|
||||
+ b->cursors_are_broken = 1;
|
||||
+ }
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1947,7 +2049,14 @@ static void
|
||||
drm_output_fini_egl(struct drm_output *output)
|
||||
{
|
||||
gl_renderer->output_destroy(&output->base);
|
||||
- gbm_surface_destroy(output->gbm_surface);
|
||||
+
|
||||
+ if (output->dumb[0]) {
|
||||
+ drm_fb_destroy_dumb(output->dumb[0]);
|
||||
+ output->dumb[0] = NULL;
|
||||
+ }
|
||||
+
|
||||
+ if (output->gbm_surface)
|
||||
+ gbm_surface_destroy(output->gbm_surface);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -3107,6 +3216,11 @@ recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
|
||||
struct drm_output *output;
|
||||
int width, height;
|
||||
|
||||
+ if (b->use_egldevice) {
|
||||
+ weston_log("recorder not supported with EGL device\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
output = container_of(b->compositor->output_list.next,
|
||||
struct drm_output, base.link);
|
||||
|
||||
@@ -3162,11 +3276,20 @@ switch_to_gl_renderer(struct drm_backend *b)
|
||||
|
||||
weston_log("Switching to GL renderer\n");
|
||||
|
||||
- b->gbm = create_gbm_device(b->drm.fd);
|
||||
- if (!b->gbm) {
|
||||
- weston_log("Failed to create gbm device. "
|
||||
- "Aborting renderer switch\n");
|
||||
- return;
|
||||
+ if (b->use_egldevice) {
|
||||
+ b->egldevice = find_egldevice(b->drm.filename);
|
||||
+ if (b->egldevice == EGL_NO_DEVICE_EXT) {
|
||||
+ weston_log("Failed to create EGL device. "
|
||||
+ "Aborting renderer switch\n");
|
||||
+ return;
|
||||
+ }
|
||||
+ } else {
|
||||
+ b->gbm = create_gbm_device(b->drm.fd);
|
||||
+ if (!b->gbm) {
|
||||
+ weston_log("Failed to create gbm device. "
|
||||
+ "Aborting renderer switch\n");
|
||||
+ return;
|
||||
+ }
|
||||
}
|
||||
|
||||
wl_list_for_each(output, &b->compositor->output_list, base.link)
|
||||
@@ -3175,7 +3298,8 @@ switch_to_gl_renderer(struct drm_backend *b)
|
||||
b->compositor->renderer->destroy(b->compositor);
|
||||
|
||||
if (drm_backend_create_gl_renderer(b) < 0) {
|
||||
- gbm_device_destroy(b->gbm);
|
||||
+ if (b->gbm)
|
||||
+ gbm_device_destroy(b->gbm);
|
||||
weston_log("Failed to create GL renderer. Quitting.\n");
|
||||
/* FIXME: we need a function to shutdown cleanly */
|
||||
assert(0);
|
||||
@@ -3239,6 +3363,7 @@ drm_backend_create(struct weston_compositor *compositor,
|
||||
b->sprites_are_broken = 1;
|
||||
b->compositor = compositor;
|
||||
b->use_pixman = config->use_pixman;
|
||||
+ b->use_egldevice = config->use_egldevice;
|
||||
|
||||
if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
|
||||
goto err_compositor;
|
||||
diff --git a/libweston/compositor-drm.h b/libweston/compositor-drm.h
|
||||
index 2e2995a2..9cd0eef6 100644
|
||||
--- libweston/compositor-drm.h
|
||||
+++ libweston/compositor-drm.h
|
||||
@@ -110,6 +110,10 @@ struct weston_drm_backend_config {
|
||||
/** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
|
||||
bool use_pixman;
|
||||
|
||||
+ /** Whether to use the GL composition based off EGLDevice & friends instead
|
||||
+ * of GBM. */
|
||||
+ bool use_egldevice;
|
||||
+
|
||||
/** The seat to be used for input and output.
|
||||
*
|
||||
* If NULL the default "seat0" will be used. The backend will
|
||||
diff --git a/libweston/gl-renderer.h b/libweston/gl-renderer.h
|
||||
index 39ea3b42..37252492 100644
|
||||
--- libweston/gl-renderer.h
|
||||
+++ libweston/gl-renderer.h
|
||||
@@ -45,6 +45,7 @@ typedef void *EGLConfig;
|
||||
typedef intptr_t EGLNativeDisplayType;
|
||||
typedef intptr_t EGLNativeWindowType;
|
||||
#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
|
||||
+#define EGL_NO_DEVICE_EXT ((EGLDeviceEXT)0)
|
||||
|
||||
#endif /* ENABLE_EGL */
|
||||
|
||||
diff --git a/shared/weston-egl-ext.h b/shared/weston-egl-ext.h
|
||||
index 11e9ccc1..de82310f 100644
|
||||
--- shared/weston-egl-ext.h
|
||||
+++ shared/weston-egl-ext.h
|
||||
@@ -162,6 +162,10 @@ typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLD
|
||||
#define EGL_PLATFORM_DEVICE_EXT 0x313F
|
||||
#endif
|
||||
|
||||
+#ifndef EGL_DRM_MASTER_FD_EXT
|
||||
+#define EGL_DRM_MASTER_FD_EXT 0x333C
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* FIXME: Remove both EGL_EXT_stream_acquire_mode and
|
||||
* EGL_NV_output_drm_flip_event definitions below once both extensions
|
||||
@@ -210,6 +214,11 @@ EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireAttribEXT (EGLDisplay dpy,
|
||||
#define EGL_PLATFORM_X11_KHR 0x31D5
|
||||
#define EGL_PLATFORM_DEVICE_EXT 0x313F
|
||||
|
||||
+/* EGL_DRM_MASTER_FD_EXT and EGL_NONE enum values are also kept to allow
|
||||
+ * compositor-drm.c to build with EGLDevice and EGLStream support */
|
||||
+#define EGL_DRM_MASTER_FD_EXT 0x333C
|
||||
+#define EGL_NONE 0x3038
|
||||
+
|
||||
#endif /* ENABLE_EGL */
|
||||
|
||||
#endif
|
||||
--
|
||||
2.11.1
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
From c876b463f62b18da2446ad097d0bdad63d34363d Mon Sep 17 00:00:00 2001
|
||||
From: "Miguel A. Vico" <mvicomoya@nvidia.com>
|
||||
Date: Mon, 27 Feb 2017 15:31:35 -0800
|
||||
Subject: [PATCH 6/7] simple-egl: Do not set EGL up until XDG setup is complete
|
||||
X-NVConfidentiality: public
|
||||
|
||||
There is nothing that prohibits the underlying EGL_PLATFORM_WAYLAND
|
||||
implementation to attach a buffer or commit surfaces right after the
|
||||
Wayland EGLSurface has been created.
|
||||
|
||||
Since XDG Shell v6 imposes that no buffer attachments or surface commits
|
||||
must be done before a configure is complete, Wayland clients shouldn't
|
||||
start setting EGL up until XDG setup is complete.
|
||||
|
||||
Related bug:
|
||||
|
||||
https://bugs.freedesktop.org/show_bug.cgi?id=98731
|
||||
|
||||
Signed-off-by: Miguel A Vico Moya <mvicomoya@nvidia.com>
|
||||
---
|
||||
clients/simple-egl.c | 67 +++++++++++++++++++++++++++-------------------------
|
||||
1 file changed, 35 insertions(+), 32 deletions(-)
|
||||
|
||||
diff --git a/clients/simple-egl.c b/clients/simple-egl.c
|
||||
index 9b6fa1f2..59311cfc 100644
|
||||
--- clients/simple-egl.c
|
||||
+++ clients/simple-egl.c
|
||||
@@ -221,11 +221,32 @@ init_egl(struct display *display, struct window *window)
|
||||
if (display->swap_buffers_with_damage)
|
||||
printf("has EGL_EXT_buffer_age and %s\n", swap_damage_ext_to_entrypoint[i].extension);
|
||||
|
||||
+ window->egl_surface =
|
||||
+ weston_platform_create_egl_surface(display->egl.dpy,
|
||||
+ display->egl.conf,
|
||||
+ window->native, NULL);
|
||||
+
|
||||
+ ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
|
||||
+ window->egl_surface, window->display->egl.ctx);
|
||||
+ assert(ret == EGL_TRUE);
|
||||
+
|
||||
+ if (!window->frame_sync)
|
||||
+ eglSwapInterval(display->egl.dpy, 0);
|
||||
+
|
||||
}
|
||||
|
||||
static void
|
||||
-fini_egl(struct display *display)
|
||||
+fini_egl(struct display *display, struct window *window)
|
||||
{
|
||||
+ /* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
|
||||
+ * on eglReleaseThread(). */
|
||||
+ eglMakeCurrent(window->display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
+ EGL_NO_CONTEXT);
|
||||
+
|
||||
+ weston_platform_destroy_egl_surface(window->display->egl.dpy,
|
||||
+ window->egl_surface);
|
||||
+ wl_egl_window_destroy(window->native);
|
||||
+
|
||||
eglTerminate(display->egl.dpy);
|
||||
eglReleaseThread();
|
||||
}
|
||||
@@ -360,7 +381,8 @@ handle_ivi_surface_configure(void *data, struct ivi_surface *ivi_surface,
|
||||
{
|
||||
struct window *window = data;
|
||||
|
||||
- wl_egl_window_resize(window->native, width, height, 0, 0);
|
||||
+ if (window->native)
|
||||
+ wl_egl_window_resize(window->native, width, height, 0, 0);
|
||||
|
||||
window->geometry.width = width;
|
||||
window->geometry.height = height;
|
||||
@@ -413,7 +435,6 @@ static void
|
||||
create_surface(struct window *window)
|
||||
{
|
||||
struct display *display = window->display;
|
||||
- EGLBoolean ret;
|
||||
|
||||
window->surface = wl_compositor_create_surface(display->compositor);
|
||||
|
||||
@@ -421,10 +442,6 @@ create_surface(struct window *window)
|
||||
wl_egl_window_create(window->surface,
|
||||
window->geometry.width,
|
||||
window->geometry.height);
|
||||
- window->egl_surface =
|
||||
- weston_platform_create_egl_surface(display->egl.dpy,
|
||||
- display->egl.conf,
|
||||
- window->native, NULL);
|
||||
|
||||
|
||||
if (display->shell) {
|
||||
@@ -435,13 +452,6 @@ create_surface(struct window *window)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
- ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
|
||||
- window->egl_surface, window->display->egl.ctx);
|
||||
- assert(ret == EGL_TRUE);
|
||||
-
|
||||
- if (!window->frame_sync)
|
||||
- eglSwapInterval(display->egl.dpy, 0);
|
||||
-
|
||||
if (!display->shell)
|
||||
return;
|
||||
|
||||
@@ -452,15 +462,6 @@ create_surface(struct window *window)
|
||||
static void
|
||||
destroy_surface(struct window *window)
|
||||
{
|
||||
- /* Required, otherwise segfault in egl_dri2.c: dri2_make_current()
|
||||
- * on eglReleaseThread(). */
|
||||
- eglMakeCurrent(window->display->egl.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
|
||||
- EGL_NO_CONTEXT);
|
||||
-
|
||||
- weston_platform_destroy_egl_surface(window->display->egl.dpy,
|
||||
- window->egl_surface);
|
||||
- wl_egl_window_destroy(window->native);
|
||||
-
|
||||
if (window->xdg_toplevel)
|
||||
zxdg_toplevel_v6_destroy(window->xdg_toplevel);
|
||||
if (window->xdg_surface)
|
||||
@@ -895,9 +896,7 @@ main(int argc, char **argv)
|
||||
|
||||
wl_display_roundtrip(display.display);
|
||||
|
||||
- init_egl(&display, &window);
|
||||
create_surface(&window);
|
||||
- init_gl(&window);
|
||||
|
||||
display.cursor_surface =
|
||||
wl_compositor_create_surface(display.compositor);
|
||||
@@ -907,23 +906,27 @@ main(int argc, char **argv)
|
||||
sigint.sa_flags = SA_RESETHAND;
|
||||
sigaction(SIGINT, &sigint, NULL);
|
||||
|
||||
+ /* We must assure XDG setup is complete before setting EGL up */
|
||||
+ while (running && window.wait_for_configure) {
|
||||
+ wl_display_dispatch(display.display);
|
||||
+ }
|
||||
+
|
||||
+ init_egl(&display, &window);
|
||||
+ init_gl(&window);
|
||||
+
|
||||
/* The mainloop here is a little subtle. Redrawing will cause
|
||||
* EGL to read events so we can just call
|
||||
* wl_display_dispatch_pending() to handle any events that got
|
||||
* queued up as a side effect. */
|
||||
while (running && ret != -1) {
|
||||
- if (window.wait_for_configure) {
|
||||
- wl_display_dispatch(display.display);
|
||||
- } else {
|
||||
- wl_display_dispatch_pending(display.display);
|
||||
- redraw(&window, NULL, 0);
|
||||
- }
|
||||
+ wl_display_dispatch_pending(display.display);
|
||||
+ redraw(&window, NULL, 0);
|
||||
}
|
||||
|
||||
fprintf(stderr, "simple-egl exiting\n");
|
||||
|
||||
+ fini_egl(&display, &window);
|
||||
destroy_surface(&window);
|
||||
- fini_egl(&display);
|
||||
|
||||
wl_surface_destroy(display.cursor_surface);
|
||||
if (display.cursor_theme)
|
||||
--
|
||||
2.11.1
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
From 7f733c58c947c5355dda3d829dd0f4a47c4c819d Mon Sep 17 00:00:00 2001
|
||||
From: "Miguel A. Vico" <mvicomoya@nvidia.com>
|
||||
Date: Fri, 11 Nov 2016 20:07:19 +0100
|
||||
Subject: [PATCH 7/7] Add nvidia-release-notes file
|
||||
X-NVConfidentiality: public
|
||||
|
||||
Signed-off-by: Miguel A Vico Moya <mvicomoya@nvidia.com>
|
||||
---
|
||||
nvidia-release-notes | 21 +++++++++++++++++++++
|
||||
1 file changed, 21 insertions(+)
|
||||
create mode 100644 nvidia-release-notes
|
||||
|
||||
diff --git a/nvidia-release-notes b/nvidia-release-notes
|
||||
new file mode 100644
|
||||
index 00000000..4bd24000
|
||||
--- /dev/null
|
||||
+++ nvidia-release-notes
|
||||
@@ -0,0 +1,21 @@
|
||||
+NVIDIA EGLStream-based Weston version 2.0
|
||||
+-----------------------------------------
|
||||
+
|
||||
+This branch includes NVIDIA EGLStream patches on top of
|
||||
+Weston 2.0.
|
||||
+
|
||||
+* Known issues:
|
||||
+
|
||||
+ - Bad interactions with XDG Shell v6 preventing
|
||||
+ clients that implement the new interface from
|
||||
+ starting
|
||||
+
|
||||
+ Fixed in 'weston-simple-egl' with commit:
|
||||
+
|
||||
+ c876b463f62b18da2446ad097d0bdad63d34363d simple-egl: Do not set EGL up until XDG setup is complete
|
||||
+
|
||||
+
|
||||
+* Contact:
|
||||
+
|
||||
+ Miguel A. Vico (mvicomoya AT nvidia.com)
|
||||
+
|
||||
--
|
||||
2.11.1
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
From 812868a91f8c9c42167bf3bf2c66f6ec1f049c41 Mon Sep 17 00:00:00 2001
|
||||
From: "Miguel A. Vico" <mvicomoya@nvidia.com>
|
||||
Date: Tue, 4 Apr 2017 14:39:47 -0700
|
||||
Subject: [PATCH] compositor-drm: Release current & next fb when deactivating
|
||||
the session
|
||||
X-NVConfidentiality: public
|
||||
|
||||
With
|
||||
|
||||
commit 47224cc9312fef05c1a523ea0da0a1aae66f100d
|
||||
Author: Daniel Stone <daniels@collabora.com>
|
||||
Date: Sat Nov 5 08:04:07 2016 +0000
|
||||
|
||||
compositor-drm: Delete drm_backend_set_modes
|
||||
|
||||
we stopped forcing a modeset when restoring the session. The motivation
|
||||
was that we would use a stale fb, so better to let the next repaint
|
||||
handle it.
|
||||
|
||||
However, if drm_output::current != NULL, we won't issue a modeset upon
|
||||
repaint.
|
||||
|
||||
This change releases both drm_output::current and drm_output::next when
|
||||
deactivating the current session. This ensures the very first repaint
|
||||
after restoring the session will issue a modeset.
|
||||
|
||||
Signed-off-by: Miguel A Vico Moya <mvicomoya@nvidia.com>
|
||||
---
|
||||
libweston/compositor-drm.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
|
||||
index 0236d196..7283d0ff 100644
|
||||
--- libweston/compositor-drm.c
|
||||
+++ libweston/compositor-drm.c
|
||||
@@ -3058,6 +3058,14 @@ session_notify(struct wl_listener *listener, void *data)
|
||||
wl_list_for_each(output, &compositor->output_list, base.link) {
|
||||
output->base.repaint_needed = 0;
|
||||
drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
|
||||
+ if (output->current != NULL) {
|
||||
+ drm_output_release_fb(output, output->current);
|
||||
+ output->current = NULL;
|
||||
+ }
|
||||
+ if (output->next != NULL) {
|
||||
+ drm_output_release_fb(output, output->next);
|
||||
+ output->next = NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
output = container_of(compositor->output_list.next,
|
||||
--
|
||||
2.12.1
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
# Template file for 'weston'.
|
||||
pkgname=weston
|
||||
version=2.0.0
|
||||
revision=1
|
||||
revision=2
|
||||
build_style=gnu-configure
|
||||
# XXX enable rdp compositor if freerdp is updated to >=1.1.
|
||||
configure_args="--enable-libinput-backend --disable-setuid-install
|
||||
|
|
Loading…
Reference in New Issue