From 0f52da62263ed4af3bdf5b813b1d050d6914e772 Mon Sep 17 00:00:00 2001 From: Pekka Paalanen Date: Thu, 18 Mar 2021 17:42:06 +0200 Subject: [PATCH] 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 Signed-off-by: Pekka Paalanen --- libweston/renderer-gl/gl-renderer-internal.h | 31 +- libweston/renderer-gl/gl-renderer.c | 306 +++++++++---------- libweston/renderer-gl/gl-shaders.c | 73 ++++- 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; }