gl-renderer: rework uniform value assignments

This patch gathers all values to be loaded to shader uniforms into a new
struct gl_shader_config along with texture target and filter
information. Struct gl_shader becomes opaque outside of gl-shaders.c.
Everything that used or open-coded these are converted.

The aim is to make gl-renderer.c easier to read. Previously, uniform
values were loaded up in various places, texture units were set up in
one place, textures were bound into units in different places. Stuff was
all over the place.

Now, shader requirements and associated uniform data is stored in a
single struct. The data is loaded into a shader program in one function
only.

That makes it easy for things like maybe_censor_override() to replace
the whole config rather than poke only the shader requirements. This may
not look like much right now, but when color management adds more
uniforms and even hardcoded color need to go through the proper color
pipeline, doing things the old way would become intractable.

Similar simplification can be seen in draw_view(), where the RGBA->RGBX
override becomes more contained. There is no longer a need to "pre-load"
the shader used by triangle fan debug. Triangle fan debug no longer
needs to play tricks with saving and restoring the current shader.

The real benefit of this change will probably come when almost all
shader operations need to take color spaces into account. That means
filling in gl_shader_config parts based on a color transformation.

This is based on an idea Sebastian already used in his Weston color
management work.

Co-authored-by: Sebastian Wick <sebastian@sebastianwick.net>
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
dev
Pekka Paalanen 4 years ago committed by Pekka Paalanen
parent 6d1a7df42f
commit 0f52da6226
  1. 31
      libweston/renderer-gl/gl-renderer-internal.h
  2. 298
      libweston/renderer-gl/gl-renderer.c
  3. 69
      libweston/renderer-gl/gl-shaders.c

