Hi, 2014-04-08 22:18 GMT+02:00 John Kåre Alsaker <[email protected]>: > 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 <[email protected]> > 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 >> <[email protected]> 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 >>> [email protected] >>> http://lists.freedesktop.org/mailman/listinfo/wayland-devel >> >> >> >> >> -- >> Jasper > _______________________________________________ > wayland-devel mailing list > [email protected] > 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 _______________________________________________ wayland-devel mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/wayland-devel
