summaryrefslogtreecommitdiff
path: root/libweston/renderer-gl
diff options
context:
space:
mode:
Diffstat (limited to 'libweston/renderer-gl')
-rw-r--r--libweston/renderer-gl/gl-renderer-internal.h31
-rw-r--r--libweston/renderer-gl/gl-renderer.c306
-rw-r--r--libweston/renderer-gl/gl-shaders.c73
3 files changed, 220 insertions, 190 deletions
diff --git a/libweston/renderer-gl/gl-renderer-internal.h b/libweston/renderer-gl/gl-renderer-internal.h
index 379bafa8..06904d5f 100644
--- a/libweston/renderer-gl/gl-renderer-internal.h
+++ b/libweston/renderer-gl/gl-renderer-internal.h
@@ -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);
diff --git a/libweston/renderer-gl/gl-renderer.c b/libweston/renderer-gl/gl-renderer.c
index b373942d..ee8027fc 100644
--- a/libweston/renderer-gl/gl-renderer.c
+++ b/libweston/renderer-gl/gl-renderer.c
@@ -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 = {
- .variant = SHADER_VARIANT_SOLID,
+ 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) {
- 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);
- }
+ 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;
+
+ for (i = 0; i < 4; i++)
+ sconf->unicolor[i] = gs->color[i];
- return gl_renderer_get_program(gr, &gs->shader_requirements);
+ 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;
+}
+
+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 = {
- .variant = SHADER_VARIANT_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 = {
- .variant = SHADER_VARIANT_RGBA,
- };
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_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;
-
- 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);
+ memcpy(sconf.projection.d, projmat_yinvert, sizeof projmat_yinvert);
+ sconf.projection.type = WESTON_MATRIX_TRANSFORM_SCALE |
+ WESTON_MATRIX_TRANSFORM_TRANSLATE;
- 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
diff --git a/libweston/renderer-gl/gl-shaders.c b/libweston/renderer-gl/gl-shaders.c
index e8108738..4468d578 100644
--- a/libweston/renderer-gl/gl-shaders.c
+++ b/libweston/renderer-gl/gl-shaders.c
@@ -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;
- glUseProgram(shader->program);
- gr->current_shader = shader;
+ if (gr->current_shader != shader) {
+ glUseProgram(shader->program);
+ gr->current_shader = shader;
+ }
+
+ gl_shader_load_config(shader, sconf);
+
return true;
}