[weston] compositor: add support for OES_EGL_image_external

Message ID 1345156101-28827-2-git-send-email-rob.clark@linaro.org
State New
Headers show

Commit Message

Rob Clark Aug. 16, 2012, 10:28 p.m.
From: Rob Clark <rob@ti.com>

In cases where the GPU can natively handle certain YUV formats,
eglQueryWaylandBufferWL() can return the value EGL_TEXTURE_EXTERNAL_WL
and the compositor will treat the buffer as a single egl-image-external.

See:
http://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image_external.txt

v1: original
v2: rename EGL_TEXTURE_EXTERNAL_OES -> EGL_TEXTURE_EXTERNAL_WL and query
    for the extension

Signed-off-by: Rob Clark <rob@ti.com>
---
 src/compositor.c     |   47 +++++++++++++++++++++++++++++++++++++----------
 src/compositor.h     |    2 ++
 src/weston-egl-ext.h |    1 +
 3 files changed, 40 insertions(+), 10 deletions(-)

Comments

Pekka Paalanen Aug. 17, 2012, 6:09 a.m. | #1
On Thu, 16 Aug 2012 17:28:20 -0500
Rob Clark <rob.clark@linaro.org> wrote:

> From: Rob Clark <rob@ti.com>
> 
> In cases where the GPU can natively handle certain YUV formats,
> eglQueryWaylandBufferWL() can return the value EGL_TEXTURE_EXTERNAL_WL
> and the compositor will treat the buffer as a single egl-image-external.
> 
> See:
> http://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image_external.txt
> 
> v1: original
> v2: rename EGL_TEXTURE_EXTERNAL_OES -> EGL_TEXTURE_EXTERNAL_WL and query
>     for the extension
> 
> Signed-off-by: Rob Clark <rob@ti.com>

Looks good to me now. The only thing I could still say is that maybe it
would be nice to log a warning, if the extension is not detected, but
querySurface still returns EGL_TEXTURE_EXTERNAL_WL.

Hmm, that reminds me, I don't think we have any EGL or GL error
reporting in Weston... but that's a whole different story.


Thanks,
pq


