Skip to content

Commit a7bd48f

Browse files
tryone144yshui
authored andcommitted
gl_common: set glViewport() to maximum supported size
- Query maximum supported dimensions of `glViewport()` when initializing so we don't have to worry about differently sized textures when rendering (usually the same as the maximum supported texture size, but dependend on the driver). - Set projection matrix in all shaders at startup to queried viewport dimensions. Allows using screen coordinates for all vertex positions without having to keep track of framebuffer dimensions. - Follow recommendations and set `glViewport()` to queried maximum dimensions for each draw call (`glDraw*()`, `glClear()`). Related: #349
1 parent 7043b2d commit a7bd48f

File tree

2 files changed

+69
-59
lines changed

2 files changed

+69
-59
lines changed

src/backend/gl/gl_common.c

Lines changed: 66 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,6 @@ _gl_average_texture_color(backend_t *base, GLuint source_texture, GLuint destina
207207
const int to_width = from_width > max_width ? from_width / 2 : from_width;
208208
const int to_height = from_height > max_height ? from_height / 2 : from_height;
209209

210-
glViewport(0, 0, width, height);
211-
212210
// Prepare coordinates
213211
GLint coord[] = {
214212
// top left
@@ -238,6 +236,7 @@ _gl_average_texture_color(backend_t *base, GLuint source_texture, GLuint destina
238236
glBindTexture(GL_TEXTURE_2D, source_texture);
239237

240238
// Render into framebuffer
239+
glViewport(0, 0, width, height);
241240
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL);
242241

243242
// Have we downscaled enough?
@@ -395,7 +394,6 @@ static void _gl_compose(backend_t *base, struct gl_image *img, GLuint target,
395394
// x, y, width, height, dx, dy, ptex->width, ptex->height, z);
396395

397396
// Bind texture
398-
glViewport(0, 0, gd->width, gd->height);
399397
glActiveTexture(GL_TEXTURE1);
400398
glBindTexture(GL_TEXTURE_2D, brightness);
401399
glActiveTexture(GL_TEXTURE0);
@@ -419,6 +417,7 @@ static void _gl_compose(backend_t *base, struct gl_image *img, GLuint target,
419417
glVertexAttribPointer(vert_in_texcoord_loc, 2, GL_INT, GL_FALSE,
420418
sizeof(GLint) * 4, (void *)(sizeof(GLint) * 2));
421419
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target);
420+
glViewport(0, 0, gd->vp_width, gd->vp_height);
422421
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
423422
glDisableVertexAttribArray(vert_coord_loc);
424423
glDisableVertexAttribArray(vert_in_texcoord_loc);
@@ -556,33 +555,6 @@ bool gl_blur(backend_t *base, double opacity, void *ctx, const region_t *reg_blu
556555
glBindTexture(GL_TEXTURE_2D, bctx->blur_texture[1]);
557556
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, bctx->texture_width,
558557
bctx->texture_height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
559-
560-
// XXX: do we need projection matrix for blur at all?
561-
// Note: OpenGL matrices are column major
562-
GLfloat projection_matrix[4][4] = {
563-
{2.0f / (GLfloat)bctx->texture_width, 0, 0, 0},
564-
{0, 2.0f / (GLfloat)bctx->texture_height, 0, 0},
565-
{0, 0, 0, 0},
566-
{-1, -1, 0, 1}};
567-
568-
// Update projection matrices in the blur shaders
569-
for (int i = 0; i < bctx->npasses - 1; i++) {
570-
assert(bctx->blur_shader[i].prog);
571-
glUseProgram(bctx->blur_shader[i].prog);
572-
int pml = glGetUniformLocationChecked(bctx->blur_shader[i].prog,
573-
"projection");
574-
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
575-
}
576-
577-
GLfloat projection_matrix2[4][4] = {{2.0f / (GLfloat)gd->width, 0, 0, 0},
578-
{0, 2.0f / (GLfloat)gd->height, 0, 0},
579-
{0, 0, 0, 0},
580-
{-1, -1, 0, 1}};
581-
assert(bctx->blur_shader[bctx->npasses - 1].prog);
582-
glUseProgram(bctx->blur_shader[bctx->npasses - 1].prog);
583-
int pml = glGetUniformLocationChecked(
584-
bctx->blur_shader[bctx->npasses - 1].prog, "projection");
585-
glUniformMatrix4fv(pml, 1, false, projection_matrix2[0]);
586558
}
587559

588560
// Remainder: regions are in Xorg coordinates
@@ -689,18 +661,17 @@ bool gl_blur(backend_t *base, double opacity, void *ctx, const region_t *reg_blu
689661
// translate the render origin so we don't need a big texture
690662
glUniform2f(p->orig_loc, -(GLfloat)extent_resized->x1,
691663
-(GLfloat)dst_y_resized_fb_coord);
692-
glViewport(0, 0, bctx->texture_width, bctx->texture_height);
693664
} else {
694665
// last pass, draw directly into the back buffer, with origin
695666
// regions
696667
glBindVertexArray(vao[0]);
697668
glBindFramebuffer(GL_FRAMEBUFFER, gd->back_fbo);
698669
glUniform1f(p->unifm_opacity, (float)opacity);
699670
glUniform2f(p->orig_loc, 0, 0);
700-
glViewport(0, 0, gd->width, gd->height);
701671
}
702672

703673
glUniform2f(p->texorig_loc, (GLfloat)texorig_x, (GLfloat)texorig_y);
674+
glViewport(0, 0, gd->vp_width, gd->vp_height);
704675
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
705676

706677
// XXX use multiple draw calls is probably going to be slow than
@@ -782,29 +753,8 @@ void gl_resize(struct gl_data *gd, int width, int height) {
782753
gd->height = height;
783754
gd->width = width;
784755

785-
// XXX: do we need projection matrix at all?
786-
// Note: OpenGL matrices are column major
787-
GLfloat projection_matrix[4][4] = {{2.0f / (GLfloat)width, 0, 0, 0},
788-
{0, 2.0f / (GLfloat)height, 0, 0},
789-
{0, 0, 0, 0},
790-
{-1, -1, 0, 1}};
791-
792-
// Update projection matrix in the win shader
793-
glUseProgram(gd->win_shader.prog);
794-
int pml = glGetUniformLocationChecked(gd->win_shader.prog, "projection");
795-
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
796-
797-
glUseProgram(gd->fill_shader.prog);
798-
pml = glGetUniformLocationChecked(gd->fill_shader.prog, "projection");
799-
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
800-
801-
glUseProgram(gd->present_prog);
802-
pml = glGetUniformLocationChecked(gd->present_prog, "projection");
803-
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
804-
805-
glUseProgram(gd->brightness_shader.prog);
806-
pml = glGetUniformLocationChecked(gd->brightness_shader.prog, "projection");
807-
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
756+
assert(gd->vp_width >= gd->width);
757+
assert(gd->vp_height >= gd->height);
808758

809759
glBindTexture(GL_TEXTURE_2D, gd->back_texture);
810760
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width, height, 0, GL_BGR,
@@ -903,7 +853,10 @@ static void _gl_fill(backend_t *base, struct color c, const region_t *clip, GLui
903853
glVertexAttribPointer(fill_vert_in_coord_loc, 2, GL_INT, GL_FALSE,
904854
sizeof(*coord) * 2, (void *)0);
905855
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target);
856+
857+
glViewport(0, 0, gd->vp_width, gd->vp_height);
906858
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
859+
907860
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
908861
glBindBuffer(GL_ARRAY_BUFFER, 0);
909862
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
@@ -1004,6 +957,14 @@ void *gl_create_blur_context(backend_t *base, enum blur_method method, void *arg
1004957
return ctx;
1005958
}
1006959

960+
// Set projection matrix to gl viewport dimensions so we can use screen
961+
// coordinates for all vertices
962+
// Note: OpenGL matrices are column major
963+
GLfloat projection_matrix[4][4] = {{2.0f / (GLfloat)gd->vp_width, 0, 0, 0},
964+
{0, 2.0f / (GLfloat)gd->vp_height, 0, 0},
965+
{0, 0, 0, 0},
966+
{-1, -1, 0, 1}};
967+
1007968
ctx->blur_shader = ccalloc(max2(2, nkernels), gl_blur_shader_t);
1008969

1009970
char *lc_numeric_old = strdup(setlocale(LC_NUMERIC, NULL));
@@ -1083,6 +1044,13 @@ void *gl_create_blur_context(backend_t *base, enum blur_method method, void *arg
10831044
pass->unifm_opacity = glGetUniformLocationChecked(pass->prog, "opacity");
10841045
pass->orig_loc = glGetUniformLocationChecked(pass->prog, "orig");
10851046
pass->texorig_loc = glGetUniformLocationChecked(pass->prog, "texorig");
1047+
1048+
// Setup projection matrix
1049+
glUseProgram(pass->prog);
1050+
int pml = glGetUniformLocationChecked(pass->prog, "projection");
1051+
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
1052+
glUseProgram(0);
1053+
10861054
ctx->resize_width += kern->w / 2;
10871055
ctx->resize_height += kern->h / 2;
10881056
}
@@ -1095,6 +1063,13 @@ void *gl_create_blur_context(backend_t *base, enum blur_method method, void *arg
10951063
pass->unifm_opacity = -1;
10961064
pass->orig_loc = glGetUniformLocationChecked(pass->prog, "orig");
10971065
pass->texorig_loc = glGetUniformLocationChecked(pass->prog, "texorig");
1066+
1067+
// Setup projection matrix
1068+
glUseProgram(pass->prog);
1069+
int pml = glGetUniformLocationChecked(pass->prog, "projection");
1070+
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
1071+
glUseProgram(0);
1072+
10981073
ctx->npasses = 2;
10991074
} else {
11001075
ctx->npasses = nkernels;
@@ -1200,7 +1175,17 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
12001175
glStencilMask(0x1);
12011176
glStencilFunc(GL_EQUAL, 0x1, 0x1);
12021177

1178+
// Set gl viewport to the maximum supported size so we won't have to worry about
1179+
// it later on when the screen is resized. The corresponding projection matrix can
1180+
// be set now and won't have to be updated. Since fragments outside the target
1181+
// buffer are skipped anyways, this should have no impact on performance.
1182+
GLint viewport_dimensions[2];
1183+
glGetIntegerv(GL_MAX_VIEWPORT_DIMS, viewport_dimensions);
1184+
gd->vp_height = viewport_dimensions[0];
1185+
gd->vp_width = viewport_dimensions[1];
1186+
12031187
// Clear screen
1188+
glViewport(0, 0, gd->vp_height, gd->vp_width);
12041189
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
12051190
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
12061191

@@ -1216,17 +1201,37 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
12161201
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
12171202
glBindTexture(GL_TEXTURE_2D, 0);
12181203

1204+
// Set projection matrix to gl viewport dimensions so we can use screen
1205+
// coordinates for all vertices
1206+
// Note: OpenGL matrices are column major
1207+
GLfloat projection_matrix[4][4] = {{2.0f / (GLfloat)gd->vp_width, 0, 0, 0},
1208+
{0, 2.0f / (GLfloat)gd->vp_height, 0, 0},
1209+
{0, 0, 0, 0},
1210+
{-1, -1, 0, 1}};
1211+
1212+
// Initialize shaders
12191213
gl_win_shader_from_string(vertex_shader, win_shader_glsl, &gd->win_shader);
1214+
int pml = glGetUniformLocationChecked(gd->win_shader.prog, "projection");
1215+
glUseProgram(gd->win_shader.prog);
1216+
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
1217+
glUseProgram(0);
1218+
12201219
gd->fill_shader.prog = gl_create_program_from_str(fill_vert, fill_frag);
12211220
gd->fill_shader.color_loc = glGetUniformLocation(gd->fill_shader.prog, "color");
1221+
pml = glGetUniformLocationChecked(gd->fill_shader.prog, "projection");
1222+
glUseProgram(gd->fill_shader.prog);
1223+
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
1224+
glUseProgram(0);
12221225

12231226
gd->present_prog = gl_create_program_from_str(present_vertex_shader, dummy_frag);
12241227
if (!gd->present_prog) {
12251228
log_error("Failed to create the present shader");
12261229
return false;
12271230
}
1231+
pml = glGetUniformLocationChecked(gd->present_prog, "projection");
12281232
glUseProgram(gd->present_prog);
12291233
glUniform1i(glGetUniformLocationChecked(gd->present_prog, "tex"), 0);
1234+
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
12301235
glUseProgram(0);
12311236

12321237
gd->brightness_shader.prog =
@@ -1235,12 +1240,13 @@ bool gl_init(struct gl_data *gd, session_t *ps) {
12351240
log_error("Failed to create the brightness shader");
12361241
return false;
12371242
}
1243+
pml = glGetUniformLocationChecked(gd->brightness_shader.prog, "projection");
12381244
glUseProgram(gd->brightness_shader.prog);
12391245
glUniform1i(glGetUniformLocationChecked(gd->brightness_shader.prog, "tex"), 0);
1246+
glUniformMatrix4fv(pml, 1, false, projection_matrix[0]);
12401247
glUseProgram(0);
12411248

1242-
// Set up the size of the viewport. We do this last because it expects the blur
1243-
// textures are already set up.
1249+
// Set up the size of the back texture
12441250
gl_resize(gd, ps->root_width, ps->root_height);
12451251

12461252
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gd->back_fbo);
@@ -1320,6 +1326,8 @@ static inline void gl_image_decouple(backend_t *base, struct gl_image *img) {
13201326
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
13211327
new_tex->texture, 0);
13221328
glDrawBuffer(GL_COLOR_ATTACHMENT0);
1329+
1330+
glViewport(0, 0, gd->vp_height, gd->vp_width);
13231331
glClearColor(0, 0, 0, 0);
13241332
glClear(GL_COLOR_BUFFER_BIT);
13251333

@@ -1395,7 +1403,6 @@ void gl_present(backend_t *base, const region_t *region) {
13951403
sizeof(GLuint) * 6);
13961404
}
13971405

1398-
glViewport(0, 0, gd->width, gd->height);
13991406
glUseProgram(gd->present_prog);
14001407
glBindTexture(GL_TEXTURE_2D, gd->back_texture);
14011408

@@ -1413,6 +1420,7 @@ void gl_present(backend_t *base, const region_t *region) {
14131420
GL_STREAM_DRAW);
14141421

14151422
glVertexAttribPointer(vert_coord_loc, 2, GL_INT, GL_FALSE, sizeof(GLint) * 2, NULL);
1423+
glViewport(0, 0, gd->vp_width, gd->vp_height);
14161424
glDrawElements(GL_TRIANGLES, nrects * 6, GL_UNSIGNED_INT, NULL);
14171425

14181426
glBindBuffer(GL_ARRAY_BUFFER, 0);

src/backend/gl/gl_common.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,10 @@ struct gl_data {
6868
backend_t base;
6969
// If we are using proprietary NVIDIA driver
7070
bool is_nvidia;
71-
// Height and width of the viewport
71+
// Height and width of the root window
7272
int height, width;
73+
// Height and width of the gl viewport
74+
int vp_height, vp_width;
7375
gl_win_shader_t win_shader;
7476
gl_brightness_shader_t brightness_shader;
7577
gl_fill_shader_t fill_shader;

0 commit comments

Comments
 (0)