[PATCH] gl-renderer: Add flexible shader generation.

Gwenole Beauchesne gb.devel at gmail.com
Wed Sep 10 23:22:03 PDT 2014


Hi,

2014-04-08 22:18 GMT+02:00 John Kåre Alsaker <john.kare.alsaker at gmail.com>:
> I need to add lots of shader variants to do color conversions.

This is a very valid reason. The original code for YUV to RGB
conversion implemented a BT.601 limited color range conversion. It is
desired to handle more combinations of (BT.601, BT.709, etc.) x
(limited, full) range for certain use cases. Besides, we can also
simplify the color conversion code to a single vector subtraction, and
matrix multiplication.

Sorry for the original oversight. I was about to write a patch for
that, but noticed this thread.

Thanks,
Gwenole.

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



-- 
Gwenole Beauchesne
Intel Corporation SAS / 2 rue de Paris, 92196 Meudon Cedex, France
Registration Number (RCS): Nanterre B 302 456 199


More information about the wayland-devel mailing list