> ---
>  src/compositor.c     |   47 +++++++++++++++++++++++++++++++++++++----------
>  src/compositor.h     |    2 ++
>  src/weston-egl-ext.h |    1 +
>  3 files changed, 40 insertions(+), 10 deletions(-)
> 
> diff --git a/src/compositor.c b/src/compositor.c
> index b2a3ae9..5c6782e 100644
> --- a/src/compositor.c
> +++ b/src/compositor.c
> @@ -719,14 +719,14 @@ ensure_textures(struct weston_surface *es, int num_textures)
>  
>  	for (i = es->num_textures; i < num_textures; i++) {
>  		glGenTextures(1, &es->textures[i]);
> -		glBindTexture(GL_TEXTURE_2D, es->textures[i]);
> -		glTexParameteri(GL_TEXTURE_2D,
> +		glBindTexture(es->target, es->textures[i]);
> +		glTexParameteri(es->target,
>  				GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
> -		glTexParameteri(GL_TEXTURE_2D,
> +		glTexParameteri(es->target,
>  				GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
>  	}
>  	es->num_textures = num_textures;
> -	glBindTexture(GL_TEXTURE_2D, 0);
> +	glBindTexture(es->target, 0);
>  }
>  
>  static void
> @@ -771,6 +771,7 @@ weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
>  	if (wl_buffer_is_shm(buffer)) {
>  		es->pitch = wl_shm_buffer_get_stride(buffer) / 4;
>  		es->shader = &ec->texture_shader_rgba;
> +		es->target = GL_TEXTURE_2D;
>  
>  		ensure_textures(es, 1);
>  		glBindTexture(GL_TEXTURE_2D, es->textures[0]);
> @@ -786,7 +787,7 @@ weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
>  		for (i = 0; i < es->num_images; i++)
>  			ec->destroy_image(ec->egl_display, es->images[i]);
>  		es->num_images = 0;
> -
> +		es->target = GL_TEXTURE_2D;
>  		switch (format) {
>  		case EGL_TEXTURE_RGB:
>  		case EGL_TEXTURE_RGBA:
> @@ -794,6 +795,11 @@ weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
>  			num_planes = 1;
>  			es->shader = &ec->texture_shader_rgba;
>  			break;
> +		case EGL_TEXTURE_EXTERNAL_WL:
> +			num_planes = 1;
> +			es->target = GL_TEXTURE_EXTERNAL_OES;
> +			es->shader = &ec->texture_shader_egl_external;
> +			break;
>  		case EGL_TEXTURE_Y_UV_WL:
>  			num_planes = 2;
>  			es->shader = &ec->texture_shader_y_uv;
> @@ -824,8 +830,8 @@ weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
>  			es->num_images++;
>  
>  			glActiveTexture(GL_TEXTURE0 + i);
> -			glBindTexture(GL_TEXTURE_2D, es->textures[i]);
> -			ec->image_target_texture_2d(GL_TEXTURE_2D,
> +			glBindTexture(es->target, es->textures[i]);
> +			ec->image_target_texture_2d(es->target,
>  						    es->images[i]);
>  		}
>  
> @@ -942,9 +948,9 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output,
>  	for (i = 0; i < es->num_textures; i++) {
>  		glUniform1i(es->shader->tex_uniforms[i], i);
>  		glActiveTexture(GL_TEXTURE0 + i);
> -		glBindTexture(GL_TEXTURE_2D, es->textures[i]);
> -		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
> -		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
> +		glBindTexture(es->target, es->textures[i]);
> +		glTexParameteri(es->target, GL_TEXTURE_MIN_FILTER, filter);
> +		glTexParameteri(es->target, GL_TEXTURE_MAG_FILTER, filter);
>  	}
>  
>  	v = ec->vertices.data;
> @@ -2842,6 +2848,19 @@ static const char texture_fragment_shader_rgba[] =
>  	FRAGMENT_SHADER_EXIT
>  	"}\n";
>  
> +static const char texture_fragment_shader_egl_external[] =
> +	"#extension GL_OES_EGL_image_external : require\n"
> +	"precision mediump float;\n"
> +	"varying vec2 v_texcoord;\n"
> +	"uniform samplerExternalOES tex;\n"
> +	FRAGMENT_SHADER_UNIFORMS
> +	"void main()\n"
> +	"{\n"
> +	FRAGMENT_SHADER_INIT
> +	"   gl_FragColor = texture2D(tex, v_texcoord)\n;"
> +	FRAGMENT_SHADER_EXIT
> +	"}\n";
> +
>  static const char texture_fragment_shader_y_uv[] =
>  	"precision mediump float;\n"
>  	"uniform sampler2D tex;\n"
> @@ -3193,6 +3212,7 @@ WL_EXPORT int
>  weston_compositor_init_gl(struct weston_compositor *ec)
>  {
>  	const char *extensions;
> +	int has_egl_image_external = 0;
>  
>  	log_egl_gl_info(ec->egl_display);
>  
> @@ -3228,6 +3248,9 @@ weston_compositor_init_gl(struct weston_compositor *ec)
>  	if (strstr(extensions, "GL_EXT_unpack_subimage"))
>  		ec->has_unpack_subimage = 1;
>  
> +	if (strstr(extensions, "GL_OES_EGL_image_external"))
> +		has_egl_image_external = 1;
> +
>  	extensions =
>  		(const char *) eglQueryString(ec->egl_display, EGL_EXTENSIONS);
>  	if (!extensions) {
> @@ -3251,6 +3274,10 @@ weston_compositor_init_gl(struct weston_compositor *ec)
>  	if (weston_shader_init(&ec->texture_shader_rgba,
>  			     vertex_shader, texture_fragment_shader_rgba) < 0)
>  		return -1;
> +	if (has_egl_image_external &&
> +			weston_shader_init(&ec->texture_shader_egl_external,
> +				vertex_shader, texture_fragment_shader_egl_external) < 0)
> +		return -1;
>  	if (weston_shader_init(&ec->texture_shader_y_uv,
>  			       vertex_shader, texture_fragment_shader_y_uv) < 0)
>  		return -1;
> diff --git a/src/compositor.h b/src/compositor.h
> index 22c0174..be1c2d2 100644
> --- a/src/compositor.h
> +++ b/src/compositor.h
> @@ -271,6 +271,7 @@ struct weston_compositor {
>  	EGLConfig egl_config;
>  	GLuint fbo;
>  	struct weston_shader texture_shader_rgba;
> +	struct weston_shader texture_shader_egl_external;
>  	struct weston_shader texture_shader_y_uv;
>  	struct weston_shader texture_shader_y_u_v;
>  	struct weston_shader texture_shader_y_xuxv;
> @@ -452,6 +453,7 @@ struct weston_surface {
>  	struct wl_list frame_callback_list;
>  
>  	EGLImageKHR images[3];
> +	GLenum target;
>  	int num_images;
>  
>  	struct wl_buffer *buffer;
> diff --git a/src/weston-egl-ext.h b/src/weston-egl-ext.h
> index 8e132c0..5369f02 100644
> --- a/src/weston-egl-ext.h
> +++ b/src/weston-egl-ext.h
> @@ -39,6 +39,7 @@
>  #define EGL_TEXTURE_Y_U_V_WL            0x31D7
>  #define EGL_TEXTURE_Y_UV_WL             0x31D8
>  #define EGL_TEXTURE_Y_XUXV_WL           0x31D9
> +#define EGL_TEXTURE_EXTERNAL_WL         0x31DA
>  
>  struct wl_display;
>  struct wl_buffer;
Rob Clark Aug. 17, 2012, 5:36 p.m. | #2
On Fri, Aug 17, 2012 at 1:09 AM, Pekka Paalanen <ppaalanen@gmail.com> wrote:
> On Thu, 16 Aug 2012 17:28:20 -0500
> Rob Clark <rob.clark@linaro.org> wrote:
>
>> From: Rob Clark <rob@ti.com>
>>
>> In cases where the GPU can natively handle certain YUV formats,
>> eglQueryWaylandBufferWL() can return the value EGL_TEXTURE_EXTERNAL_WL
>> and the compositor will treat the buffer as a single egl-image-external.
>>
>> See:
>> http://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image_external.txt
>>
>> v1: original
>> v2: rename EGL_TEXTURE_EXTERNAL_OES -> EGL_TEXTURE_EXTERNAL_WL and query
>>     for the extension
>>
>> Signed-off-by: Rob Clark <rob@ti.com>
>
> Looks good to me now. The only thing I could still say is that maybe it
> would be nice to log a warning, if the extension is not detected, but
> querySurface still returns EGL_TEXTURE_EXTERNAL_WL.

I was debating about putting an assert in there to make it more
explicit that query_surface should never return
EGL_TEXTURE_EXTERNAL_WL if the gl driver doesn't support
OES_EGL_image_external.  I guess it could be a warning too, although
there is nothing really sane that weston could do as a fallback

BR,
-R

> Hmm, that reminds me, I don't think we have any EGL or GL error
> reporting in Weston... but that's a whole different story.
>
>
> Thanks,
> pq
>
>
>> ---
>>  src/compositor.c     |   47 +++++++++++++++++++++++++++++++++++++----------
>>  src/compositor.h     |    2 ++
>>  src/weston-egl-ext.h |    1 +
>>  3 files changed, 40 insertions(+), 10 deletions(-)
>>
>> diff --git a/src/compositor.c b/src/compositor.c
>> index b2a3ae9..5c6782e 100644
>> --- a/src/compositor.c
>> +++ b/src/compositor.c
>> @@ -719,14 +719,14 @@ ensure_textures(struct weston_surface *es, int num_textures)
>>
>>       for (i = es->num_textures; i < num_textures; i++) {
>>               glGenTextures(1, &es->textures[i]);
>> -             glBindTexture(GL_TEXTURE_2D, es->textures[i]);
>> -             glTexParameteri(GL_TEXTURE_2D,
>> +             glBindTexture(es->target, es->textures[i]);
>> +             glTexParameteri(es->target,
>>                               GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
>> -             glTexParameteri(GL_TEXTURE_2D,
>> +             glTexParameteri(es->target,
>>                               GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
>>       }
>>       es->num_textures = num_textures;
>> -     glBindTexture(GL_TEXTURE_2D, 0);
>> +     glBindTexture(es->target, 0);
>>  }
>>
>>  static void
>> @@ -771,6 +771,7 @@ weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
>>       if (wl_buffer_is_shm(buffer)) {
>>               es->pitch = wl_shm_buffer_get_stride(buffer) / 4;
>>               es->shader = &ec->texture_shader_rgba;
>> +             es->target = GL_TEXTURE_2D;
>>
>>               ensure_textures(es, 1);
>>               glBindTexture(GL_TEXTURE_2D, es->textures[0]);
>> @@ -786,7 +787,7 @@ weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
>>               for (i = 0; i < es->num_images; i++)
>>                       ec->destroy_image(ec->egl_display, es->images[i]);
>>               es->num_images = 0;
>> -
>> +             es->target = GL_TEXTURE_2D;
>>               switch (format) {
>>               case EGL_TEXTURE_RGB:
>>               case EGL_TEXTURE_RGBA:
>> @@ -794,6 +795,11 @@ weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
>>                       num_planes = 1;
>>                       es->shader = &ec->texture_shader_rgba;
>>                       break;
>> +             case EGL_TEXTURE_EXTERNAL_WL:
>> +                     num_planes = 1;
>> +                     es->target = GL_TEXTURE_EXTERNAL_OES;
>> +                     es->shader = &ec->texture_shader_egl_external;
>> +                     break;
>>               case EGL_TEXTURE_Y_UV_WL:
>>                       num_planes = 2;
>>                       es->shader = &ec->texture_shader_y_uv;
>> @@ -824,8 +830,8 @@ weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
>>                       es->num_images++;
>>
>>                       glActiveTexture(GL_TEXTURE0 + i);
>> -                     glBindTexture(GL_TEXTURE_2D, es->textures[i]);
>> -                     ec->image_target_texture_2d(GL_TEXTURE_2D,
>> +                     glBindTexture(es->target, es->textures[i]);
>> +                     ec->image_target_texture_2d(es->target,
>>                                                   es->images[i]);
>>               }
>>
>> @@ -942,9 +948,9 @@ weston_surface_draw(struct weston_surface *es, struct weston_output *output,
>>       for (i = 0; i < es->num_textures; i++) {
>>               glUniform1i(es->shader->tex_uniforms[i], i);
>>               glActiveTexture(GL_TEXTURE0 + i);
>> -             glBindTexture(GL_TEXTURE_2D, es->textures[i]);
>> -             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
>> -             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
>> +             glBindTexture(es->target, es->textures[i]);
>> +             glTexParameteri(es->target, GL_TEXTURE_MIN_FILTER, filter);
>> +             glTexParameteri(es->target, GL_TEXTURE_MAG_FILTER, filter);
>>       }
>>
>>       v = ec->vertices.data;
>> @@ -2842,6 +2848,19 @@ static const char texture_fragment_shader_rgba[] =
>>       FRAGMENT_SHADER_EXIT
>>       "}\n";
>>
>> +static const char texture_fragment_shader_egl_external[] =
>> +     "#extension GL_OES_EGL_image_external : require\n"
>> +     "precision mediump float;\n"
>> +     "varying vec2 v_texcoord;\n"
>> +     "uniform samplerExternalOES tex;\n"
>> +     FRAGMENT_SHADER_UNIFORMS
>> +     "void main()\n"
>> +     "{\n"
>> +     FRAGMENT_SHADER_INIT
>> +     "   gl_FragColor = texture2D(tex, v_texcoord)\n;"
>> +     FRAGMENT_SHADER_EXIT
>> +     "}\n";
>> +
>>  static const char texture_fragment_shader_y_uv[] =
>>       "precision mediump float;\n"
>>       "uniform sampler2D tex;\n"
>> @@ -3193,6 +3212,7 @@ WL_EXPORT int
>>  weston_compositor_init_gl(struct weston_compositor *ec)
>>  {
>>       const char *extensions;
>> +     int has_egl_image_external = 0;
>>
>>       log_egl_gl_info(ec->egl_display);
>>
>> @@ -3228,6 +3248,9 @@ weston_compositor_init_gl(struct weston_compositor *ec)
>>       if (strstr(extensions, "GL_EXT_unpack_subimage"))
>>               ec->has_unpack_subimage = 1;
>>
>> +     if (strstr(extensions, "GL_OES_EGL_image_external"))
>> +             has_egl_image_external = 1;
>> +
>>       extensions =
>>               (const char *) eglQueryString(ec->egl_display, EGL_EXTENSIONS);
>>       if (!extensions) {
>> @@ -3251,6 +3274,10 @@ weston_compositor_init_gl(struct weston_compositor *ec)
>>       if (weston_shader_init(&ec->texture_shader_rgba,
>>                            vertex_shader, texture_fragment_shader_rgba) < 0)
>>               return -1;
>> +     if (has_egl_image_external &&
>> +                     weston_shader_init(&ec->texture_shader_egl_external,
>> +                             vertex_shader, texture_fragment_shader_egl_external) < 0)
>> +             return -1;
>>       if (weston_shader_init(&ec->texture_shader_y_uv,
>>                              vertex_shader, texture_fragment_shader_y_uv) < 0)
>>               return -1;
>> diff --git a/src/compositor.h b/src/compositor.h
>> index 22c0174..be1c2d2 100644
>> --- a/src/compositor.h
>> +++ b/src/compositor.h
>> @@ -271,6 +271,7 @@ struct weston_compositor {
>>       EGLConfig egl_config;
>>       GLuint fbo;
>>       struct weston_shader texture_shader_rgba;
>> +     struct weston_shader texture_shader_egl_external;
>>       struct weston_shader texture_shader_y_uv;
>>       struct weston_shader texture_shader_y_u_v;
>>       struct weston_shader texture_shader_y_xuxv;
>> @@ -452,6 +453,7 @@ struct weston_surface {
>>       struct wl_list frame_callback_list;
>>
>>       EGLImageKHR images[3];
>> +     GLenum target;
>>       int num_images;
>>
>>       struct wl_buffer *buffer;
>> diff --git a/src/weston-egl-ext.h b/src/weston-egl-ext.h
>> index 8e132c0..5369f02 100644
>> --- a/src/weston-egl-ext.h
>> +++ b/src/weston-egl-ext.h
>> @@ -39,6 +39,7 @@
>>  #define EGL_TEXTURE_Y_U_V_WL            0x31D7
>>  #define EGL_TEXTURE_Y_UV_WL             0x31D8
>>  #define EGL_TEXTURE_Y_XUXV_WL           0x31D9
>> +#define EGL_TEXTURE_EXTERNAL_WL         0x31DA
>>
>>  struct wl_display;
>>  struct wl_buffer;
>
> _______________________________________________
> mesa-dev mailing list
> mesa-dev@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Patch

diff --git a/src/compositor.c b/src/compositor.c
index b2a3ae9..5c6782e 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -719,14 +719,14 @@  ensure_textures(struct weston_surface *es, int num_textures)
 
 	for (i = es->num_textures; i < num_textures; i++) {
 		glGenTextures(1, &es->textures[i]);
-		glBindTexture(GL_TEXTURE_2D, es->textures[i]);
-		glTexParameteri(GL_TEXTURE_2D,
+		glBindTexture(es->target, es->textures[i]);
+		glTexParameteri(es->target,
 				GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-		glTexParameteri(GL_TEXTURE_2D,
+		glTexParameteri(es->target,
 				GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 	}
 	es->num_textures = num_textures;
-	glBindTexture(GL_TEXTURE_2D, 0);
+	glBindTexture(es->target, 0);
 }
 
 static void
@@ -771,6 +771,7 @@  weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
 	if (wl_buffer_is_shm(buffer)) {
 		es->pitch = wl_shm_buffer_get_stride(buffer) / 4;
 		es->shader = &ec->texture_shader_rgba;
+		es->target = GL_TEXTURE_2D;
 
 		ensure_textures(es, 1);
 		glBindTexture(GL_TEXTURE_2D, es->textures[0]);
@@ -786,7 +787,7 @@  weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
 		for (i = 0; i < es->num_images; i++)
 			ec->destroy_image(ec->egl_display, es->images[i]);
 		es->num_images = 0;
-
+		es->target = GL_TEXTURE_2D;
 		switch (format) {
 		case EGL_TEXTURE_RGB:
 		case EGL_TEXTURE_RGBA:
@@ -794,6 +795,11 @@  weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
 			num_planes = 1;
 			es->shader = &ec->texture_shader_rgba;
 			break;
+		case EGL_TEXTURE_EXTERNAL_WL:
+			num_planes = 1;
+			es->target = GL_TEXTURE_EXTERNAL_OES;
+			es->shader = &ec->texture_shader_egl_external;
+			break;
 		case EGL_TEXTURE_Y_UV_WL:
 			num_planes = 2;
 			es->shader = &ec->texture_shader_y_uv;
@@ -824,8 +830,8 @@  weston_surface_attach(struct wl_surface *surface, struct wl_buffer *buffer)
 			es->num_images++;
 
 			glActiveTexture(GL_TEXTURE0 + i);
-			glBindTexture(GL_TEXTURE_2D, es->textures[i]);
-			ec->image_target_texture_2d(GL_TEXTURE_2D,
+			glBindTexture(es->target, es->textures[i]);
+			ec->image_target_texture_2d(es->target,
 						    es->images[i]);
 		}
 
@@ -942,9 +948,9 @@  weston_surface_draw(struct weston_surface *es, struct weston_output *output,
 	for (i = 0; i < es->num_textures; i++) {
 		glUniform1i(es->shader->tex_uniforms[i], i);
 		glActiveTexture(GL_TEXTURE0 + i);
-		glBindTexture(GL_TEXTURE_2D, es->textures[i]);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+		glBindTexture(es->target, es->textures[i]);
+		glTexParameteri(es->target, GL_TEXTURE_MIN_FILTER, filter);
+		glTexParameteri(es->target, GL_TEXTURE_MAG_FILTER, filter);
 	}
 
 	v = ec->vertices.data;
@@ -2842,6 +2848,19 @@  static const char texture_fragment_shader_rgba[] =
 	FRAGMENT_SHADER_EXIT
 	"}\n";
 
+static const char texture_fragment_shader_egl_external[] =
+	"#extension GL_OES_EGL_image_external : require\n"
+	"precision mediump float;\n"
+	"varying vec2 v_texcoord;\n"
+	"uniform samplerExternalOES tex;\n"
+	FRAGMENT_SHADER_UNIFORMS
+	"void main()\n"
+	"{\n"
+	FRAGMENT_SHADER_INIT
+	"   gl_FragColor = texture2D(tex, v_texcoord)\n;"
+	FRAGMENT_SHADER_EXIT
+	"}\n";
+
 static const char texture_fragment_shader_y_uv[] =
 	"precision mediump float;\n"
 	"uniform sampler2D tex;\n"
@@ -3193,6 +3212,7 @@  WL_EXPORT int
 weston_compositor_init_gl(struct weston_compositor *ec)
 {
 	const char *extensions;
+	int has_egl_image_external = 0;
 
 	log_egl_gl_info(ec->egl_display);
 
@@ -3228,6 +3248,9 @@  weston_compositor_init_gl(struct weston_compositor *ec)
 	if (strstr(extensions, "GL_EXT_unpack_subimage"))
 		ec->has_unpack_subimage = 1;
 
+	if (strstr(extensions, "GL_OES_EGL_image_external"))
+		has_egl_image_external = 1;
+
 	extensions =
 		(const char *) eglQueryString(ec->egl_display, EGL_EXTENSIONS);
 	if (!extensions) {
@@ -3251,6 +3274,10 @@  weston_compositor_init_gl(struct weston_compositor *ec)
 	if (weston_shader_init(&ec->texture_shader_rgba,
 			     vertex_shader, texture_fragment_shader_rgba) < 0)
 		return -1;
+	if (has_egl_image_external &&
+			weston_shader_init(&ec->texture_shader_egl_external,
+				vertex_shader, texture_fragment_shader_egl_external) < 0)
+		return -1;
 	if (weston_shader_init(&ec->texture_shader_y_uv,
 			       vertex_shader, texture_fragment_shader_y_uv) < 0)
 		return -1;
diff --git a/src/compositor.h b/src/compositor.h
index 22c0174..be1c2d2 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -271,6 +271,7 @@  struct weston_compositor {
 	EGLConfig egl_config;
 	GLuint fbo;
 	struct weston_shader texture_shader_rgba;
+	struct weston_shader texture_shader_egl_external;
 	struct weston_shader texture_shader_y_uv;
 	struct weston_shader texture_shader_y_u_v;
 	struct weston_shader texture_shader_y_xuxv;
@@ -452,6 +453,7 @@  struct weston_surface {
 	struct wl_list frame_callback_list;
 
 	EGLImageKHR images[3];
+	GLenum target;
 	int num_images;
 
 	struct wl_buffer *buffer;
diff --git a/src/weston-egl-ext.h b/src/weston-egl-ext.h
index 8e132c0..5369f02 100644
--- a/src/weston-egl-ext.h
+++ b/src/weston-egl-ext.h
@@ -39,6 +39,7 @@ 
 #define EGL_TEXTURE_Y_U_V_WL            0x31D7
 #define EGL_TEXTURE_Y_UV_WL             0x31D8
 #define EGL_TEXTURE_Y_XUXV_WL           0x31D9
+#define EGL_TEXTURE_EXTERNAL_WL         0x31DA
 
 struct wl_display;
 struct wl_buffer;