<div dir="ltr">The code looks good, but I have one question: why? What's the motivation for adding a generic shader generator? Does this fix any bugs? Add new hardware support? Do you have new features lined up that rely on this?<br>
<br>I always found that debugging generated shaders was fairly difficult and annoying, and while the old code isn't great, I find it's a lot simple to understand.<br></div><div class="gmail_extra"><br><br><div class="gmail_quote">
On Tue, Apr 8, 2014 at 3:26 PM, John Kåre Alsaker <span dir="ltr"><<a href="mailto:john.kare.alsaker@gmail.com" target="_blank">john.kare.alsaker@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
This add a more flexible way of generating shaders. It generates all valid<br>
combinations of different input, conversion and output pipelines, which<br>
can easily be extended with more if desired. It adds gl-internal.h for<br>
shared definitions between the gl-renderer.c and gl-shaders.c.<br>
---<br>
 Makefile.am       |   2 +<br>
 src/gl-internal.h | 238 ++++++++++++++++++++++<br>
 src/gl-renderer.c | 512 +++++-----------------------------------------<br>
 src/gl-shaders.c  | 596 ++++++++++++++++++++++++++++++++++++++++++++++++++++++<br>
 4 files changed, 881 insertions(+), 467 deletions(-)<br>
 create mode 100644 src/gl-internal.h<br>
 create mode 100644 src/gl-shaders.c<br>
<br>
diff --git a/Makefile.am b/Makefile.am<br>
index a247c3d..8952d1a 100644<br>
--- a/Makefile.am<br>
+++ b/Makefile.am<br>
@@ -158,6 +158,8 @@ gl_renderer_la_CFLAGS =                             \<br>
        $(EGL_CFLAGS)                           \<br>
        $(GCC_CFLAGS)<br>
 gl_renderer_la_SOURCES =                       \<br>
+       src/gl-shaders.c                        \<br>
+       src/gl-internal.h                       \<br>
        src/gl-renderer.h                       \<br>
        src/gl-renderer.c                       \<br>
        src/vertex-clipping.c                   \<br>
diff --git a/src/gl-internal.h b/src/gl-internal.h<br>
new file mode 100644<br>
index 0000000..15f8c8a<br>
--- /dev/null<br>
+++ b/src/gl-internal.h<br>
@@ -0,0 +1,238 @@<br>
+/*<br>
+ * Copyright © 2012 Intel Corporation<br>
+ * Copyright © 2012 John Kåre Alsaker<br>
+ *<br>
+ * Permission to use, copy, modify, distribute, and sell this software and<br>
+ * its documentation for any purpose is hereby granted without fee, provided<br>
+ * that the above copyright notice appear in all copies and that both that<br>
+ * copyright notice and this permission notice appear in supporting<br>
+ * documentation, and that the name of the copyright holders not be used in<br>
+ * advertising or publicity pertaining to distribution of the software<br>
+ * without specific, written prior permission.  The copyright holders make<br>
+ * no representations about the suitability of this software for any<br>
+ * purpose.  It is provided "as is" without express or implied warranty.<br>
+ *<br>
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS<br>
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND<br>
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY<br>
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER<br>
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF<br>
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN<br>
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.<br>
+ */<br>
+<br>
+#ifndef _GL_INTERNAL_H_<br>
+#define _GL_INTERNAL_H_<br>
+<br>
+#include "config.h"<br>
+<br>
+#include <GLES2/gl2.h><br>
+#include <GLES2/gl2ext.h><br>
+<br>
+#include <stdlib.h><br>
+#include <string.h><br>
+#include <ctype.h><br>
+#include <float.h><br>
+#include <assert.h><br>
+#include <linux/input.h><br>
+<br>
+#include "gl-renderer.h"<br>
+#include "vertex-clipping.h"<br>
+<br>
+#include <EGL/eglext.h><br>
+#include "weston-egl-ext.h"<br>
+<br>
+#define MAX_PLANES 3<br>
+<br>
+enum gl_shader_attribute {<br>
+       ATTRIBUTE_INPUT,<br>
+       ATTRIBUTE_OUTPUT,<br>
+       ATTRIBUTE_CONVERSION,<br>
+       ATTRIBUTE_COUNT<br>
+};<br>
+<br>
+enum gl_conversion_attribute {<br>
+       CONVERSION_NONE,<br>
+       CONVERSION_COUNT<br>
+};<br>
+<br>
+enum gl_output_attribute {<br>
+       OUTPUT_BLEND,<br>
+       OUTPUT_COUNT<br>
+};<br>
+<br>
+enum gl_input_attribute {<br>
+       INPUT_RGBX,<br>
+       INPUT_RGBA,<br>
+       INPUT_EGL_EXTERNAL,<br>
+       INPUT_Y_UV,<br>
+       INPUT_Y_U_V,<br>
+       INPUT_Y_XUXV,<br>
+       INPUT_SOLID,<br>
+       INPUT_COUNT<br>
+};<br>
+<br>
+struct gl_shader {<br>
+       GLuint program;<br>
+       GLint projection_uniform;<br>
+       GLint color_uniform;<br>
+       GLint alpha_uniform;<br>
+};<br>
+<br>
+#define BUFFER_DAMAGE_COUNT 2<br>
+<br>
+enum gl_border_status {<br>
+       BORDER_STATUS_CLEAN = 0,<br>
+       BORDER_TOP_DIRTY = 1 << GL_RENDERER_BORDER_TOP,<br>
+       BORDER_LEFT_DIRTY = 1 << GL_RENDERER_BORDER_LEFT,<br>
+       BORDER_RIGHT_DIRTY = 1 << GL_RENDERER_BORDER_RIGHT,<br>
+       BORDER_BOTTOM_DIRTY = 1 << GL_RENDERER_BORDER_BOTTOM,<br>
+       BORDER_ALL_DIRTY = 0xf,<br>
+       BORDER_SIZE_CHANGED = 0x10<br>
+};<br>
+<br>
+struct gl_border_image {<br>
+       GLuint tex;<br>
+       int32_t width, height;<br>
+       int32_t tex_width;<br>
+       void *data;<br>
+};<br>
+<br>
+struct gl_output_state {<br>
+       EGLSurface egl_surface;<br>
+       pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];<br>
+       enum gl_border_status border_damage[BUFFER_DAMAGE_COUNT];<br>
+       struct gl_border_image borders[4];<br>
+       enum gl_border_status border_status;<br>
+};<br>
+<br>
+enum buffer_type {<br>
+       BUFFER_TYPE_NULL,<br>
+       BUFFER_TYPE_SHM,<br>
+       BUFFER_TYPE_EGL<br>
+};<br>
+<br>
+struct gl_surface_state {<br>
+       GLfloat color[4];<br>
+       enum gl_input_attribute input;<br>
+<br>
+       GLuint textures[MAX_PLANES];<br>
+       int num_textures;<br>
+       int needs_full_upload;<br>
+       pixman_region32_t texture_damage;<br>
+<br>
+       /* These are only used by SHM surfaces to detect when we need<br>
+        * to do a full upload to specify a new internal texture<br>
+        * format */<br>
+       GLenum gl_format;<br>
+       GLenum gl_pixel_type;<br>
+<br>
+       EGLImageKHR images[MAX_PLANES];<br>
+       GLenum target;<br>
+       int num_images;<br>
+<br>
+       struct weston_buffer_reference buffer_ref;<br>
+       enum buffer_type buffer_type;<br>
+       int pitch; /* in pixels */<br>
+       int height; /* in pixels */<br>
+       int y_inverted;<br>
+<br>
+       struct weston_surface *surface;<br>
+<br>
+       struct wl_listener surface_destroy_listener;<br>
+       struct wl_listener renderer_destroy_listener;<br>
+};<br>
+<br>
+struct gl_renderer {<br>
+       struct weston_renderer base;<br>
+       int fragment_shader_debug;<br>
+       int fan_debug;<br>
+       struct weston_binding *fragment_binding;<br>
+       struct weston_binding *fan_binding;<br>
+<br>
+       EGLDisplay egl_display;<br>
+       EGLContext egl_context;<br>
+       EGLConfig egl_config;<br>
+<br>
+       struct wl_array vertices;<br>
+       struct wl_array vtxcnt;<br>
+<br>
+       PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;<br>
+       PFNEGLCREATEIMAGEKHRPROC create_image;<br>
+       PFNEGLDESTROYIMAGEKHRPROC destroy_image;<br>
+<br>
+#ifdef EGL_EXT_swap_buffers_with_damage<br>
+       PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;<br>
+#endif<br>
+<br>
+       int has_unpack_subimage;<br>
+<br>
+       PFNEGLBINDWAYLANDDISPLAYWL bind_display;<br>
+       PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;<br>
+       PFNEGLQUERYWAYLANDBUFFERWL query_buffer;<br>
+       int has_bind_display;<br>
+<br>
+       int has_egl_image_external;<br>
+<br>
+       int has_egl_buffer_age;<br>
+<br>
+       int has_configless_context;<br>
+<br>
+       struct gl_shader *solid_shader;<br>
+       struct gl_shader *current_shader;<br>
+<br>
+       struct gl_shader **shaders;<br>
+       size_t shader_count;<br>
+<br>
+       struct wl_signal destroy_signal;<br>
+};<br>
+<br>
+static inline struct gl_output_state *<br>
+get_output_state(struct weston_output *output)<br>
+{<br>
+       return (struct gl_output_state *)output->renderer_state;<br>
+}<br>
+<br>
+int<br>
+gl_renderer_create_surface(struct weston_surface *surface);<br>
+<br>
+static inline struct gl_surface_state *<br>
+get_surface_state(struct weston_surface *surface)<br>
+{<br>
+       if (!surface->renderer_state)<br>
+               gl_renderer_create_surface(surface);<br>
+<br>
+       return (struct gl_surface_state *)surface->renderer_state;<br>
+}<br>
+<br>
+static inline struct gl_renderer *<br>
+get_renderer(struct weston_compositor *ec)<br>
+{<br>
+       return (struct gl_renderer *)ec->renderer;<br>
+}<br>
+<br>
+int<br>
+gl_init_shaders(struct gl_renderer *gr);<br>
+<br>
+void<br>
+gl_destroy_shaders(struct gl_renderer *gr);<br>
+<br>
+void<br>
+gl_shader_set_matrix(struct gl_shader *shader,<br>
+                    struct weston_matrix *matrix);<br>
+<br>
+void<br>
+gl_use_shader(struct gl_renderer *gr,<br>
+                            struct gl_shader *shader);<br>
+<br>
+struct gl_shader *<br>
+gl_select_shader(struct gl_renderer *gr,<br>
+                       enum gl_input_attribute input,<br>
+                       enum gl_output_attribute output);<br>
+<br>
+void<br>
+gl_shader_setup(struct gl_shader *shader,<br>
+                      struct weston_view *view,<br>
+                      struct weston_output *output);<br>
+<br>
+#endif<br>
diff --git a/src/gl-renderer.c b/src/gl-renderer.c<br>
index 63af75d..8064ed6 100644<br>
--- a/src/gl-renderer.c<br>
+++ b/src/gl-renderer.c<br>
@@ -1,5 +1,6 @@<br>
 /*<br>
  * Copyright © 2012 Intel Corporation<br>
+ * Copyright © 2012 John Kåre Alsaker<br>
  *<br>
  * Permission to use, copy, modify, distribute, and sell this software and<br>
  * its documentation for any purpose is hereby granted without fee, provided<br>
@@ -20,169 +21,7 @@<br>
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.<br>
  */<br>