@ -74,16 +74,17 @@ 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;
struct wl_list link; /* gl_renderer::shader_list */
struct timespec last_used;
struct gl_shader;
#define GL_SHADER_INPUT_TEX_MAX 3
struct gl_shader_config {
struct gl_shader_requirements req;
struct weston_matrix projection;
float view_alpha;
GLfloat unicolor[4];
GLint input_tex_filter; /* GL_NEAREST or GL_LINEAR */
GLuint input_tex[GL_SHADER_INPUT_TEX_MAX];
};
struct gl_renderer {
@ -198,6 +199,9 @@ gl_renderer_setup_egl_client_extensions(struct gl_renderer *gr);
int
gl_renderer_setup_egl_extensions(struct weston_compositor *ec);
GLenum
gl_shader_texture_variant_get_target(enum gl_shader_texture_variant v);
void
gl_shader_destroy(struct gl_renderer *gr, struct gl_shader *shader);
@ -211,11 +215,8 @@ void
gl_renderer_garbage_collect_programs(struct gl_renderer *gr);
bool
gl_renderer_use_program(struct gl_renderer *gr, struct gl_shader **shaderp);
struct gl_shader *
gl_renderer_get_program(struct gl_renderer *gr,
const struct gl_shader_requirements *requirements);
gl_renderer_use_program(struct gl_renderer *gr,
const struct gl_shader_config *sconf);
struct weston_log_scope *
gl_shader_scope_create(struct gl_renderer *gr);

@ -716,12 +716,9 @@ gl_renderer_send_shader_error(struct weston_view *view)
wl_resource_get_id(resource));
}
static const struct gl_shader_requirements requirements_triangle_fan = {
.variant = SHADER_VARIANT_SOLID,
};
static void
triangle_fan_debug(struct gl_renderer *gr,
const struct gl_shader_config *sconf,
int first, int count)
{
int i;
@ -729,8 +726,8 @@ triangle_fan_debug(struct gl_renderer *gr,
GLushort *index;
int nelems;
static int color_idx = 0;
struct gl_shader *shader;
struct gl_shader *prev_shader = gr->current_shader;
struct gl_shader_config alt;
const GLfloat *col;
static const GLfloat color[][4] = {
{ 1.0, 0.0, 0.0, 1.0 },
{ 0.0, 1.0, 0.0, 1.0 },
@ -738,9 +735,17 @@ triangle_fan_debug(struct gl_renderer *gr,
{ 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;
col = color[color_idx++ % ARRAY_LENGTH(color)];
alt = (struct gl_shader_config) {
.req = {
.variant = SHADER_VARIANT_SOLID,
},
.projection = sconf->projection,
.view_alpha = 1.0f,
.unicolor = { col[0], col[1], col[2], col[3] },
};
gl_renderer_use_program(gr, &alt);
nelems = (count - 1 + count - 2) * 2;
@ -757,19 +762,19 @@ triangle_fan_debug(struct gl_renderer *gr,
*index++ = first + i;
}
glUniform4fv(shader->color_uniform, 1,
color[color_idx++ % ARRAY_LENGTH(color)]);
glDrawElements(GL_LINES, nelems, GL_UNSIGNED_SHORT, buffer);
gl_renderer_use_program(gr, &prev_shader);
free(buffer);
gl_renderer_use_program(gr, sconf);
}
static void
repaint_region(struct gl_renderer *gr,
struct weston_view *ev,
pixman_region32_t *region,
pixman_region32_t *surf_region)
pixman_region32_t *surf_region,
const struct gl_shader_config *sconf)
{
GLfloat *v;
unsigned int *vtxcnt;
@ -796,10 +801,15 @@ repaint_region(struct gl_renderer *gr,
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
glEnableVertexAttribArray(1);
if (!gl_renderer_use_program(gr, sconf)) {
gl_renderer_send_shader_error(ev);
/* continue drawing with the fallback shader */
}
for (i = 0, first = 0; i < nfans; i++) {
glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
if (gr->fan_debug)
triangle_fan_debug(gr, first, vtxcnt[i]);
triangle_fan_debug(gr, sconf, first, vtxcnt[i]);
first += vtxcnt[i];
}
@ -833,34 +843,6 @@ use_output(struct weston_output *output)
return 0;
}
static void
gl_renderer_use_program_with_view_uniforms(struct gl_renderer *gr,
struct gl_shader **shaderp,
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);
struct gl_shader *shader;
bool ok;
ok = gl_renderer_use_program(gr, shaderp);
shader = *shaderp;
glUniformMatrix4fv(shader->proj_uniform,
1, GL_FALSE, go->output_matrix.d);
if (ok) {
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);
} else {
gl_renderer_send_shader_error(view);
}
}
static int
ensure_surface_buffer_is_ready(struct gl_renderer *gr,
struct gl_surface_state *gs)
@ -934,18 +916,21 @@ ensure_surface_buffer_is_ready(struct gl_renderer *gr,
* protected view is captured.
* - unprotected_censor: Censor regions of protected views
* when displayed on an output which has lower protection capability.
* Returns a censoring shader if necessary, or the surface's original
* shader otherwise.
* If censoring is needed, smashes the GL shader config.
*/
static struct gl_shader *
maybe_censor_override(struct weston_output *output,
static void
maybe_censor_override(struct gl_shader_config *sconf,
struct weston_output *output,
struct weston_view *ev)
{
const struct gl_shader_requirements requirements_censor = {
const struct gl_shader_config alt = {
.req = {
.variant = SHADER_VARIANT_SOLID,
},
.projection = sconf->projection,
.view_alpha = sconf->view_alpha,
.unicolor = { 0.40, 0.0, 0.0, 1.0 },
};
struct weston_compositor *ec = ev->surface->compositor;
struct gl_renderer *gr = get_renderer(ec);
struct gl_surface_state *gs = get_surface_state(ev->surface);
bool recording_censor =
(output->disable_planes > 0) &&
@ -955,28 +940,56 @@ maybe_censor_override(struct weston_output *output,
(ev->surface->desired_protection > output->current_protection);
if (gs->direct_display) {
gs->color[0] = 0.40;
gs->color[1] = 0.0;
gs->color[2] = 0.0;
gs->color[3] = 1.0;
return gl_renderer_get_program(gr, &requirements_censor);
*sconf = alt;
return;
}
/* 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 gl_renderer_get_program(gr, &gs->shader_requirements);
return;
if (recording_censor || unprotected_censor)
*sconf = alt;
}
static void
gl_shader_config_set_input_textures(struct gl_shader_config *sconf,
struct gl_surface_state *gs)
{
int i;
sconf->req.variant = gs->shader_requirements.variant;
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 gl_renderer_get_program(gr, &requirements_censor);
for (i = 0; i < 4; i++)
sconf->unicolor[i] = gs->color[i];
assert(gs->num_textures <= GL_SHADER_INPUT_TEX_MAX);
for (i = 0; i < gs->num_textures; i++)
sconf->input_tex[i] = gs->textures[i];
for (; i < GL_SHADER_INPUT_TEX_MAX; i++)
sconf->input_tex[i] = 0;
}
return gl_renderer_get_program(gr, &gs->shader_requirements);
static bool
gl_shader_config_init_for_view(struct gl_shader_config *sconf,
struct weston_view *view,
struct weston_output *output,
GLint filter)
{
struct gl_surface_state *gs = get_surface_state(view->surface);
struct gl_output_state *go = get_output_state(output);
*sconf = (struct gl_shader_config) {
.projection = go->output_matrix,
.view_alpha = view->alpha,
.input_tex_filter = filter,
};
gl_shader_config_set_input_textures(sconf, gs);
return true;
}
static void
@ -993,8 +1006,7 @@ draw_view(struct weston_view *ev, struct weston_output *output,
/* non-opaque region in surface coordinates: */
pixman_region32_t surface_blend;
GLint filter;
int i;
struct gl_shader *shader;
struct gl_shader_config sconf;
/* 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
@ -1016,30 +1028,14 @@ draw_view(struct weston_view *ev, struct weston_output *output,
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) {
shader = gl_renderer_get_program(gr,
&requirements_triangle_fan);
gl_renderer_use_program_with_view_uniforms(gr, &shader,
ev, output);
}
if (ev->transform.enabled || output->zoom.active ||
output->current_scale != ev->surface->buffer_viewport.buffer.scale)
filter = GL_LINEAR;
else
filter = GL_NEAREST;
for (i = 0; i < gs->num_textures; i++) {
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(gs->target, gs->textures[i]);
glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, filter);
glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, filter);
}
if (!gl_shader_config_init_for_view(&sconf, ev, output, filter))
goto out;
/* blended region is whole surface minus opaque region: */
pixman_region32_init_rect(&surface_blend, 0, 0,
@ -1059,25 +1055,18 @@ 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);
maybe_censor_override(&sconf, output, ev);
if (pixman_region32_not_empty(&surface_opaque)) {
if (shader->key.variant == SHADER_VARIANT_RGBA) {
struct gl_shader_requirements tmp_requirements;
struct gl_shader *tmp_shader;
struct gl_shader_config alt = sconf;
if (alt.req.variant == SHADER_VARIANT_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.
*/
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);
alt.req.variant = SHADER_VARIANT_RGBX;
}
if (ev->alpha < 1.0)
@ -1085,14 +1074,13 @@ draw_view(struct weston_view *ev, struct weston_output *output,
else
glDisable(GL_BLEND);
repaint_region(gr, ev, &repaint, &surface_opaque);
repaint_region(gr, ev, &repaint, &surface_opaque, &alt);
gs->used_in_output_repaint = true;
}
if (pixman_region32_not_empty(&surface_blend)) {
gl_renderer_use_program(gr, &shader);
glEnable(GL_BLEND);
repaint_region(gr, ev, &repaint, &surface_blend);
repaint_region(gr, ev, &repaint, &surface_blend, &sconf);
gs->used_in_output_repaint = true;
}
@ -1182,7 +1170,9 @@ update_buffer_release_fences(struct weston_compositor *compositor,
}
static void
draw_output_border_texture(struct gl_output_state *go,
draw_output_border_texture(struct gl_renderer *gr,
struct gl_output_state *go,
struct gl_shader_config *sconf,
enum gl_renderer_border_side side,
int32_t x, int32_t y,
int32_t width, int32_t height)
@ -1207,10 +1197,6 @@ draw_output_border_texture(struct gl_output_state *go,
GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,
GL_TEXTURE_MAG_FILTER, GL_NEAREST);
} else {
glBindTexture(GL_TEXTURE_2D, img->tex);
}
@ -1224,6 +1210,10 @@ draw_output_border_texture(struct gl_output_state *go,
GL_BGRA_EXT, GL_UNSIGNED_BYTE, img->data);
}
sconf->input_tex_filter = GL_NEAREST;
sconf->input_tex[0] = img->tex;
gl_renderer_use_program(gr, sconf);
GLfloat texcoord[] = {
0.0f, 0.0f,
(GLfloat)img->width / (GLfloat)img->tex_width, 0.0f,
@ -1264,14 +1254,15 @@ static void
draw_output_borders(struct weston_output *output,
enum gl_border_status border_status)
{
const struct gl_shader_requirements requirements_rgba = {
struct gl_shader_config sconf = {
.req = {
.variant = SHADER_VARIANT_RGBA,
},
.view_alpha = 1.0f,
};
struct gl_output_state *go = get_output_state(output);
struct gl_renderer *gr = get_renderer(output->compositor);
struct gl_border_image *top, *bottom, *left, *right;
struct gl_shader *shader;
struct weston_matrix matrix;
int full_width, full_height;
if (border_status == BORDER_STATUS_CLEAN)
@ -1286,35 +1277,30 @@ draw_output_borders(struct weston_output *output,
full_height = output->current_mode->height + top->height + bottom->height;
glDisable(GL_BLEND);
shader = gl_renderer_get_program(gr, &requirements_rgba);
if (!gl_renderer_use_program(gr, &shader))
return;
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);
weston_matrix_init(&sconf.projection);
weston_matrix_translate(&sconf.projection,
-full_width / 2.0, -full_height / 2.0, 0);
weston_matrix_scale(&sconf.projection,
2.0 / full_width, -2.0 / full_height, 1);
glUniform1i(shader->tex_uniforms[0], 0);
glUniform1f(shader->alpha_uniform, 1);
glActiveTexture(GL_TEXTURE0);
if (border_status & BORDER_TOP_DIRTY)
draw_output_border_texture(go, GL_RENDERER_BORDER_TOP,
draw_output_border_texture(gr, go, &sconf, GL_RENDERER_BORDER_TOP,
0, 0,
full_width, top->height);
if (border_status & BORDER_LEFT_DIRTY)
draw_output_border_texture(go, GL_RENDERER_BORDER_LEFT,
draw_output_border_texture(gr, go, &sconf, GL_RENDERER_BORDER_LEFT,
0, top->height,
left->width, output->current_mode->height);
if (border_status & BORDER_RIGHT_DIRTY)
draw_output_border_texture(go, GL_RENDERER_BORDER_RIGHT,
draw_output_border_texture(gr, go, &sconf, GL_RENDERER_BORDER_RIGHT,
full_width - right->width, top->height,
right->width, output->current_mode->height);
if (border_status & BORDER_BOTTOM_DIRTY)
draw_output_border_texture(go, GL_RENDERER_BORDER_BOTTOM,
draw_output_border_texture(gr, go, &sconf, GL_RENDERER_BORDER_BOTTOM,
0, full_height - bottom->height,
full_width, bottom->height);
}
@ -1489,12 +1475,26 @@ static void
blit_shadow_to_output(struct weston_output *output,
pixman_region32_t *output_damage)
{
const struct gl_shader_requirements blit_requirements = {
struct gl_output_state *go = get_output_state(output);
const struct gl_shader_config sconf = {
.req = {
.variant = SHADER_VARIANT_RGBA,
},
.projection = {
.d = { /* transpose */
2.0f, 0.0f, 0.0f, 0.0f,
0.0f, 2.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 1.0f
},
.type = WESTON_MATRIX_TRANSFORM_SCALE |
WESTON_MATRIX_TRANSFORM_TRANSLATE,
},
.view_alpha = 1.0f,
.input_tex_filter = GL_NEAREST,
.input_tex[0] = go->shadow.tex,
};
struct gl_output_state *go = get_output_state(output);
struct gl_renderer *gr = get_renderer(output->compositor);
struct gl_shader *shader;
double width = output->current_mode->width;
double height = output->current_mode->height;
pixman_box32_t *rects;
@ -1502,26 +1502,11 @@ blit_shadow_to_output(struct weston_output *output,
int i;
pixman_region32_t translated_damage;
GLfloat verts[4 * 2];
static const GLfloat proj[16] = { /* transpose */
2.0f, 0.0f, 0.0f, 0.0f,
0.0f, 2.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 0.0f, 1.0f
};
pixman_region32_init(&translated_damage);
shader = gl_renderer_get_program(gr, &blit_requirements);
if (!gl_renderer_use_program(gr, &shader))
return;
glUniformMatrix4fv(shader->proj_uniform, 1, GL_FALSE, proj);
glUniform1f(shader->alpha_uniform, 1.0f);
glUniform1i(shader->tex_uniforms[0], 0);
gl_renderer_use_program(gr, &sconf);
glDisable(GL_BLEND);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, go->shadow.tex);
/* output_damage is in global coordinates */
pixman_region32_intersect(&translated_damage, output_damage,
@ -2927,18 +2912,20 @@ gl_renderer_surface_copy_content(struct weston_surface *surface,
0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f
};
struct gl_shader_config sconf = {
.view_alpha = 1.0f,
.input_tex_filter = GL_NEAREST,
};
const pixman_format_code_t format = PIXMAN_a8b8g8r8;
const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
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;
GLenum status;
const GLfloat *proj;
int i;
int ret = -1;
gl_renderer_surface_get_content_size(surface, &cw, &ch);
@ -2955,9 +2942,7 @@ 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;
gl_shader_config_set_input_textures(&sconf, gs);
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &tex);
@ -2974,29 +2959,20 @@ gl_renderer_surface_copy_content(struct weston_surface *surface,
status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
weston_log("%s: fbo error: %#x\n", __func__, status);
glDeleteFramebuffers(1, &fbo);
glDeleteTextures(1, &tex);
return -1;
goto out;
}
glViewport(0, 0, cw, ch);
glDisable(GL_BLEND);
if (gs->y_inverted)
proj = projmat_normal;
memcpy(sconf.projection.d, projmat_normal, sizeof projmat_normal);
else
proj = projmat_yinvert;
memcpy(sconf.projection.d, projmat_yinvert, sizeof projmat_yinvert);
sconf.projection.type = WESTON_MATRIX_TRANSFORM_SCALE |
WESTON_MATRIX_TRANSFORM_TRANSLATE;
glUniformMatrix4fv(shader->proj_uniform, 1, GL_FALSE, proj);
glUniform1f(shader->alpha_uniform, 1.0f);
for (i = 0; i < gs->num_textures; i++) {
glUniform1i(shader->tex_uniforms[i], i);
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(gs->target, gs->textures[i]);
glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
}
if (!gl_renderer_use_program(gr, &sconf))
goto out;
/* position: */
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
@ -3014,11 +2990,13 @@ gl_renderer_surface_copy_content(struct weston_surface *surface,
glPixelStorei(GL_PACK_ALIGNMENT, bytespp);
glReadPixels(src_x, src_y, width, height, gl_format,
GL_UNSIGNED_BYTE, target);
ret = 0;
out:
glDeleteFramebuffers(1, &fbo);
glDeleteTextures(1, &tex);
return 0;
return ret;
}
static void

@ -50,6 +50,18 @@
/* static const char fragment_shader[]; fragment.glsl */
#include "fragment-shader.h"
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;
struct wl_list link; /* gl_renderer::shader_list */
struct timespec last_used;
};
static const char *
gl_shader_texture_variant_to_string(enum gl_shader_texture_variant v)
{
@ -354,7 +366,7 @@ gl_renderer_create_fallback_shader(struct gl_renderer *gr)
return shader;
}
struct gl_shader *
static struct gl_shader *
gl_renderer_get_program(struct gl_renderer *gr,
const struct gl_shader_requirements *requirements)
{
@ -379,7 +391,6 @@ gl_renderer_get_program(struct gl_renderer *gr,
if (shader)
return shader;
weston_log("warning: failed to generate gl program\n");
return NULL;
}
@ -404,26 +415,61 @@ gl_renderer_garbage_collect_programs(struct gl_renderer *gr)
}
}
GLenum
gl_shader_texture_variant_get_target(enum gl_shader_texture_variant v)
{
if (v == SHADER_VARIANT_EXTERNAL)
return GL_TEXTURE_EXTERNAL_OES;
else
return GL_TEXTURE_2D;
}
static void
gl_shader_load_config(struct gl_shader *shader,
const struct gl_shader_config *sconf)
{
GLint in_filter = sconf->input_tex_filter;
GLenum in_tgt;
int i;
glUniformMatrix4fv(shader->proj_uniform,
1, GL_FALSE, sconf->projection.d);
glUniform4fv(shader->color_uniform, 1, sconf->unicolor);
glUniform1f(shader->alpha_uniform, sconf->view_alpha);
in_tgt = gl_shader_texture_variant_get_target(sconf->req.variant);
for (i = 0; i < GL_SHADER_INPUT_TEX_MAX; i++) {
if (sconf->input_tex[i] == 0)
continue;
assert(shader->tex_uniforms[i] != -1);
glUniform1i(shader->tex_uniforms[i], i);
glActiveTexture(GL_TEXTURE0 + i);
glBindTexture(in_tgt, sconf->input_tex[i]);
glTexParameteri(in_tgt, GL_TEXTURE_MIN_FILTER, in_filter);
glTexParameteri(in_tgt, GL_TEXTURE_MAG_FILTER, in_filter);
}
}
bool
gl_renderer_use_program(struct gl_renderer *gr, struct gl_shader **shaderp)
gl_renderer_use_program(struct gl_renderer *gr,
const struct gl_shader_config *sconf)
{
static const GLfloat fallback_shader_color[4] = { 0.2, 0.1, 0.0, 1.0 };
struct gl_shader *shader = *shaderp;
struct gl_shader *shader;
shader = gl_renderer_get_program(gr, &sconf->req);
if (!shader) {
weston_log("Error: trying to use NULL GL shader.\n");
weston_log("Error: failed to generate shader program.\n");
gr->current_shader = NULL;
shader = gr->fallback_shader;
glUseProgram(shader->program);
glUniform4fv(shader->color_uniform, 1, fallback_shader_color);
glUniform1f(shader->alpha_uniform, 1.0f);
*shaderp = shader;
return false;
}
if (gr->current_shader == shader)
return true;
if (shader != gr->fallback_shader) {
/* Update list order for most recently used. */
wl_list_remove(&shader->link);
@ -431,7 +477,12 @@ gl_renderer_use_program(struct gl_renderer *gr, struct gl_shader **shaderp)
}
shader->last_used = gr->compositor->last_repaint_start;
if (gr->current_shader != shader) {
glUseProgram(shader->program);
gr->current_shader = shader;
}
gl_shader_load_config(shader, sconf);
return true;
}

Loading…
Cancel
Save