gl-renderer: Derive texcoords from position in the vertex shader

Let the graphics hardware handle the transformation from surface
position to texture coordinates. Paint nodes now have a single vertex
position attribute from which texture coordinates are derived. A new
vertex shader variant handles the transformation.

Signed-off-by: Loïc Molinari <loic.molinari@gmail.com>
This commit is contained in:
Loïc Molinari 2023-02-15 14:38:32 +01:00 committed by Pekka Paalanen
parent a4d31fa8bd
commit bcd04e0fad
4 changed files with 87 additions and 35 deletions

View File

@ -38,6 +38,12 @@
#include "shared/weston-egl-ext.h" /* for PFN* stuff */
#include "shared/helpers.h"
/* Keep the following in sync with vertex.glsl. */
enum gl_shader_texcoord_input {
SHADER_TEXCOORD_INPUT_ATTRIB = 0,
SHADER_TEXCOORD_INPUT_SURFACE,
};
enum gl_shader_texture_variant {
SHADER_VARIANT_NONE = 0,
/* Keep the following in sync with fragment.glsl. */
@ -75,6 +81,8 @@ enum gl_shader_color_mapping {
*/
struct gl_shader_requirements
{
unsigned texcoord_input:1; /* enum gl_shader_texcoord_input */
unsigned variant:4; /* enum gl_shader_texture_variant */
bool input_is_premult:1;
bool green_tint:1;
@ -86,7 +94,7 @@ struct gl_shader_requirements
* 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_:22;
unsigned pad_bits_:21;
};
static_assert(sizeof(struct gl_shader_requirements) ==
4 /* total bitfield size in bytes */,
@ -100,6 +108,7 @@ struct gl_shader_config {
struct gl_shader_requirements req;
struct weston_matrix projection;
struct weston_matrix surface_to_buffer;
float view_alpha;
GLfloat unicolor[4];
GLint input_tex_filter; /* GL_NEAREST or GL_LINEAR */

View File

@ -569,12 +569,10 @@ texture_region(struct weston_paint_node *pnode,
pixman_region32_t *region,
pixman_region32_t *surf_region)
{
struct gl_surface_state *gs = get_surface_state(pnode->surface);
struct weston_buffer *buffer = gs->buffer_ref.buffer;
struct weston_compositor *ec = pnode->surface->compositor;
struct weston_view *ev = pnode->view;
struct gl_renderer *gr = get_renderer(ec);
GLfloat *v, inv_width, inv_height;
GLfloat *v;
unsigned int *vtxcnt, nvtx = 0;
pixman_box32_t *rects, *surf_rects;
pixman_box32_t *raw_rects;
@ -596,12 +594,9 @@ texture_region(struct weston_paint_node *pnode,
/* worst case we can have 8 vertices per rect (ie. clipped into
* an octagon):
*/
v = wl_array_add(&gr->vertices, nrects * nsurf * 8 * 4 * sizeof *v);
v = wl_array_add(&gr->vertices, nrects * nsurf * 8 * 2 * sizeof *v);
vtxcnt = wl_array_add(&gr->vtxcnt, nrects * nsurf * sizeof *vtxcnt);
inv_width = 1.0 / buffer->width;
inv_height = 1.0 / buffer->height;
for (i = 0; i < nrects; i++) {
rect_to_quad(&rects[i], ev, &quad);
for (j = 0; j < nsurf; j++) {
@ -627,23 +622,8 @@ texture_region(struct weston_paint_node *pnode,
/* emit edge points: */
for (k = 0; k < n; k++) {
struct weston_coord_surface pos_s;
struct weston_coord_buffer pos_b;
/* position: */
*(v++) = e[k].x;
*(v++) = e[k].y;
/* texcoord: */
pos_s = weston_coord_surface(e[k].x, e[k].y, ev->surface);
pos_b = weston_coord_surface_to_buffer(ev->surface, pos_s);
*(v++) = pos_b.c.x * inv_width;
if (buffer->buffer_origin == ORIGIN_TOP_LEFT) {
*(v++) = pos_b.c.y * inv_height;
} else {
*(v++) = (buffer->height - pos_b.c.y) * inv_height;
}
}
vtxcnt[nvtx++] = n;
@ -1065,9 +1045,7 @@ repaint_region(struct gl_renderer *gr,
vtxcnt = gr->vtxcnt.data;
/* position: */
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
/* texcoord: */
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof *v, v);
if (!gl_renderer_use_program(gr, sconf)) {
gl_renderer_send_shader_error(pnode);
@ -1264,18 +1242,33 @@ gl_shader_config_init_for_paint_node(struct gl_shader_config *sconf,
{
struct gl_surface_state *gs = get_surface_state(pnode->surface);
struct gl_output_state *go = get_output_state(pnode->output);
struct weston_buffer *buffer = gs->buffer_ref.buffer;
if (!pnode->surf_xform_valid)
return false;
*sconf = (struct gl_shader_config) {
.req.texcoord_input = SHADER_TEXCOORD_INPUT_SURFACE,
.projection = pnode->view->transform.matrix,
.surface_to_buffer =
pnode->view->surface->surface_to_buffer_matrix,
.view_alpha = pnode->view->alpha,
.input_tex_filter = filter,
};
weston_matrix_multiply(&sconf->projection, &go->output_matrix);
if (buffer->buffer_origin == ORIGIN_TOP_LEFT) {
weston_matrix_scale(&sconf->surface_to_buffer,
1.0f / buffer->width,
1.0f / buffer->height, 1);
} else {
weston_matrix_scale(&sconf->surface_to_buffer,
1.0f / buffer->width,
-1.0f / buffer->height, 1);
weston_matrix_translate(&sconf->surface_to_buffer, 0, 1, 0);
}
gl_shader_config_set_input_textures(sconf, gs);
if (!gl_shader_config_set_color_transform(sconf, pnode->surf_xform.transform)) {
@ -1387,9 +1380,7 @@ repaint_views(struct weston_output *output, pixman_region32_t *damage)
struct weston_paint_node *pnode;
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
wl_list_for_each_reverse(pnode, &output->paint_node_z_order_list,
z_order_link) {
@ -1397,7 +1388,6 @@ repaint_views(struct weston_output *output, pixman_region32_t *damage)
draw_paint_node(pnode, damage);
}
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(0);
}

View File

@ -56,6 +56,7 @@ struct gl_shader {
GLuint program;
GLuint vertex_shader, fragment_shader;
GLint proj_uniform;
GLint surface_to_buffer_uniform;
GLint tex_uniforms[3];
GLint view_alpha_uniform;
GLint color_uniform;
@ -74,6 +75,19 @@ struct gl_shader {
struct timespec last_used;
};
static const char *
gl_shader_texcoord_input_to_string(enum gl_shader_texcoord_input kind)
{
switch (kind) {
#define CASERET(x) case x: return #x;
CASERET(SHADER_TEXCOORD_INPUT_SURFACE)
CASERET(SHADER_TEXCOORD_INPUT_ATTRIB)
#undef CASERET
}
return "!?!?"; /* never reached */
}
static const char *
gl_shader_texture_variant_to_string(enum gl_shader_texture_variant v)
{
@ -186,7 +200,8 @@ create_shader_description_string(const struct gl_shader_requirements *req)
int size;
char *str;
size = asprintf(&str, "%s %s %s %s %cinput_is_premult %cgreen",
size = asprintf(&str, "%s %s %s %s %s %cinput_is_premult %cgreen",
gl_shader_texcoord_input_to_string(req->variant),
gl_shader_texture_variant_to_string(req->variant),
gl_shader_color_curve_to_string(req->color_pre_curve),
gl_shader_color_mapping_to_string(req->color_mapping),
@ -199,7 +214,21 @@ create_shader_description_string(const struct gl_shader_requirements *req)
}
static char *
create_shader_config_string(const struct gl_shader_requirements *req)
create_vertex_shader_config_string(const struct gl_shader_requirements *req)
{
int size;
char *str;
size = asprintf(&str,
"#define DEF_TEXCOORD_INPUT %s\n",
gl_shader_texcoord_input_to_string(req->texcoord_input));
if (size < 0)
return NULL;
return str;
}
static char *
create_fragment_shader_config_string(const struct gl_shader_requirements *req)
{
int size;
char *str;
@ -252,12 +281,18 @@ gl_shader_create(struct gl_renderer *gr,
free(desc);
}
sources[0] = vertex_shader;
shader->vertex_shader = compile_shader(GL_VERTEX_SHADER, 1, sources);
conf = create_vertex_shader_config_string(&shader->key);
if (!conf)
goto error_vertex;
sources[0] = conf;
sources[1] = vertex_shader;
shader->vertex_shader = compile_shader(GL_VERTEX_SHADER, 2, sources);
if (shader->vertex_shader == GL_NONE)
goto error_vertex;
conf = create_shader_config_string(&shader->key);
free(conf);
conf = create_fragment_shader_config_string(&shader->key);
if (!conf)
goto error_fragment;
@ -273,7 +308,8 @@ gl_shader_create(struct gl_renderer *gr,
glAttachShader(shader->program, shader->vertex_shader);
glAttachShader(shader->program, shader->fragment_shader);
glBindAttribLocation(shader->program, 0, "position");
glBindAttribLocation(shader->program, 1, "texcoord");
if (requirements->texcoord_input == SHADER_TEXCOORD_INPUT_ATTRIB)
glBindAttribLocation(shader->program, 1, "texcoord");
glLinkProgram(shader->program);
glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
@ -287,6 +323,8 @@ gl_shader_create(struct gl_renderer *gr,
glDeleteShader(shader->fragment_shader);
shader->proj_uniform = glGetUniformLocation(shader->program, "proj");
shader->surface_to_buffer_uniform =
glGetUniformLocation(shader->program, "surface_to_buffer");
shader->tex_uniforms[0] = glGetUniformLocation(shader->program, "tex");
shader->tex_uniforms[1] = glGetUniformLocation(shader->program, "tex1");
shader->tex_uniforms[2] = glGetUniformLocation(shader->program, "tex2");
@ -540,6 +578,10 @@ gl_shader_load_config(struct gl_shader *shader,
glUniformMatrix4fv(shader->proj_uniform,
1, GL_FALSE, sconf->projection.d);
if (shader->surface_to_buffer_uniform != -1)
glUniformMatrix4fv(shader->surface_to_buffer_uniform,
1, GL_FALSE, sconf->surface_to_buffer.d);
if (shader->color_uniform != -1)
glUniform4fv(shader->color_uniform, 1, sconf->unicolor);

View File

@ -25,6 +25,10 @@
* SOFTWARE.
*/
/* enum gl_shader_texcoord_input */
#define SHADER_TEXCOORD_INPUT_ATTRIB 0
#define SHADER_TEXCOORD_INPUT_SURFACE 1
/* Always use high-precision for vertex calculations */
precision highp float;
@ -35,6 +39,8 @@ precision highp float;
#endif
uniform mat4 proj;
uniform mat4 surface_to_buffer;
attribute vec2 position;
attribute vec2 texcoord;
@ -44,5 +50,10 @@ varying FRAG_PRECISION vec2 v_texcoord;
void main()
{
gl_Position = proj * vec4(position, 0.0, 1.0);
#if DEF_TEXCOORD_INPUT == SHADER_TEXCOORD_INPUT_ATTRIB
v_texcoord = texcoord;
#elif DEF_TEXCOORD_INPUT == SHADER_TEXCOORD_INPUT_SURFACE
v_texcoord = vec2(surface_to_buffer * vec4(position, 0.0, 1.0));
#endif
}