<br>
-#include "config.h"<br>
-<br>
-#include <GLES2/gl2.h><br>
-#include <GLES2/gl2ext.h><br>
-<br>
-#include <stdlib.h><br>
-#include <string.h><br>
-#include <ctype.h><br>
-#include <float.h><br>
-#include <assert.h><br>
-#include <linux/input.h><br>
-<br>
-#include "gl-renderer.h"<br>
-#include "vertex-clipping.h"<br>
-<br>
-#include <EGL/eglext.h><br>
-#include "weston-egl-ext.h"<br>
-<br>
-struct gl_shader {<br>
-       GLuint program;<br>
-       GLuint vertex_shader, fragment_shader;<br>
-       GLint proj_uniform;<br>
-       GLint tex_uniforms[3];<br>
-       GLint alpha_uniform;<br>
-       GLint color_uniform;<br>
-       const char *vertex_source, *fragment_source;<br>
-};<br>
-<br>
-#define BUFFER_DAMAGE_COUNT 2<br>
-<br>
-enum gl_border_status {<br>
-       BORDER_STATUS_CLEAN = 0,<br>
-       BORDER_TOP_DIRTY = 1 << GL_RENDERER_BORDER_TOP,<br>
-       BORDER_LEFT_DIRTY = 1 << GL_RENDERER_BORDER_LEFT,<br>
-       BORDER_RIGHT_DIRTY = 1 << GL_RENDERER_BORDER_RIGHT,<br>
-       BORDER_BOTTOM_DIRTY = 1 << GL_RENDERER_BORDER_BOTTOM,<br>
-       BORDER_ALL_DIRTY = 0xf,<br>
-       BORDER_SIZE_CHANGED = 0x10<br>
-};<br>
-<br>
-struct gl_border_image {<br>
-       GLuint tex;<br>
-       int32_t width, height;<br>
-       int32_t tex_width;<br>
-       void *data;<br>
-};<br>
-<br>
-struct gl_output_state {<br>
-       EGLSurface egl_surface;<br>
-       pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];<br>
-       enum gl_border_status border_damage[BUFFER_DAMAGE_COUNT];<br>
-       struct gl_border_image borders[4];<br>
-       enum gl_border_status border_status;<br>
-};<br>
-<br>
-enum buffer_type {<br>
-       BUFFER_TYPE_NULL,<br>
-       BUFFER_TYPE_SHM,<br>
-       BUFFER_TYPE_EGL<br>
-};<br>
-<br>
-struct gl_surface_state {<br>
-       GLfloat color[4];<br>
-       struct gl_shader *shader;<br>
-<br>
-       GLuint textures[3];<br>
-       int num_textures;<br>
-       int needs_full_upload;<br>
-       pixman_region32_t texture_damage;<br>
-<br>
-       /* These are only used by SHM surfaces to detect when we need<br>
-        * to do a full upload to specify a new internal texture<br>
-        * format */<br>
-       GLenum gl_format;<br>
-       GLenum gl_pixel_type;<br>
-<br>
-       EGLImageKHR images[3];<br>
-       GLenum target;<br>
-       int num_images;<br>
-<br>
-       struct weston_buffer_reference buffer_ref;<br>
-       enum buffer_type buffer_type;<br>
-       int pitch; /* in pixels */<br>
-       int height; /* in pixels */<br>
-       int y_inverted;<br>
-<br>
-       struct weston_surface *surface;<br>
-<br>
-       struct wl_listener surface_destroy_listener;<br>
-       struct wl_listener renderer_destroy_listener;<br>
-};<br>
-<br>
-struct gl_renderer {<br>
-       struct weston_renderer base;<br>
-       int fragment_shader_debug;<br>
-       int fan_debug;<br>
-       struct weston_binding *fragment_binding;<br>
-       struct weston_binding *fan_binding;<br>
-<br>
-       EGLDisplay egl_display;<br>
-       EGLContext egl_context;<br>
-       EGLConfig egl_config;<br>
-<br>
-       struct wl_array vertices;<br>
-       struct wl_array vtxcnt;<br>
-<br>
-       PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;<br>
-       PFNEGLCREATEIMAGEKHRPROC create_image;<br>
-       PFNEGLDESTROYIMAGEKHRPROC destroy_image;<br>
-<br>
-#ifdef EGL_EXT_swap_buffers_with_damage<br>
-       PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;<br>
-#endif<br>
-<br>
-       int has_unpack_subimage;<br>
-<br>
-       PFNEGLBINDWAYLANDDISPLAYWL bind_display;<br>
-       PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;<br>
-       PFNEGLQUERYWAYLANDBUFFERWL query_buffer;<br>
-       int has_bind_display;<br>
-<br>
-       int has_egl_image_external;<br>
-<br>
-       int has_egl_buffer_age;<br>
-<br>
-       int has_configless_context;<br>
-<br>
-       struct gl_shader texture_shader_rgba;<br>
-       struct gl_shader texture_shader_rgbx;<br>
-       struct gl_shader texture_shader_egl_external;<br>
-       struct gl_shader texture_shader_y_uv;<br>
-       struct gl_shader texture_shader_y_u_v;<br>
-       struct gl_shader texture_shader_y_xuxv;<br>
-       struct gl_shader invert_color_shader;<br>
-       struct gl_shader solid_shader;<br>
-       struct gl_shader *current_shader;<br>
-<br>
-       struct wl_signal destroy_signal;<br>
-};<br>
-<br>
-static inline struct gl_output_state *<br>
-get_output_state(struct weston_output *output)<br>
-{<br>
-       return (struct gl_output_state *)output->renderer_state;<br>
-}<br>
-<br>
-static int<br>
-gl_renderer_create_surface(struct weston_surface *surface);<br>
-<br>
-static inline struct gl_surface_state *<br>
-get_surface_state(struct weston_surface *surface)<br>
-{<br>
-       if (!surface->renderer_state)<br>
-               gl_renderer_create_surface(surface);<br>
-<br>
-       return (struct gl_surface_state *)surface->renderer_state;<br>
-}<br>
-<br>
-static inline struct gl_renderer *<br>
-get_renderer(struct weston_compositor *ec)<br>
-{<br>
-       return (struct gl_renderer *)ec->renderer;<br>
-}<br>
+#include "gl-internal.h"<br>
<br>
 static const char *<br>
 egl_error_string(EGLint code)<br>
