gl-renderer: Requirement based shader generation

This patch modifies the shader generation code so that the shaders are
stitched together based on the requirement instead of creating them
during initialization. This is necessary for HDR use cases where each
surface would have different properties based on which different
de-gamma or tone mapping or gamma shaders are stitched together.

v2: Use /* */ instead of // (Pekka)
    Move shader strings to gl-shaders.c file (Pekka)
    Remove Makefile.am changes (Pekka)
    Use a struct instead of uint32_t for storing requirements (Pekka)
    Clean up shader list on destroy (Pekka)
    Rename shader_release -> shader_destroy (Pekka)
    Move shader creation/deletion into gl-shaders.c (Pekka)
    Use create_shaders's multi string capbility instead of
    concatenating (Pekka)

v3: Add length check when adding shader string (Pekka)

Signed-off-by: Harish Krupo <harishkrupo@gmail.com>

v4: Rebased, PROTECTION_MODE_ENFORCED converted.
    Dropped unnecessary { }.
    Ported setup_censor_overrides().
    Split out moving code into gl-shaders.c.
    Changed to follow "gl-renderer: rewrite fragment shaders",
    no more shader source stitching.
    Added SHADER_VARIANT_XYUV.
    Const'fy function arguments.
    Added gl_shader_requirements_cmp() and moved the early return in
    use_gl_program().
    Moved use_gl_program() before first use in file.
    Split solid shader requirements by use case: requirements_censor and
    requirements_triangle_fan.
    Simplified fragment_debug_binding() since no need to force anything.

    Ensure struct gl_shader_requirements has no padding. This allows us
    to use normal C syntax instead of memset() and memcpy() when
    initializing or assigning. See also:
    https://gitlab.freedesktop.org/mesa/mesa/-/issues/2071
    Make it also a bitfield to squeeze the size.

v5: Move wl_list_insert() into gl_shader_create() (Daniel)
    Compare variant to explicit value. (Daniel)
    Change functions to gl_renderer_get_program,
    gl_renderer_use_program, and
    gl_renderer_use_program_with_view_uniforms.
    Use local variable instead of gr->current_shader. (Daniel)
    Simplified gl_renderer_get_program.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
dev
Harish Krupo 6 years ago committed by Pekka Paalanen
parent e41c6d90d0
commit 7903c5e667
  1. 2
      libweston/renderer-gl/fragment.glsl
  2. 74
      libweston/renderer-gl/gl-renderer-internal.h
  3. 229
      libweston/renderer-gl/gl-renderer.c
  4. 159
      libweston/renderer-gl/gl-shaders.c

@ -28,7 +28,7 @@
/* GLSL version 1.00 ES, defined in gl-shaders.c */
/*
* Enumeration of shader variants.
* Enumeration of shader variants, must match enum gl_shader_texture_variant.
*/
#define SHADER_VARIANT_RGBX 1
#define SHADER_VARIANT_RGBA 2

