[PATCH] gl-renderer: Add flexible shader generation.
John Kåre Alsaker
john.kare.alsaker at gmail.com
Tue Apr 8 13:18:19 PDT 2014
I need to add lots of shader variants to do color conversions.
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,
>> + 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
More information about the wayland-devel
mailing list