@@ -403,8 +242,8 @@ triangle_fan_debug(struct weston_view *view, int first, int count)<br>
                *index++ = first + i;<br>
        }<br>
<br>
-       glUseProgram(gr->solid_shader.program);<br>
-       glUniform4fv(gr->solid_shader.color_uniform, 1,<br>
+       glUseProgram(gr->solid_shader->program);<br>
+       glUniform4fv(gr->solid_shader->color_uniform, 1,<br>
                        color[color_idx++ % ARRAY_LENGTH(color)]);<br>
        glDrawElements(GL_LINES, nelems, GL_UNSIGNED_SHORT, buffer);<br>
        glUseProgram(gr->current_shader->program);<br>
@@ -479,47 +318,6 @@ use_output(struct weston_output *output)<br>
        return 0;<br>
 }<br>
<br>
-static int<br>
-shader_init(struct gl_shader *shader, struct gl_renderer *gr,<br>
-                  const char *vertex_source, const char *fragment_source);<br>
-<br>
-static void<br>
-use_shader(struct gl_renderer *gr, struct gl_shader *shader)<br>
-{<br>
-       if (!shader->program) {<br>
-               int ret;<br>
-<br>
-               ret =  shader_init(shader, gr,<br>
-                                  shader->vertex_source,<br>
-                                  shader->fragment_source);<br>
-<br>
-               if (ret < 0)<br>
-                       weston_log("warning: failed to compile shader\n");<br>
-       }<br>
-<br>
-       if (gr->current_shader == shader)<br>
-               return;<br>
-       glUseProgram(shader->program);<br>
-       gr->current_shader = shader;<br>
-}<br>
-<br>
-static void<br>
-shader_uniforms(struct gl_shader *shader,<br>
-               struct weston_view *view,<br>
-               struct weston_output *output)<br>
-{<br>
-       int i;<br>
-       struct gl_surface_state *gs = get_surface_state(view->surface);<br>
-<br>
-       glUniformMatrix4fv(shader->proj_uniform,<br>
-                          1, GL_FALSE, output->matrix.d);<br>
-       glUniform4fv(shader->color_uniform, 1, gs->color);<br>
-       glUniform1f(shader->alpha_uniform, view->alpha);<br>
-<br>
-       for (i = 0; i < gs->num_textures; i++)<br>
-               glUniform1i(shader->tex_uniforms[i], i);<br>
-}<br>
-<br>
 static void<br>
 draw_view(struct weston_view *ev, struct weston_output *output,<br>
          pixman_region32_t *damage) /* in global coordinates */<br>