@ -1,5 +1,7 @@
/*
* Copyright © 2019 Collabora, Ltd.
* Copyright © 2019 Harish Krupo
* Copyright © 2019 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -26,18 +28,60 @@
#ifndef GL_RENDERER_INTERNAL_H
#define GL_RENDERER_INTERNAL_H
#include <stdbool.h>
#include <wayland-util.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include "shared/weston-egl-ext.h" /* for PFN* stuff */
#include "shared/helpers.h"
enum gl_shader_texture_variant {
SHADER_VARIANT_NONE = 0,
/* Keep the following in sync with fragment.glsl. */
SHADER_VARIANT_RGBX,
SHADER_VARIANT_RGBA,
SHADER_VARIANT_Y_U_V,
SHADER_VARIANT_Y_UV,
SHADER_VARIANT_Y_XUXV,
SHADER_VARIANT_XYUV,
SHADER_VARIANT_SOLID,
SHADER_VARIANT_EXTERNAL,
};
/** GL shader requirements key
*
* This structure is used as a binary blob key for building and searching
* shaders. Therefore it must not contain any bytes or bits the C compiler
* would be free to leave undefined e.g. after struct initialization,
* struct assignment, or member operations.
*
* Use 'pahole' from package 'dwarves' to inspect this structure.
*/
struct gl_shader_requirements
{
unsigned variant:4; /* enum gl_shader_texture_variant */
bool green_tint:1;
/*
* The total size of all bitfields plus pad_bits_ must fill up exactly
* how many bytes the compiler allocates for them together.
*/
unsigned pad_bits_:27;
};
static_assert(sizeof(struct gl_shader_requirements) ==
4 /* total bitfield size in bytes */,
"struct gl_shader_requirements must not contain implicit padding");
struct gl_shader {
struct gl_shader_requirements key;
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;
struct wl_list link; /* gl_renderer::shader_list */
};
struct gl_renderer {
@ -91,15 +135,6 @@ struct gl_renderer {
bool has_gl_texture_rg;
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 texture_shader_xyuv;
struct gl_shader invert_color_shader;
struct gl_shader solid_shader;
struct gl_shader *current_shader;
struct wl_signal destroy_signal;
@ -117,6 +152,12 @@ struct gl_renderer {
bool has_wait_sync;
PFNEGLWAITSYNCKHRPROC wait_sync;
/** struct gl_shader::link
*
* List constains cached shaders built from struct gl_shader_requirements
*/
struct wl_list shader_list;
};
static inline struct gl_renderer *
@ -149,14 +190,15 @@ gl_renderer_setup_egl_client_extensions(struct gl_renderer *gr);
int
gl_renderer_setup_egl_extensions(struct weston_compositor *ec);
int
shader_init(struct gl_shader *shader, struct gl_renderer *renderer,
const char *vertex_source, const char *fragment_source);
void
shader_release(struct gl_shader *shader);
gl_shader_destroy(struct gl_shader *shader);
struct gl_shader *
gl_shader_create(struct gl_renderer *gr,
const struct gl_shader_requirements *requirements);
int
compile_shaders(struct weston_compositor *ec);
gl_shader_requirements_cmp(const struct gl_shader_requirements *a,
const struct gl_shader_requirements *b);
#endif /* GL_RENDERER_INTERNAL_H */

@ -123,7 +123,7 @@ struct dmabuf_image {
enum import_type import_type;
GLenum target;
struct gl_shader *shader;
enum gl_shader_texture_variant shader_variant;
};
struct dmabuf_format {
@ -159,7 +159,6 @@ struct yuv_format_descriptor {
struct gl_surface_state {
GLfloat color[4];
struct gl_shader *shader;
GLuint textures[3];
int num_textures;
@ -197,6 +196,7 @@ struct gl_surface_state {
struct wl_listener surface_destroy_listener;
struct wl_listener renderer_destroy_listener;
struct gl_shader_requirements shader_requirements;
};
enum timeline_render_point_type {
@ -625,6 +625,55 @@ texture_region(struct weston_view *ev, pixman_region32_t *region,
return nvtx;
}
static struct gl_shader *
gl_renderer_get_program(struct gl_renderer *gr,
const struct gl_shader_requirements *requirements)
{
struct gl_shader_requirements reqs = *requirements;
struct gl_shader *shader;
assert(reqs.pad_bits_ == 0);
if (gr->fragment_shader_debug)
reqs.green_tint = true;
if (gr->current_shader &&
gl_shader_requirements_cmp(&reqs, &gr->current_shader->key) == 0)
return gr->current_shader;
wl_list_for_each(shader, &gr->shader_list, link) {
if (gl_shader_requirements_cmp(&reqs, &shader->key) == 0)
return shader;
}
shader = gl_shader_create(gr, &reqs);
if (shader)
return shader;
weston_log("warning: failed to generate gl program\n");
return NULL;
}
static bool
gl_renderer_use_program(struct gl_renderer *gr, struct gl_shader *shader)
{
if (!shader) {
weston_log("Error: trying to use NULL GL shader.\n");
return false;
}
if (gr->current_shader == shader)
return true;
glUseProgram(shader->program);
gr->current_shader = shader;
return true;
}
static const struct gl_shader_requirements requirements_triangle_fan = {
.variant = SHADER_VARIANT_SOLID,
};
static void
triangle_fan_debug(struct weston_view *view, int first, int count)
{
@ -635,6 +684,8 @@ triangle_fan_debug(struct weston_view *view, int first, int count)
GLushort *index;
int nelems;
static int color_idx = 0;
struct gl_shader *shader;
struct gl_shader *prev_shader = gr->current_shader;
static const GLfloat color[][4] = {
{ 1.0, 0.0, 0.0, 1.0 },
{ 0.0, 1.0, 0.0, 1.0 },
@ -642,6 +693,10 @@ triangle_fan_debug(struct weston_view *view, int first, int count)
{ 1.0, 1.0, 1.0, 1.0 },
};
shader = gl_renderer_get_program(gr, &requirements_triangle_fan);
if (!gl_renderer_use_program(gr, shader))
return;
nelems = (count - 1 + count - 2) * 2;
buffer = malloc(sizeof(GLushort) * nelems);
@ -657,11 +712,11 @@ 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,
color[color_idx++ % ARRAY_LENGTH(color)]);
glUniform4fv(shader->color_uniform, 1,
color[color_idx++ % ARRAY_LENGTH(color)]);
glDrawElements(GL_LINES, nelems, GL_UNSIGNED_SHORT, buffer);
glUseProgram(gr->current_shader->program);
gl_renderer_use_program(gr, prev_shader);
free(buffer);
}
@ -734,34 +789,18 @@ use_output(struct weston_output *output)
}
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)
gl_renderer_use_program_with_view_uniforms(struct gl_renderer *gr,
struct gl_shader *shader,
struct weston_view *view,
struct weston_output *output)
{
int i;
struct gl_surface_state *gs = get_surface_state(view->surface);
struct gl_output_state *go = get_output_state(output);
if (!gl_renderer_use_program(gr, shader))
return;
glUniformMatrix4fv(shader->proj_uniform,
1, GL_FALSE, go->output_matrix.d);
glUniform4fv(shader->color_uniform, 1, gs->color);
@ -851,6 +890,9 @@ static struct gl_shader *
maybe_censor_override(struct weston_output *output,
struct weston_view *ev)
{
const struct gl_shader_requirements requirements_censor = {
.variant = SHADER_VARIANT_SOLID,
};
struct weston_compositor *ec = ev->surface->compositor;
struct gl_renderer *gr = get_renderer(ec);
struct gl_surface_state *gs = get_surface_state(ev->surface);
@ -866,24 +908,24 @@ maybe_censor_override(struct weston_output *output,
gs->color[1] = 0.0;
gs->color[2] = 0.0;
gs->color[3] = 1.0;
return &gr->solid_shader;
return gl_renderer_get_program(gr, &requirements_censor);
}
/* When not in enforced mode, the client is notified of the protection */
/* change, so content censoring is not required */
if (ev->surface->protection_mode !=
WESTON_SURFACE_PROTECTION_MODE_ENFORCED)
return gs->shader;
return gl_renderer_get_program(gr, &gs->shader_requirements);
if (recording_censor || unprotected_censor) {
gs->color[0] = 0.40;
gs->color[1] = 0.0;
gs->color[2] = 0.0;
gs->color[3] = 1.0;
return &gr->solid_shader;
return gl_renderer_get_program(gr, &requirements_censor);
}
return gs->shader;
return gl_renderer_get_program(gr, &gs->shader_requirements);
}
static void
@ -906,7 +948,8 @@ 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 && !gs->direct_display)
if (gs->shader_requirements.variant == SHADER_VARIANT_NONE &&
!gs->direct_display)
return;
pixman_region32_init(&repaint);
@ -920,18 +963,20 @@ draw_view(struct weston_view *ev, struct weston_output *output,
if (ensure_surface_buffer_is_ready(gr, gs) < 0)
goto out;
shader = maybe_censor_override(output, ev);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
/* The built shader objects are cached in struct
* gl_renderer::shader_list and retrieved when requested with the same
* struct gl_shader_requirements. The triangle fan shader is generated
* here so that the shader uniforms are cached when used later
*/
if (gr->fan_debug) {
use_shader(gr, &gr->solid_shader);
shader_uniforms(&gr->solid_shader, ev, output);
shader = gl_renderer_get_program(gr,
&requirements_triangle_fan);
gl_renderer_use_program_with_view_uniforms(gr, shader,
ev, output);
}
use_shader(gr, shader);
shader_uniforms(shader, ev, output);
if (ev->transform.enabled || output->zoom.active ||
output->current_scale != ev->surface->buffer_viewport.buffer.scale)
filter = GL_LINEAR;
@ -963,15 +1008,25 @@ draw_view(struct weston_view *ev, struct weston_output *output,
else
pixman_region32_copy(&surface_opaque, &ev->surface->opaque);
shader = maybe_censor_override(output, ev);
gl_renderer_use_program_with_view_uniforms(gr, shader, ev, output);
if (pixman_region32_not_empty(&surface_opaque)) {
if (shader == &gr->texture_shader_rgba) {
if (shader->key.variant == SHADER_VARIANT_RGBA) {
struct gl_shader_requirements tmp_requirements;
struct gl_shader *tmp_shader;
/* 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);
tmp_requirements = shader->key;
tmp_requirements.variant = SHADER_VARIANT_RGBX;
tmp_shader = gl_renderer_get_program(gr, &tmp_requirements);
gl_renderer_use_program_with_view_uniforms(gr,
tmp_shader,
ev, output);
}
if (ev->alpha < 1.0)
@ -984,7 +1039,7 @@ draw_view(struct weston_view *ev, struct weston_output *output,
}
if (pixman_region32_not_empty(&surface_blend)) {
use_shader(gr, shader);
gl_renderer_use_program(gr, shader);
glEnable(GL_BLEND);
repaint_region(ev, &repaint, &surface_blend);
gs->used_in_output_repaint = true;
@ -1158,10 +1213,13 @@ static void
draw_output_borders(struct weston_output *output,
enum gl_border_status border_status)
{
const struct gl_shader_requirements requirements_rgba = {
.variant = SHADER_VARIANT_RGBA,
};
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_border_image *top, *bottom, *left, *right;
struct gl_shader *shader;
struct weston_matrix matrix;
int full_width, full_height;
@ -1177,7 +1235,9 @@ draw_output_borders(struct weston_output *output,
full_height = output->current_mode->height + top->height + bottom->height;
glDisable(GL_BLEND);
use_shader(gr, shader);
shader = gl_renderer_get_program(gr, &requirements_rgba);
if (!gl_renderer_use_program(gr, shader))
return;
glViewport(0, 0, full_width, full_height);
@ -1711,28 +1771,28 @@ 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->shader_requirements.variant = SHADER_VARIANT_RGBX;
pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
gl_format[0] = GL_BGRA_EXT;
gl_pixel_type = GL_UNSIGNED_BYTE;
es->is_opaque = true;
break;
case WL_SHM_FORMAT_ARGB8888:
gs->shader = &gr->texture_shader_rgba;
gs->shader_requirements.variant = SHADER_VARIANT_RGBA;
pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
gl_format[0] = GL_BGRA_EXT;
gl_pixel_type = GL_UNSIGNED_BYTE;
es->is_opaque = false;
break;
case WL_SHM_FORMAT_RGB565:
gs->shader = &gr->texture_shader_rgbx;
gs->shader_requirements.variant = SHADER_VARIANT_RGBX;
pitch = wl_shm_buffer_get_stride(shm_buffer) / 2;
gl_format[0] = GL_RGB;
gl_pixel_type = GL_UNSIGNED_SHORT_5_6_5;
es->is_opaque = true;
break;
case WL_SHM_FORMAT_YUV420:
gs->shader = &gr->texture_shader_y_u_v;
gs->shader_requirements.variant = SHADER_VARIANT_Y_U_V;
pitch = wl_shm_buffer_get_stride(shm_buffer);
gl_pixel_type = GL_UNSIGNED_BYTE;
num_planes = 3;
@ -1764,18 +1824,18 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
gs->hsub[1] = 2;
gs->vsub[1] = 2;
if (gr->has_gl_texture_rg) {
gs->shader = &gr->texture_shader_y_uv;
gs->shader_requirements.variant = SHADER_VARIANT_Y_UV;
gl_format[0] = GL_R8_EXT;
gl_format[1] = GL_RG8_EXT;
} else {
gs->shader = &gr->texture_shader_y_xuxv;
gs->shader_requirements.variant = SHADER_VARIANT_Y_XUXV;
gl_format[0] = GL_LUMINANCE;
gl_format[1] = GL_LUMINANCE_ALPHA;
}
es->is_opaque = true;
break;
case WL_SHM_FORMAT_YUYV:
gs->shader = &gr->texture_shader_y_xuxv;
gs->shader_requirements.variant = SHADER_VARIANT_Y_XUXV;
pitch = wl_shm_buffer_get_stride(shm_buffer) / 2;
gl_pixel_type = GL_UNSIGNED_BYTE;
num_planes = 2;
@ -1855,26 +1915,26 @@ gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,
case EGL_TEXTURE_RGBA:
default:
num_planes = 1;
gs->shader = &gr->texture_shader_rgba;
gs->shader_requirements.variant = SHADER_VARIANT_RGBA;
break;
case EGL_TEXTURE_EXTERNAL_WL:
num_planes = 1;
gs->target = GL_TEXTURE_EXTERNAL_OES;
gs->shader = &gr->texture_shader_egl_external;
gs->shader_requirements.variant = SHADER_VARIANT_EXTERNAL;
break;
case EGL_TEXTURE_Y_UV_WL:
num_planes = 2;
gs->shader = &gr->texture_shader_y_uv;
gs->shader_requirements.variant = SHADER_VARIANT_Y_UV;
es->is_opaque = true;
break;
case EGL_TEXTURE_Y_U_V_WL:
num_planes = 3;
gs->shader = &gr->texture_shader_y_u_v;
gs->shader_requirements.variant = SHADER_VARIANT_Y_U_V;
es->is_opaque = true;
break;
case EGL_TEXTURE_Y_XUXV_WL:
num_planes = 2;
gs->shader = &gr->texture_shader_y_xuxv;
gs->shader_requirements.variant = SHADER_VARIANT_Y_XUXV;
es->is_opaque = true;
break;
}
@ -2198,16 +2258,16 @@ import_yuv_dmabuf(struct gl_renderer *gr,
switch (format->texture_type) {
case TEXTURE_Y_XUXV_WL:
image->shader = &gr->texture_shader_y_xuxv;
image->shader_variant = SHADER_VARIANT_Y_XUXV;
break;
case TEXTURE_Y_UV_WL:
image->shader = &gr->texture_shader_y_uv;
image->shader_variant = SHADER_VARIANT_Y_UV;
break;
case TEXTURE_Y_U_V_WL:
image->shader = &gr->texture_shader_y_u_v;
image->shader_variant = SHADER_VARIANT_Y_U_V;
break;
case TEXTURE_XYUV_WL:
image->shader = &gr->texture_shader_xyuv;
image->shader_variant = SHADER_VARIANT_XYUV;
break;
default:
assert(false);
@ -2320,10 +2380,10 @@ import_dmabuf(struct gl_renderer *gr,
switch (image->target) {
case GL_TEXTURE_2D:
image->shader = &gr->texture_shader_rgba;
image->shader_variant = SHADER_VARIANT_RGBA;
break;
default:
image->shader = &gr->texture_shader_egl_external;
image->shader_variant = SHADER_VARIANT_EXTERNAL;
}
} else {
if (!import_yuv_dmabuf(gr, image)) {
@ -2587,7 +2647,7 @@ gl_renderer_attach_dmabuf(struct weston_surface *surface,
gr->image_target_texture_2d(gs->target, gs->images[i]->image);
}
gs->shader = image->shader;
gs->shader_requirements.variant = image->shader_variant;
}
static void
@ -2651,7 +2711,6 @@ 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;
@ -2661,7 +2720,7 @@ gl_renderer_surface_set_color(struct weston_surface *surface,
gs->pitch = 1;
gs->height = 1;
gs->shader = &gr->solid_shader;
gs->shader_requirements.variant = SHADER_VARIANT_SOLID;
}
static void
@ -2725,6 +2784,7 @@ gl_renderer_surface_copy_content(struct weston_surface *surface,
const GLenum gl_format = GL_RGBA; /* PIXMAN_a8b8g8r8 little-endian */
struct gl_renderer *gr = get_renderer(surface->compositor);
struct gl_surface_state *gs = get_surface_state(surface);
struct gl_shader *shader;
int cw, ch;
GLuint fbo;
GLuint tex;
@ -2747,6 +2807,10 @@ gl_renderer_surface_copy_content(struct weston_surface *surface,
break;
}
shader = gl_renderer_get_program(gr, &gs->shader_requirements);
if (!gl_renderer_use_program(gr, shader))
return -1;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cw, ch,
@ -2768,17 +2832,16 @@ gl_renderer_surface_copy_content(struct weston_surface *surface,
glViewport(0, 0, cw, ch);
glDisable(GL_BLEND);
use_shader(gr, gs->shader);
if (gs->y_inverted)
proj = projmat_normal;
else
proj = projmat_yinvert;
glUniformMatrix4fv(gs->shader->proj_uniform, 1, GL_FALSE, proj);
glUniform1f(gs->shader->alpha_uniform, 1.0f);
glUniformMatrix4fv(shader->proj_uniform, 1, GL_FALSE, proj);
glUniform1f(shader->alpha_uniform, 1.0f);
for (i = 0; i < gs->num_textures; i++) {
glUniform1i(gs->shader->tex_uniforms[i], i);
glUniform1i(shader->tex_uniforms[i], i);
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(gs->target, gs->textures[i]);
@ -3181,18 +3244,21 @@ gl_renderer_destroy(struct weston_compositor *ec)
struct gl_renderer *gr = get_renderer(ec);
struct dmabuf_image *image, *next;
struct dmabuf_format *format, *next_format;
struct gl_shader *shader, *next_shader;
wl_signal_emit(&gr->destroy_signal, gr);
if (gr->has_bind_display)
gr->unbind_display(gr->egl_display, ec->wl_display);
wl_list_for_each_safe(shader, next_shader, &gr->shader_list, link)
gl_shader_destroy(shader);
/* 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,
EGL_NO_CONTEXT);
wl_list_for_each_safe(image, next, &gr->dmabuf_images, link)
dmabuf_image_destroy(image);
@ -3275,6 +3341,7 @@ gl_renderer_display_create(struct weston_compositor *ec,
if (gr == NULL)
return -1;
wl_list_init(&gr->shader_list);
gr->platform = options->egl_platform;
if (gl_renderer_setup_egl_client_extensions(gr) < 0)
@ -3381,19 +3448,6 @@ fragment_debug_binding(struct weston_keyboard *keyboard,
gr->fragment_shader_debug = !gr->fragment_shader_debug;
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->texture_shader_xyuv);
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;
wl_list_for_each(output, &ec->output_list, link)
weston_output_damage(output);
}
@ -3536,9 +3590,6 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
glActiveTexture(GL_TEXTURE0);
if (compile_shaders(ec))
return -1;
gr->fragment_binding =
weston_compositor_add_debug_binding(ec, KEY_S,
fragment_debug_binding,

@ -2,6 +2,8 @@
* Copyright 2012 Intel Corporation
* Copyright 2015,2019 Collabora, Ltd.
* Copyright 2016 NVIDIA Corporation
* Copyright 2019 Harish Krupo
* Copyright 2019 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
@ -27,12 +29,18 @@
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <libweston/libweston.h>
#include <GLES2/gl2.h>
#include <string.h>
#include "gl-renderer.h"
#include "gl-renderer-internal.h"
#include "shared/helpers.h"
/* static const char vertex_shader[]; vertex.glsl */
#include "vertex-shader.h"
@ -40,6 +48,26 @@
/* static const char fragment_shader[]; fragment.glsl */
#include "fragment-shader.h"
static const char *
gl_shader_texture_variant_to_string(enum gl_shader_texture_variant v)
{
switch (v) {
#define CASERET(x) case x: return #x;
CASERET(SHADER_VARIANT_NONE)
CASERET(SHADER_VARIANT_RGBX)
CASERET(SHADER_VARIANT_RGBA)
CASERET(SHADER_VARIANT_Y_U_V)
CASERET(SHADER_VARIANT_Y_UV)
CASERET(SHADER_VARIANT_Y_XUXV)
CASERET(SHADER_VARIANT_XYUV)
CASERET(SHADER_VARIANT_SOLID)
CASERET(SHADER_VARIANT_EXTERNAL)
#undef CASERET
}
return "!?!?"; /* never reached */
}
static void
dump_program_with_line_numbers(int count, const char **sources)
{
@ -77,6 +105,14 @@ dump_program_with_line_numbers(int count, const char **sources)
free(dumpstr);
}
void
gl_shader_destroy(struct gl_shader *shader)
{
glDeleteProgram(shader->program);
wl_list_remove(&shader->link);
free(shader);
}
static int
compile_shader(GLenum type, int count, const char **sources)
{
@ -99,44 +135,57 @@ compile_shader(GLenum type, int count, const char **sources)
return s;
}
int
shader_init(struct gl_shader *shader, struct gl_renderer *renderer,
const char *vertex_source, const char *fragment_variant)
static char *
create_shader_config_string(const struct gl_shader_requirements *req)
{
int size;
char *str;
size = asprintf(&str,
"#define DEF_GREEN_TINT %s\n"
"#define DEF_VARIANT %s\n",
req->green_tint ? "true" : "false",
gl_shader_texture_variant_to_string(req->variant));
if (size < 0)
return NULL;
return str;
}
struct gl_shader *
gl_shader_create(struct gl_renderer *gr,
const struct gl_shader_requirements *requirements)
{
static const char fragment_shader_attrs_fmt[] =
"#define DEF_GREEN_TINT %s\n"
"#define DEF_VARIANT %s\n"
;
struct gl_shader *shader = NULL;
char msg[512];
GLint status;
int ret;
const char *sources[3];
char *attrs;
const char *def_green_tint;
char *conf = NULL;
shader->vertex_shader =
compile_shader(GL_VERTEX_SHADER, 1, &vertex_source);
if (shader->vertex_shader == GL_NONE)
return -1;
shader = zalloc(sizeof *shader);
if (!shader) {
weston_log("could not create shader\n");
goto error_vertex;
}
if (renderer->fragment_shader_debug)
def_green_tint = "true";
else
def_green_tint = "false";
wl_list_init(&shader->link);
shader->key = *requirements;
ret = asprintf(&attrs, fragment_shader_attrs_fmt,
def_green_tint, fragment_variant);
if (ret < 0)
return -1;
sources[0] = vertex_shader;
shader->vertex_shader = compile_shader(GL_VERTEX_SHADER, 1, sources);
if (shader->vertex_shader == GL_NONE)
goto error_vertex;
conf = create_shader_config_string(&shader->key);
if (!conf)
goto error_fragment;
sources[0] = "#version 100\n";
sources[1] = attrs;
sources[1] = conf;
sources[2] = fragment_shader;
shader->fragment_shader = compile_shader(GL_FRAGMENT_SHADER,
3, sources);
free(attrs);
if (shader->fragment_shader == GL_NONE)
return -1;
goto error_fragment;
shader->program = glCreateProgram();
glAttachShader(shader->program, shader->vertex_shader);
@ -149,9 +198,12 @@ shader_init(struct gl_shader *shader, struct gl_renderer *renderer,
if (!status) {
glGetProgramInfoLog(shader->program, sizeof msg, NULL, msg);
weston_log("link info: %s\n", msg);
return -1;
goto error_link;
}
glDeleteShader(shader->vertex_shader);
glDeleteShader(shader->fragment_shader);
shader->proj_uniform = glGetUniformLocation(shader->program, "proj");
shader->tex_uniforms[0] = glGetUniformLocation(shader->program, "tex");
shader->tex_uniforms[1] = glGetUniformLocation(shader->program, "tex1");
@ -159,49 +211,28 @@ shader_init(struct gl_shader *shader, struct gl_renderer *renderer,
shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha");
shader->color_uniform = glGetUniformLocation(shader->program, "color");
return 0;
}
free(conf);
void
shader_release(struct gl_shader *shader)
{
glDeleteShader(shader->vertex_shader);
glDeleteShader(shader->fragment_shader);
wl_list_insert(&gr->shader_list, &shader->link);
return shader;
error_link:
glDeleteProgram(shader->program);
glDeleteShader(shader->fragment_shader);
shader->vertex_shader = 0;
shader->fragment_shader = 0;
shader->program = 0;
error_fragment:
glDeleteShader(shader->vertex_shader);
error_vertex:
free(conf);
free(shader);
return NULL;
}
int
compile_shaders(struct weston_compositor *ec)
gl_shader_requirements_cmp(const struct gl_shader_requirements *a,
const struct gl_shader_requirements *b)
{
struct gl_renderer *gr = get_renderer(ec);
gr->texture_shader_rgba.vertex_source = vertex_shader;
gr->texture_shader_rgba.fragment_source = "SHADER_VARIANT_RGBA";
gr->texture_shader_rgbx.vertex_source = vertex_shader;
gr->texture_shader_rgbx.fragment_source = "SHADER_VARIANT_RGBX";
gr->texture_shader_egl_external.vertex_source = vertex_shader;
gr->texture_shader_egl_external.fragment_source = "SHADER_VARIANT_EXTERNAL";
gr->texture_shader_y_uv.vertex_source = vertex_shader;
gr->texture_shader_y_uv.fragment_source = "SHADER_VARIANT_Y_UV";
gr->texture_shader_y_u_v.vertex_source = vertex_shader;
gr->texture_shader_y_u_v.fragment_source = "SHADER_VARIANT_Y_U_V";
gr->texture_shader_y_xuxv.vertex_source = vertex_shader;
gr->texture_shader_y_xuxv.fragment_source = "SHADER_VARIANT_Y_XUXV";
gr->texture_shader_xyuv.vertex_source = vertex_shader;
gr->texture_shader_xyuv.fragment_source = "SHADER_VARIANT_XYUV";
gr->solid_shader.vertex_source = vertex_shader;
gr->solid_shader.fragment_source = "SHADER_VARIANT_SOLID";
return 0;
return memcmp(a, b, sizeof(*a));
}

Loading…
Cancel
Save