@@ -527,6 +325,7 @@ draw_view(struct weston_view *ev, struct weston_output *output,<br>
        struct weston_compositor *ec = ev->surface->compositor;<br>
        struct gl_renderer *gr = get_renderer(ec);<br>
        struct gl_surface_state *gs = get_surface_state(ev->surface);<br>
+       struct gl_shader *shader;<br>
        /* repaint bounding region in global coordinates: */<br>
        pixman_region32_t repaint;<br>
        /* non-opaque region in surface coordinates: */<br>
@@ -537,7 +336,7 @@ draw_view(struct weston_view *ev, struct weston_output *output,<br>
        /* In case of a runtime switch of renderers, we may not have received<br>
         * an attach for this surface since the switch. In that case we don't<br>
         * have a valid buffer or a proper shader set up so skip rendering. */<br>
-       if (!gs->shader)<br>
+       if (gs->buffer_type == BUFFER_TYPE_NULL)<br>
                return;<br>
<br>
        pixman_region32_init(&repaint);<br>
@@ -551,12 +350,14 @@ draw_view(struct weston_view *ev, struct weston_output *output,<br>
        glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);<br>
<br>
        if (gr->fan_debug) {<br>
-               use_shader(gr, &gr->solid_shader);<br>
-               shader_uniforms(&gr->solid_shader, ev, output);<br>
+               gl_use_shader(gr, gr->solid_shader);<br>
+               gl_shader_setup(gr->solid_shader, ev, output);<br>
        }<br>
<br>
-       use_shader(gr, gs->shader);<br>
-       shader_uniforms(gs->shader, ev, output);<br>
+       shader = gl_select_shader(gr, gs->input, OUTPUT_BLEND);<br>
+<br>
+       gl_use_shader(gr, shader);<br>
+       gl_shader_setup(shader, ev, output);<br>
<br>
        if (ev->transform.enabled || output->zoom.active ||<br>
            output->current_scale != ev->surface->buffer_viewport.buffer.scale)<br>
@@ -578,14 +379,15 @@ draw_view(struct weston_view *ev, struct weston_output *output,<br>
<br>
        /* XXX: Should we be using ev->transform.opaque here? */<br>
        if (pixman_region32_not_empty(&ev->surface->opaque)) {<br>
-               if (gs->shader == &gr->texture_shader_rgba) {<br>
+               if (gs->input == INPUT_RGBA) {<br>
                        /* Special case for RGBA textures with possibly<br>
                         * bad data in alpha channel: use the shader<br>
                         * that forces texture alpha = 1.0.<br>
                         * Xwayland surfaces need this.<br>
                         */<br>
-                       use_shader(gr, &gr->texture_shader_rgbx);<br>
-                       shader_uniforms(&gr->texture_shader_rgbx, ev, output);<br>
+                       struct gl_shader *rgbx_shader = gl_select_shader(gr, INPUT_RGBX, OUTPUT_BLEND);<br>
+                       gl_use_shader(gr, rgbx_shader);<br>
+                       gl_shader_setup(rgbx_shader, ev, output);<br>
                }<br>
<br>
                if (ev->alpha < 1.0)<br>
@@ -597,7 +399,7 @@ draw_view(struct weston_view *ev, struct weston_output *output,<br>
        }<br>
<br>
        if (pixman_region32_not_empty(&surface_blend)) {<br>
-               use_shader(gr, gs->shader);<br>
+               gl_use_shader(gr, shader);<br>
                glEnable(GL_BLEND);<br>
                repaint_region(ev, &repaint, &surface_blend);<br>
        }<br>
@@ -706,7 +508,7 @@ draw_output_borders(struct weston_output *output,<br>
 {<br>
        struct gl_output_state *go = get_output_state(output);<br>
        struct gl_renderer *gr = get_renderer(output->compositor);<br>
-       struct gl_shader *shader = &gr->texture_shader_rgba;<br>
+       struct gl_shader *shader;<br>
        struct gl_border_image *top, *bottom, *left, *right;<br>
        struct weston_matrix matrix;<br>
        int full_width, full_height;<br>
@@ -714,6 +516,8 @@ draw_output_borders(struct weston_output *output,<br>
        if (border_status == BORDER_STATUS_CLEAN)<br>
                return; /* Clean. Nothing to do. */<br>
<br>
+       shader = gl_select_shader(gr, INPUT_RGBA, OUTPUT_BLEND);<br>
+<br>
        top = &go->borders[GL_RENDERER_BORDER_TOP];<br>
        bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];<br>
        left = &go->borders[GL_RENDERER_BORDER_LEFT];<br>
@@ -722,17 +526,18 @@ draw_output_borders(struct weston_output *output,<br>
        full_width = output->current_mode->width + left->width + right->width;<br>
        full_height = output->current_mode->height + top->height + bottom->height;<br>
<br>
+       shader = gl_select_shader(gr, INPUT_RGBA, OUTPUT_BLEND);<br>
+<br>
        glDisable(GL_BLEND);<br>
-       use_shader(gr, shader);<br>
+       gl_use_shader(gr, shader);<br>
<br>
        glViewport(0, 0, full_width, full_height);<br>
<br>
        weston_matrix_init(&matrix);<br>
        weston_matrix_translate(&matrix, -full_width/2.0, -full_height/2.0, 0);<br>
        weston_matrix_scale(&matrix, 2.0/full_width, -2.0/full_height, 1);<br>
-       glUniformMatrix4fv(shader->proj_uniform, 1, GL_FALSE, matrix.d);<br>
+       gl_shader_set_matrix(shader, &matrix);<br>
<br>
-       glUniform1i(shader->tex_uniforms[0], 0);<br>
        glUniform1f(shader->alpha_uniform, 1);<br>
        glActiveTexture(GL_TEXTURE0);<br>
<br>
@@ -1124,19 +929,19 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,<br>
<br>
        switch (wl_shm_buffer_get_format(shm_buffer)) {<br>
        case WL_SHM_FORMAT_XRGB8888:<br>
-               gs->shader = &gr->texture_shader_rgbx;<br>
+               gs->input = INPUT_RGBX;<br>
                pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;<br>
                gl_format = GL_BGRA_EXT;<br>
                gl_pixel_type = GL_UNSIGNED_BYTE;<br>
                break;<br>
        case WL_SHM_FORMAT_ARGB8888:<br>
-               gs->shader = &gr->texture_shader_rgba;<br>
+               gs->input = INPUT_RGBA;<br>
                pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;<br>
                gl_format = GL_BGRA_EXT;<br>
                gl_pixel_type = GL_UNSIGNED_BYTE;<br>
                break;<br>
        case WL_SHM_FORMAT_RGB565:<br>
-               gs->shader = &gr->texture_shader_rgbx;<br>
+               gs->input = INPUT_RGBX;<br>
                pitch = wl_shm_buffer_get_stride(shm_buffer) / 2;<br>
                gl_format = GL_RGB;<br>
                gl_pixel_type = GL_UNSIGNED_SHORT_5_6_5;<br>
@@ -1194,30 +999,35 @@ gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,<br>
        gs->target = GL_TEXTURE_2D;<br>
        switch (format) {<br>
        case EGL_TEXTURE_RGB:<br>
+               num_planes = 1;<br>
+               gs->input = INPUT_RGBX;<br>
+               break;<br>
        case EGL_TEXTURE_RGBA:<br>
        default:<br>
                num_planes = 1;<br>
-               gs->shader = &gr->texture_shader_rgba;<br>
+               gs->input = INPUT_RGBA;<br>
                break;<br>
        case EGL_TEXTURE_EXTERNAL_WL:<br>
                num_planes = 1;<br>
                gs->target = GL_TEXTURE_EXTERNAL_OES;<br>
-               gs->shader = &gr->texture_shader_egl_external;<br>
+               gs->input = INPUT_EGL_EXTERNAL;<br>
                break;<br>
        case EGL_TEXTURE_Y_UV_WL:<br>
                num_planes = 2;<br>
-               gs->shader = &gr->texture_shader_y_uv;<br>
+               gs->input = INPUT_Y_UV;<br>
                break;<br>
        case EGL_TEXTURE_Y_U_V_WL:<br>
                num_planes = 3;<br>
-               gs->shader = &gr->texture_shader_y_u_v;<br>
+               gs->input = INPUT_Y_U_V;<br>
                break;<br>
        case EGL_TEXTURE_Y_XUXV_WL:<br>
                num_planes = 2;<br>
-               gs->shader = &gr->texture_shader_y_xuxv;<br>
+               gs->input = INPUT_Y_XUXV;<br>
                break;<br>
        }<br>
<br>
+       assert(num_planes <= MAX_PLANES);<br>
+<br>
        ensure_textures(gs, num_planes);<br>
        for (i = 0; i < num_planes; i++) {<br>
                attribs[0] = EGL_WAYLAND_PLANE_WL;<br>
@@ -1291,14 +1101,13 @@ gl_renderer_surface_set_color(struct weston_surface *surface,<br>
                 float red, float green, float blue, float alpha)<br>
 {<br>
        struct gl_surface_state *gs = get_surface_state(surface);<br>
-       struct gl_renderer *gr = get_renderer(surface->compositor);<br>
<br>
        gs->color[0] = red;<br>
        gs->color[1] = green;<br>
        gs->color[2] = blue;<br>
        gs->color[3] = alpha;<br>
<br>
-       gs->shader = &gr->solid_shader;<br>
+       gs->input = INPUT_SOLID;<br>
 }<br>
<br>
 static void<br>
@@ -1349,7 +1158,7 @@ surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)<br>
        surface_state_destroy(gs, gr);<br>
 }<br>
<br>
-static int<br>
+int<br>
 gl_renderer_create_surface(struct weston_surface *surface)<br>
 {<br>
        struct gl_surface_state *gs;<br>
@@ -1389,196 +1198,6 @@ gl_renderer_create_surface(struct weston_surface *surface)<br>
        return 0;<br>
 }<br>
<br>
-static const char vertex_shader[] =<br>
-       "uniform mat4 proj;\n"<br>
-       "attribute vec2 position;\n"<br>
-       "attribute vec2 texcoord;\n"<br>
-       "varying vec2 v_texcoord;\n"<br>
-       "void main()\n"<br>
-       "{\n"<br>
-       "   gl_Position = proj * vec4(position, 0.0, 1.0);\n"<br>
-       "   v_texcoord = texcoord;\n"<br>
-       "}\n";<br>
-<br>
-/* Declare common fragment shader uniforms */<br>
-#define FRAGMENT_CONVERT_YUV                                           \<br>
-       "  y *= alpha;\n"                                               \<br>
-       "  u *= alpha;\n"                                               \<br>
-       "  v *= alpha;\n"                                               \<br>
-       "  gl_FragColor.r = y + 1.59602678 * v;\n"                      \<br>
-       "  gl_FragColor.g = y - 0.39176229 * u - 0.81296764 * v;\n"     \<br>
-       "  gl_FragColor.b = y + 2.01723214 * u;\n"                      \<br>
-       "  gl_FragColor.a = alpha;\n"<br>
-<br>
-static const char fragment_debug[] =<br>
-       "  gl_FragColor = vec4(0.0, 0.3, 0.0, 0.2) + gl_FragColor * 0.8;\n";<br>
-<br>
-static const char fragment_brace[] =<br>
-       "}\n";<br>
-<br>
-static const char texture_fragment_shader_rgba[] =<br>
-       "precision mediump float;\n"<br>
-       "varying vec2 v_texcoord;\n"<br>
-       "uniform sampler2D tex;\n"<br>
-       "uniform float alpha;\n"<br>
-       "void main()\n"<br>
-       "{\n"<br>
-       "   gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"<br>
-       ;<br>
-<br>
-static const char texture_fragment_shader_rgbx[] =<br>
-       "precision mediump float;\n"<br>
-       "varying vec2 v_texcoord;\n"<br>
-       "uniform sampler2D tex;\n"<br>
-       "uniform float alpha;\n"<br>
-       "void main()\n"<br>
-       "{\n"<br>
-       "   gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb\n;"<br>
-       "   gl_FragColor.a = alpha;\n"<br>
-       ;<br>
-<br>
-static const char texture_fragment_shader_egl_external[] =<br>
-       "#extension GL_OES_EGL_image_external : require\n"<br>
-       "precision mediump float;\n"<br>
-       "varying vec2 v_texcoord;\n"<br>
-       "uniform samplerExternalOES tex;\n"<br>
-       "uniform float alpha;\n"<br>
-       "void main()\n"<br>
-       "{\n"<br>
-       "   gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"<br>
-       ;<br>
-<br>
-static const char texture_fragment_shader_y_uv[] =<br>
-       "precision mediump float;\n"<br>
-       "uniform sampler2D tex;\n"<br>
-       "uniform sampler2D tex1;\n"<br>
-       "varying vec2 v_texcoord;\n"<br>
-       "uniform float alpha;\n"<br>
-       "void main() {\n"<br>
-       "  float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"<br>
-       "  float u = texture2D(tex1, v_texcoord).r - 0.5;\n"<br>
-       "  float v = texture2D(tex1, v_texcoord).g - 0.5;\n"<br>
-       FRAGMENT_CONVERT_YUV<br>
-       ;<br>
-<br>
-static const char texture_fragment_shader_y_u_v[] =<br>
-       "precision mediump float;\n"<br>
-       "uniform sampler2D tex;\n"<br>
-       "uniform sampler2D tex1;\n"<br>
-       "uniform sampler2D tex2;\n"<br>
-       "varying vec2 v_texcoord;\n"<br>
-       "uniform float alpha;\n"<br>
-       "void main() {\n"<br>
-       "  float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"<br>
-       "  float u = texture2D(tex1, v_texcoord).x - 0.5;\n"<br>
-       "  float v = texture2D(tex2, v_texcoord).x - 0.5;\n"<br>
-       FRAGMENT_CONVERT_YUV<br>
-       ;<br>
-<br>
-static const char texture_fragment_shader_y_xuxv[] =<br>
-       "precision mediump float;\n"<br>
-       "uniform sampler2D tex;\n"<br>
-       "uniform sampler2D tex1;\n"<br>
-       "varying vec2 v_texcoord;\n"<br>
-       "uniform float alpha;\n"<br>
-       "void main() {\n"<br>
-       "  float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"<br>
-       "  float u = texture2D(tex1, v_texcoord).g - 0.5;\n"<br>
-       "  float v = texture2D(tex1, v_texcoord).a - 0.5;\n"<br>
-       FRAGMENT_CONVERT_YUV<br>
-       ;<br>
-<br>
-static const char solid_fragment_shader[] =<br>
-       "precision mediump float;\n"<br>
-       "uniform vec4 color;\n"<br>
-       "uniform float alpha;\n"<br>
-       "void main()\n"<br>
-       "{\n"<br>
-       "   gl_FragColor = alpha * color\n;"<br>
-       ;<br>
-<br>
-static int<br>
-compile_shader(GLenum type, int count, const char **sources)<br>
-{<br>
-       GLuint s;<br>
-       char msg[512];<br>
-       GLint status;<br>
-<br>
-       s = glCreateShader(type);<br>
-       glShaderSource(s, count, sources, NULL);<br>
-       glCompileShader(s);<br>
-       glGetShaderiv(s, GL_COMPILE_STATUS, &status);<br>
-       if (!status) {<br>
-               glGetShaderInfoLog(s, sizeof msg, NULL, msg);<br>
-               weston_log("shader info: %s\n", msg);<br>
-               return GL_NONE;<br>
-       }<br>
-<br>
-       return s;<br>
-}<br>
-<br>
-static int<br>
-shader_init(struct gl_shader *shader, struct gl_renderer *renderer,<br>
-                  const char *vertex_source, const char *fragment_source)<br>
-{<br>
-       char msg[512];<br>
-       GLint status;<br>
-       int count;<br>
-       const char *sources[3];<br>
-<br>
-       shader->vertex_shader =<br>
-               compile_shader(GL_VERTEX_SHADER, 1, &vertex_source);<br>
-<br>
-       if (renderer->fragment_shader_debug) {<br>
-               sources[0] = fragment_source;<br>
-               sources[1] = fragment_debug;<br>
-               sources[2] = fragment_brace;<br>
-               count = 3;<br>
-       } else {<br>
-               sources[0] = fragment_source;<br>
-               sources[1] = fragment_brace;<br>
-               count = 2;<br>
-       }<br>
-<br>
-       shader->fragment_shader =<br>
-               compile_shader(GL_FRAGMENT_SHADER, count, sources);<br>
-<br>
-       shader->program = glCreateProgram();<br>
-       glAttachShader(shader->program, shader->vertex_shader);<br>
-       glAttachShader(shader->program, shader->fragment_shader);<br>
-       glBindAttribLocation(shader->program, 0, "position");<br>
-       glBindAttribLocation(shader->program, 1, "texcoord");<br>
-<br>
-       glLinkProgram(shader->program);<br>
-       glGetProgramiv(shader->program, GL_LINK_STATUS, &status);<br>
-       if (!status) {<br>
-               glGetProgramInfoLog(shader->program, sizeof msg, NULL, msg);<br>
-               weston_log("link info: %s\n", msg);<br>
-               return -1;<br>
-       }<br>
-<br>
-       shader->proj_uniform = glGetUniformLocation(shader->program, "proj");<br>
-       shader->tex_uniforms[0] = glGetUniformLocation(shader->program, "tex");<br>
-       shader->tex_uniforms[1] = glGetUniformLocation(shader->program, "tex1");<br>
-       shader->tex_uniforms[2] = glGetUniformLocation(shader->program, "tex2");<br>
-       shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha");<br>
-       shader->color_uniform = glGetUniformLocation(shader->program, "color");<br>
-<br>
-       return 0;<br>
-}<br>
-<br>
-static void<br>
-shader_release(struct gl_shader *shader)<br>
-{<br>
-       glDeleteShader(shader->vertex_shader);<br>
-       glDeleteShader(shader->fragment_shader);<br>
-       glDeleteProgram(shader->program);<br>
-<br>
-       shader->vertex_shader = 0;<br>
-       shader->fragment_shader = 0;<br>
-       shader->program = 0;<br>
-}<br>
-<br>
 static void<br>
 log_extensions(const char *name, const char *extensions)<br>
 {<br>
@@ -1821,6 +1440,8 @@ gl_renderer_destroy(struct weston_compositor *ec)<br>
        if (gr->has_bind_display)<br>
                gr->unbind_display(gr->egl_display, ec->wl_display);<br>
<br>
+       gl_destroy_shaders(gr);<br>
+<br>
        /* Work around crash in egl_dri2.c's dri2_make_current() - when does this apply? */<br>
        eglMakeCurrent(gr->egl_display,<br>
                       EGL_NO_SURFACE, EGL_NO_SURFACE,<br>
@@ -1838,6 +1459,7 @@ gl_renderer_destroy(struct weston_compositor *ec)<br>
                weston_binding_destroy(gr->fan_binding);<br>
<br>
        free(gr);<br>
+       ec->renderer = NULL;<br>
 }<br>
<br>
 static int<br>
@@ -1974,62 +1596,18 @@ gl_renderer_display(struct weston_compositor *ec)<br>
        return get_renderer(ec)->egl_display;<br>
 }<br>
<br>
-static int<br>
-compile_shaders(struct weston_compositor *ec)<br>
-{<br>
-       struct gl_renderer *gr = get_renderer(ec);<br>
-<br>
-       gr->texture_shader_rgba.vertex_source = vertex_shader;<br>
-       gr->texture_shader_rgba.fragment_source = texture_fragment_shader_rgba;<br>
-<br>
-       gr->texture_shader_rgbx.vertex_source = vertex_shader;<br>
-       gr->texture_shader_rgbx.fragment_source = texture_fragment_shader_rgbx;<br>
-<br>
-       gr->texture_shader_egl_external.vertex_source = vertex_shader;<br>
-       gr->texture_shader_egl_external.fragment_source =<br>
-               texture_fragment_shader_egl_external;<br>
-<br>
-       gr->texture_shader_y_uv.vertex_source = vertex_shader;<br>
-       gr->texture_shader_y_uv.fragment_source = texture_fragment_shader_y_uv;<br>
-<br>
-       gr->texture_shader_y_u_v.vertex_source = vertex_shader;<br>
-       gr->texture_shader_y_u_v.fragment_source =<br>
-               texture_fragment_shader_y_u_v;<br>
-<br>
-       gr->texture_shader_y_xuxv.vertex_source = vertex_shader;<br>
-       gr->texture_shader_y_xuxv.fragment_source =<br>
-               texture_fragment_shader_y_xuxv;<br>
-<br>
-       gr->solid_shader.vertex_source = vertex_shader;<br>
-       gr->solid_shader.fragment_source = solid_fragment_shader;<br>
-<br>
-       return 0;<br>
-}<br>
-<br>
 static void<br>
 fragment_debug_binding(struct weston_seat *seat, uint32_t time, uint32_t key,<br>
                       void *data)<br>
 {<br>
        struct weston_compositor *ec = data;<br>
        struct gl_renderer *gr = get_renderer(ec);<br>
-       struct weston_output *output;<br>
<br>
        gr->fragment_shader_debug ^= 1;<br>
<br>
-       shader_release(&gr->texture_shader_rgba);<br>
-       shader_release(&gr->texture_shader_rgbx);<br>
-       shader_release(&gr->texture_shader_egl_external);<br>
-       shader_release(&gr->texture_shader_y_uv);<br>
-       shader_release(&gr->texture_shader_y_u_v);<br>
-       shader_release(&gr->texture_shader_y_xuxv);<br>
-       shader_release(&gr->solid_shader);<br>
-<br>
-       /* Force use_shader() to call glUseProgram(), since we need to use<br>
-        * the recompiled version of the shader. */<br>
-       gr->current_shader = NULL;<br>
+       gl_init_shaders(gr);<br>
<br>
-       wl_list_for_each(output, &ec->output_list, link)<br>
-               weston_output_damage(output);<br>
+       weston_compositor_damage_all(ec);<br>
 }<br>
<br>
 static void<br>
@@ -2116,7 +1694,7 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)<br>
<br>
        glActiveTexture(GL_TEXTURE0);<br>
<br>
-       if (compile_shaders(ec))<br>
+       if (gl_init_shaders(gr) < 0)<br>
                return -1;<br>
<br>
        gr->fragment_binding =<br>
diff --git a/src/gl-shaders.c b/src/gl-shaders.c<br>
new file mode 100644<br>
index 0000000..be356dc<br>
--- /dev/null<br>
+++ b/src/gl-shaders.c<br>
@@ -0,0 +1,596 @@<br>
+/*<br>
+ * Copyright © 2012 John Kåre Alsaker<br>
+ * Copyright © 2012 Intel Corporation<br>
+ *<br>
+ * Permission to use, copy, modify, distribute, and sell this software and<br>
+ * its documentation for any purpose is hereby granted without fee, provided<br>
+ * that the above copyright notice appear in all copies and that both that<br>
+ * copyright notice and this permission notice appear in supporting<br>
+ * documentation, and that the name of the copyright holders not be used in<br>
+ * advertising or publicity pertaining to distribution of the software<br>
+ * without specific, written prior permission.  The copyright holders make<br>
+ * no representations about the suitability of this software for any<br>
+ * purpose.  It is provided "as is" without express or implied warranty.<br>
+ *<br>
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS<br>
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND<br>
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY<br>
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER<br>
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF<br>
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN<br>
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.<br>
+ */<br>
+<br>
+#include "gl-internal.h"<br>
+<br>
+#define STRINGIFY(expr) #expr<br>
+#define STRINGIFY_VALUE(expr) STRINGIFY(expr)<br>
+<br>
+static const size_t attribute_counts[ATTRIBUTE_COUNT] = {<br>
+       INPUT_COUNT,<br>
+       OUTPUT_COUNT,<br>
+       CONVERSION_COUNT<br>
+};<br>
+<br>
+struct shader_builder;<br>
+<br>
+typedef int (*gl_shader_constructor_t)<br>
+                                 (struct shader_builder *builder);<br>
+typedef void (*gl_shader_setup_uniforms_t)(struct shader_builder *builder,<br>
+                                          struct gl_shader *shader);<br>
+<br>
+struct gl_input_type_desc {<br>
+       int transparent;<br>
+       gl_shader_constructor_t constructor;<br>
+       gl_shader_setup_uniforms_t setup_uniforms;<br>
+};<br>
+<br>
+struct shader_string {<br>
+       size_t length;<br>
+       const char *str;<br>
+};<br>
+<br>
+struct shader_string_list {<br>
+       struct shader_builder *builder;<br>
+       struct wl_array array;<br>
+};<br>
+<br>
+struct shader_builder {<br>
+       struct gl_renderer *renderer;<br>
+       struct gl_input_type_desc *desc;<br>
+       int error;<br>
+       size_t attributes[ATTRIBUTE_COUNT];<br>
+       struct shader_string_list directives, global, body;<br>
+       size_t result_size;<br>
+       struct wl_array result;<br>
+};<br>
+<br>
+static void<br>
+shader_string_list_init(struct shader_string_list *strings,<br>
+                       struct shader_builder *builder)<br>
+{<br>
+       strings->builder = builder;<br>
+       wl_array_init(&strings->array);<br>
+}<br>
+<br>
+static void<br>
+shader_builder_init(struct shader_builder *builder)<br>
+{<br>
+       builder->error = 0;<br>
+       builder->result_size = 1;<br>
+       wl_array_init(&builder->result);<br>
+       shader_string_list_init(&builder->directives, builder);<br>
+       shader_string_list_init(&builder->global, builder);<br>
+       shader_string_list_init(&builder->body, builder);<br>
+}<br>
+<br>
+static void<br>
+shader_builder_release(struct shader_builder *builder)<br>
+{<br>
+       wl_array_release(&builder->directives.array);<br>
+       wl_array_release(&builder->global.array);<br>
+       wl_array_release(&builder->body.array);<br>
+}<br>
+<br>
+static void<br>
+append_shader_string_list(char **result, struct shader_string_list *string)<br>
+{<br>
+       struct shader_string *str;<br>
+<br>
+       wl_array_for_each(str, &string->array) {<br>
+               memcpy(*result, str->str, str->length);<br>
+               *result += str->length;<br>
+       }<br>
+}<br>
+<br>
+static const char *<br>
+shader_builder_get_string(struct shader_builder *builder)<br>
+{<br>
+       char *data;<br>
+<br>
+       if (builder->error)<br>
+               return NULL;<br>
+<br>
+       data = wl_array_add(&builder->result, builder->result_size);<br>
+<br>
+       if (!data)<br>
+               return NULL;<br>
+<br>
+       append_shader_string_list(&data, &builder->directives);<br>
+       append_shader_string_list(&data, &builder->global);<br>
+       append_shader_string_list(&data, &builder->body);<br>
+<br>
+       *data = 0;<br>
+<br>
+       return builder->result.data;<br>
+}<br>
+<br>
+static void<br>
+append(struct shader_string_list *list, const char *string)<br>
+{<br>
+       struct shader_string str;<br>
+       struct shader_string *data;<br>
+<br>
+       if (!string) {<br>
+               list->builder->error = 1;<br>
+               return;<br>
+       }<br>
+<br>
+       str.str = string;<br>
+       str.length = strlen(string);<br>
+       list->builder->result_size += str.length;<br>
+<br>
+       if (str.length > list->builder->result_size)<br>
+               list->builder->error = 3;<br>
+<br>
+       data = wl_array_add(&list->array, sizeof(str));<br>
+       if (!data)<br>
+               list->builder->error = 2;<br>
+       else<br>
+               *data = str;<br>
+}<br>
+<br>
+static int<br>
+shader_rgbx_constructor(struct shader_builder *sb)<br>
+{<br>
+       append(&sb->global, "uniform sampler2D texture;\n");<br>
+       append(&sb->body,<br>
+               "gl_FragColor.rgb = texture2D(texture, texture_coord).rgb;\n" \<br>
+               "gl_FragColor.a = 1.0;\n");<br>
+<br>
+       return 1;<br>
+}<br>
+<br>
+static int<br>
+shader_rgba_constructor(struct shader_builder *sb)<br>
+{<br>
+       append(&sb->global, "uniform sampler2D texture;\n");<br>
+       append(&sb->body,<br>
+               "gl_FragColor = texture2D(texture, texture_coord);\n");<br>
+<br>
+<br>
+       return 1;<br>
+}<br>
+<br>
+static int<br>
+shader_egl_external_constructor(struct shader_builder *sb)<br>
+{<br>
+       if (!sb->renderer->has_egl_image_external)<br>
+               return 0;<br>
+<br>
+       append(&sb->directives,<br>
+               "#extension GL_OES_EGL_image_external : require;\n");<br>
+       append(&sb->global,<br>
+               "uniform samplerExternalOES texture;\n");<br>
+       append(&sb->body,<br>
+               "gl_FragColor = texture2D(texture, texture_coord);\n");<br>
+<br>
+       return 1;<br>
+}<br>
+<br>
+static void<br>
+shader_texture_uniforms(struct shader_builder *sb,<br>
+                       struct gl_shader *shader)<br>
+{<br>
+       glUniform1i(glGetUniformLocation(shader->program, "texture"), 0);<br>
+}<br>
+<br>
+static int<br>
+shader_yuv_constructor(struct shader_builder *sb)<br>
+{<br>
+       const char *sample;<br>
+<br>
+       append(&sb->global,<br>
+               "uniform sampler2D planes[" STRINGIFY_VALUE(MAX_PLANES) "];\n");<br>
+<br>
+       switch (sb->attributes[ATTRIBUTE_INPUT]) {<br>
+       case INPUT_Y_UV:<br>
+               sample = "vec3 yuv = vec3(" \<br>
+                       "texture2D(planes[0], texture_coord).x," \<br>
+                       "texture2D(planes[1], texture_coord).xy);\n";<br>
+               break;<br>
+       case INPUT_Y_U_V:<br>
+               sample = "vec3 yuv = vec3(" \<br>
+                       "texture2D(planes[0], texture_coord).x," \<br>
+                       "texture2D(planes[1], texture_coord).x," \<br>
+                       "texture2D(planes[2], texture_coord).x);\n";<br>
+               break;<br>
+       case INPUT_Y_XUXV:<br>
+               sample = "vec3 yuv = vec3(" \<br>
+                       "texture2D(planes[0], texture_coord).x," \<br>
+                       "texture2D(planes[1], texture_coord).yw);\n";<br>
+               break;<br>
+       default:<br>
+               sample = NULL;<br>
+       }<br>
+<br>
+       append(&sb->body, sample);<br>
+       append(&sb->body,<br>
+               "yuv = vec3(1.16438356 * (yuv.x - 0.0625), yuv.yz - 0.5);\n" \<br>
+               "gl_FragColor.r = yuv.x + 1.59602678 * yuv.z;\n" \<br>
+               "gl_FragColor.g = yuv.x - 0.39176229 * yuv.y - " \<br>
+                       "0.81296764 * yuv.z;\n" \<br>
+               "gl_FragColor.b = yuv.x + 2.01723214 * yuv.y;\n" \<br>
+               "gl_FragColor.a = 1.0;\n");<br>
+<br>
+       return 1;<br>
+}<br>
+<br>
+static void<br>
+shader_yuv_uniforms(struct shader_builder *sb, struct gl_shader *shader)<br>
+{<br>
+       int i;<br>
+       GLint values[MAX_PLANES];<br>
+<br>
+       for (i = 0; i < MAX_PLANES; i++)<br>
+               values[i] = i;<br>
+<br>
+       glUniform1iv(glGetUniformLocation(shader->program, "planes"),<br>
+                    MAX_PLANES, values);<br>
+}<br>
+<br>
+static int<br>
+shader_solid_constructor(struct shader_builder *sb)<br>
+{<br>
+       append(&sb->global, "uniform vec4 color;\n");<br>
+       append(&sb->body, "gl_FragColor = color;\n");<br>
+<br>
+       return 1;<br>
+}<br>
+<br>
+static void<br>
+shader_solid_uniforms(struct shader_builder *sb, struct gl_shader *shader)<br>
+{<br>
+       shader->color_uniform = glGetUniformLocation(shader->program, "color");<br>
+}<br>
+<br>
+static struct gl_input_type_desc input_type_descs[INPUT_COUNT] = {<br>
+       /* INPUT_RGBX */<br>
+       {0, shader_rgbx_constructor, shader_texture_uniforms},<br>
+<br>
+       /* INPUT_RGBA */<br>
+       {1, shader_rgba_constructor, shader_texture_uniforms},<br>
+<br>
+       /* INPUT_EGL_EXTERNAL */<br>
+       {1, shader_egl_external_constructor, shader_texture_uniforms},<br>
+<br>
+       /* INPUT_Y_UV */<br>
+       {0, shader_yuv_constructor, shader_yuv_uniforms},<br>
+<br>
+       /* INPUT_Y_U_V */<br>
+       {0, shader_yuv_constructor, shader_yuv_uniforms},<br>
+<br>
+       /* INPUT_Y_XUXV */<br>
+       {0, shader_yuv_constructor, shader_yuv_uniforms},<br>
+<br>
+       /* INPUT_SOLID */<br>
+       {1, shader_solid_constructor, shader_solid_uniforms},<br>
+};<br>
+<br>
+static void<br>
+attributes_from_permutation(size_t permutation, size_t *attributes)<br>
+{<br>
+       int i;<br>
+       for (i = 0; i < ATTRIBUTE_COUNT; i++) {<br>
+               size_t attribute_count = attribute_counts[i];<br>
+               size_t attribute = permutation % attribute_count;<br>
+               permutation /= attribute_count;<br>
+               attributes[i] = attribute;<br>
+       }<br>
+}<br>
+<br>
+static size_t<br>
+permutation_from_attributes(size_t *attributes)<br>
+{<br>
+       size_t i;<br>
+       size_t result = 0, factor = 1;<br>
+<br>
+       for (i = 0; i < ATTRIBUTE_COUNT; i++) {<br>
+               result += attributes[i] * factor;<br>
+               factor *= attribute_counts[i];<br>
+       }<br>
+<br>
+       return result;<br>
+}<br>
+<br>
+static const char vertex_shader_source[] =<br>
+       "uniform mat4 projection;\n"<br>
+       "attribute vec2 position;\n"<br>
+       "attribute vec2 attr_texture_coord;\n"<br>
+       "varying vec2 texture_coord;\n"<br>
+       "void main()\n"<br>
+       "{\n"<br>
+       "   gl_Position = projection * vec4(position, 0.0, 1.0);\n"<br>
+       "   texture_coord = attr_texture_coord;\n"<br>
+       "}\n";<br>
+<br>
+static GLuint<br>
+compile_shader(GLenum type, const char *source)<br>
+{<br>
+       GLuint s;<br>
+       char msg[512];<br>
+       GLint status;<br>
+<br>
+       s = glCreateShader(type);<br>
+       glShaderSource(s, 1, &source, NULL);<br>
+       glCompileShader(s);<br>
+       glGetShaderiv(s, GL_COMPILE_STATUS, &status);<br>
+       if (!status) {<br>
+               glGetShaderInfoLog(s, sizeof msg, NULL, msg);<br>
+               weston_log("shader source: %s\n", source);<br>
+               weston_log("shader info: %s\n", msg);<br>
+               return GL_NONE;<br>
+       }<br>
+<br>
+       return s;<br>
+}<br>
+<br>
+static struct gl_shader *<br>
+shader_create(GLuint vertex_shader,<br>
+               const char *fragment_source)<br>
+{<br>
+       char msg[512];<br>
+       GLint status;<br>
+       GLuint program, fragment_shader;<br>
+<br>
+       struct gl_shader *shader;<br>
+<br>
+       fragment_shader =<br>
+               compile_shader(GL_FRAGMENT_SHADER, fragment_source);<br>
+<br>
+       if (!fragment_shader)<br>
+               return NULL;<br>
+<br>
+       shader = calloc(1, sizeof(struct gl_shader));<br>
+<br>
+       if (!shader)<br>
+               return NULL;<br>
+<br>
+       program = glCreateProgram();<br>
+<br>
+       glAttachShader(program, vertex_shader);<br>
+       glAttachShader(program, fragment_shader);<br>
+<br>
+       glDeleteShader(fragment_shader);<br>
+<br>
+       glBindAttribLocation(program, 0, "position");<br>
+       glBindAttribLocation(program, 1, "attr_texture_coord");<br>
+<br>
+       glLinkProgram(program);<br>
+       glGetProgramiv(program, GL_LINK_STATUS, &status);<br>
+<br>
+       if (!status) {<br>
+               glGetProgramInfoLog(program, sizeof msg, NULL, msg);<br>
+               weston_log("link info: %s\n", msg);<br>
+               free(shader);<br>
+               return NULL;<br>
+       }<br>
+<br>
+       shader->program = program;<br>
+       shader->projection_uniform = glGetUniformLocation(program,<br>
+                                                         "projection");<br>
+       shader->alpha_uniform = glGetUniformLocation(program, "alpha");<br>
+<br>
+       return shader;<br>
+}<br>
+<br>
+<br>
+static void<br>
+destroy_shaders(struct gl_shader **shaders, size_t count)<br>
+{<br>
+       size_t i;<br>
+<br>
+       for (i = 0; i < count; i++)<br>
+               if (shaders[i]) {<br>
+                       glDeleteProgram(shaders[i]->program);<br>
+                       free(shaders[i]);<br>
+               }<br>
+<br>
+       free(shaders);<br>
+}<br>
+<br>
+static int<br>
+create_shader_permutation(struct gl_renderer *renderer,<br>
+       struct gl_shader **shader, size_t permutation, GLuint vertex_shader)<br>
+{<br>
+       struct shader_builder sb;<br>
+       const char *fragment_shader;<br>
+<br>
+       attributes_from_permutation(permutation, sb.attributes);<br>
+<br>
+       sb.renderer = renderer;<br>
+       sb.desc = &input_type_descs[sb.attributes[ATTRIBUTE_INPUT]];<br>
+<br>
+       shader_builder_init(&sb);<br>
+<br>
+       append(&sb.global, "precision mediump float;\n" \<br>
+               "varying vec2 texture_coord;\n" \<br>
+               "uniform float alpha;\n");<br>
+<br>
+       append(&sb.body, "void main()\n{\n");<br>
+<br>
+       if (!sb.desc->constructor(&sb)) {<br>
+               shader_builder_release(&sb);<br>
+               return 0;<br>
+       }<br>
+<br>
+       append(&sb.body, "gl_FragColor *= alpha;\n");<br>
+<br>
+       if (renderer->fragment_shader_debug)<br>
+               append(&sb.body, "gl_FragColor = vec4(0.0, 0.3, 0.0, 0.2) + " \<br>
+                       "gl_FragColor * 0.8;\n");<br>
+<br>
+       append(&sb.body, "}\n");<br>
+<br>
+       fragment_shader = shader_builder_get_string(&sb);<br>
+<br>
+       if (!fragment_shader)<br>
+               goto error;<br>
+<br>
+       *shader = shader_create(vertex_shader, fragment_shader);<br>
+<br>
+       if (!*shader)<br>
+               goto error;<br>
+<br>
+       glUseProgram((*shader)->program);<br>
+<br>
+       sb.desc->setup_uniforms(&sb, *shader);<br>
+<br>
+       shader_builder_release(&sb);<br>
+<br>
+       return 0;<br>
+<br>
+error:<br>
+       shader_builder_release(&sb);<br>
+       return -1;<br>
+}<br>
+<br>
+static struct gl_shader **<br>
+create_shader_permutations(struct gl_renderer *gr)<br>
+{<br>
+       struct gl_shader **shaders;<br>
+       size_t i, permutations = 1;<br>
+       unsigned int created = 0;<br>
+       GLuint vertex_shader;<br>
+<br>
+       vertex_shader = compile_shader(GL_VERTEX_SHADER, vertex_shader_source);<br>
+<br>
+       if (!vertex_shader)<br>
+               return NULL;<br>
+<br>
+       for (i = 0; i < ATTRIBUTE_COUNT; i++)<br>
+               permutations *= attribute_counts[i];<br>
+<br>
+       shaders = calloc(permutations, sizeof(shaders));<br>
+<br>
+       if (!shaders)<br>
+               return NULL;<br>
+<br>
+       for (i = 0; i < permutations; i++) {<br>
+               if (create_shader_permutation(gr, &shaders[i],<br>
+                               i, vertex_shader) < 0)<br>
+                       goto error;<br>
+<br>
+               if (shaders[i])<br>
+                       created++;<br>
+       }<br>
+<br>
+       gr->shader_count = permutations;<br>
+<br>
+       weston_log("Created %u shader permutations\n", created);<br>
+<br>
+       glDeleteShader(vertex_shader);<br>
+<br>
+       return shaders;<br>
+<br>
+error:<br>
+       destroy_shaders(shaders, permutations);<br>
+       glDeleteShader(vertex_shader);<br>
+       return NULL;<br>
+}<br>
+<br>
+struct gl_shader *<br>
+gl_select_shader(struct gl_renderer *gr,<br>
+                       enum gl_input_attribute input,<br>
+                       enum gl_output_attribute output)<br>
+{<br>
+       struct gl_shader *shader;<br>
+       size_t attributes[ATTRIBUTE_COUNT] = {<br>
+               input,<br>
+               output,<br>
+               CONVERSION_NONE<br>
+       };<br>
+<br>
+       shader = gr->shaders[permutation_from_attributes(attributes)];<br>
+<br>
+       assert(shader);<br>
+<br>
+       return shader;<br>
+}<br>
+<br>
+void<br>
+gl_use_shader(struct gl_renderer *gr,<br>
+                            struct gl_shader *shader)<br>
+{<br>
+       if (gr->current_shader == shader)<br>
+               return;<br>
+<br>
+       glUseProgram(shader->program);<br>
+       gr->current_shader = shader;<br>
+}<br>
+<br>
+void<br>
+gl_shader_set_matrix(struct gl_shader *shader,<br>
+                    struct weston_matrix *matrix)<br>
+{<br>
+       GLfloat m[16];<br>
+       size_t i;<br>
+<br>
+       for (i = 0; i < ARRAY_LENGTH(m); i++)<br>
+               m[i] = matrix->d[i];<br>
+<br>
+       glUniformMatrix4fv(shader->projection_uniform,<br>
+                          1, GL_FALSE, m);<br>
+}<br>
+<br>
+void<br>
+gl_shader_setup(struct gl_shader *shader,<br>
+                      struct weston_view *view,<br>
+                      struct weston_output *output)<br>
+{<br>
+       struct gl_surface_state *gs = get_surface_state(view->surface);<br>
+<br>
+       gl_shader_set_matrix(shader, &output->matrix);<br>
+<br>
+       if (gs->input == INPUT_SOLID)<br>
+               glUniform4fv(shader->color_uniform, 1, gs->color);<br>
+<br>
+       glUniform1f(shader->alpha_uniform, view->alpha);<br>
+}<br>
+<br>
+int<br>
+gl_init_shaders(struct gl_renderer *gr)<br>
+{<br>
+       struct gl_shader **shaders = create_shader_permutations(gr);<br>
+<br>
+       if (!shaders)<br>
+               return -1;<br>
+<br>
+       if (gr->shaders)<br>
+               gl_destroy_shaders(gr);<br>
+<br>
+       gr->shaders = shaders;<br>
+       gr->solid_shader = gl_select_shader(gr, INPUT_SOLID, OUTPUT_BLEND);<br>
+<br>
+       /* Force use_shader() to call glUseProgram(), since we need to use<br>
+        * the recompiled version of the shader. */<br>
+       gr->current_shader = NULL;<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+void<br>
+gl_destroy_shaders(struct gl_renderer *gr)<br>
+{<br>
+       destroy_shaders(gr->shaders, gr->shader_count);<br>
+}<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.9.1<br>
<br>
_______________________________________________<br>
wayland-devel mailing list<br>
<a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</font></span></blockquote></div><br><br clear="all"><br>-- <br>  Jasper<br>
</div>