This patch ignores the borders for now. Signed-off-by: Niels Ole Salscheider <niels_...@salscheider-online.de> --- src/gl-renderer.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 286 insertions(+), 23 deletions(-)
diff --git a/src/gl-renderer.c b/src/gl-renderer.c index b2dfbac..fe3aa4d 100644 --- a/src/gl-renderer.c +++ b/src/gl-renderer.c @@ -38,6 +38,8 @@ #include <EGL/eglext.h> #include "weston-egl-ext.h" +#include "colorcorrection-server-protocol.h" + struct gl_shader { GLuint program; GLuint vertex_shader, fragment_shader; @@ -74,6 +76,11 @@ struct gl_output_state { enum gl_border_status border_damage[BUFFER_DAMAGE_COUNT]; struct gl_border_image borders[4]; enum gl_border_status border_status; + + GLuint fb; + GLuint fb_texture; + GLuint fb_mask_texture; + GLuint lut; }; enum buffer_type { @@ -82,6 +89,11 @@ enum buffer_type { BUFFER_TYPE_EGL }; +enum draw_type { + DRAW_TYPE_NORMAL, + DRAW_TYPE_MASK +}; + struct gl_surface_state { GLfloat color[4]; struct gl_shader *shader; @@ -91,6 +103,8 @@ struct gl_surface_state { int needs_full_upload; pixman_region32_t texture_damage; + GLuint lut; + EGLImageKHR images[3]; GLenum target; int num_images; @@ -526,7 +540,8 @@ shader_uniforms(struct gl_shader *shader, static void draw_view(struct weston_view *ev, struct weston_output *output, - pixman_region32_t *damage) /* in global coordinates */ + pixman_region32_t *damage /* in global coordinates */, + enum draw_type type) { struct weston_compositor *ec = ev->surface->compositor; struct gl_renderer *gr = get_renderer(ec); @@ -559,9 +574,6 @@ draw_view(struct weston_view *ev, struct weston_output *output, shader_uniforms(&gr->solid_shader, ev, output); } - use_shader(gr, gs->shader); - shader_uniforms(gs->shader, ev, output); - if (ev->transform.enabled || output->zoom.active || output->current_scale != ev->surface->buffer_viewport.scale) filter = GL_LINEAR; @@ -575,6 +587,16 @@ draw_view(struct weston_view *ev, struct weston_output *output, glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, filter); } + /* Set LUT */ + if (gr->has_texture_3d && ev->surface->clut.data) { + glActiveTexture(GL_TEXTURE0 + i); + glBindTexture(GL_TEXTURE_3D_OES, gs->lut); + glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MIN_FILTER, + GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MAG_FILTER, + GL_LINEAR); + } + /* blended region is whole surface minus opaque region: */ pixman_region32_init_rect(&surface_blend, 0, 0, ev->surface->width, ev->surface->height); @@ -582,14 +604,34 @@ draw_view(struct weston_view *ev, struct weston_output *output, /* XXX: Should we be using ev->transform.opaque here? */ if (pixman_region32_not_empty(&ev->surface->opaque)) { - if (gs->shader == &gr->texture_shader_rgba) { + if (gs->shader == &gr->texture_shader_rgba || + gs->shader == &gr->texture_shader_rgba_lut) { /* 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. */ - use_shader(gr, &gr->texture_shader_rgbx); - shader_uniforms(&gr->texture_shader_rgbx, ev, output); + if (type == DRAW_TYPE_NORMAL) { + if (gs->shader == &gr->texture_shader_rgba) { + use_shader(gr, &gr->texture_shader_rgbx); + shader_uniforms(&gr->texture_shader_rgbx, + ev, output); + } else { + use_shader(gr, &gr->texture_shader_rgbx_lut); + shader_uniforms(&gr->texture_shader_rgbx_lut, + ev, output); + } + } else { + float r = ev->surface->color_profile_mode == + WL_COLORCORRECTION_MODE_UNCORRECTED ? + 1.0f : 0.0f; + use_shader(gr, &gr->solid_shader); + glUniformMatrix4fv(gr->solid_shader.proj_uniform, + 1, GL_FALSE, output->matrix.d); + glUniform4f(gr->solid_shader.color_uniform, + r, 0.0f, 0.0f, 1.0f); + glUniform1f(gr->solid_shader.alpha_uniform, 1.0f); + } } if (ev->alpha < 1.0) @@ -601,7 +643,20 @@ draw_view(struct weston_view *ev, struct weston_output *output, } if (pixman_region32_not_empty(&surface_blend)) { - use_shader(gr, gs->shader); + if (type == DRAW_TYPE_NORMAL) { + use_shader(gr, gs->shader); + shader_uniforms(gs->shader, ev, output); + } else { + float r = ev->surface->color_profile_mode == + WL_COLORCORRECTION_MODE_UNCORRECTED ? + 1.0f : 0.0f; + use_shader(gr, &gr->solid_shader); + glUniformMatrix4fv(gr->solid_shader.proj_uniform, + 1, GL_FALSE, output->matrix.d); + glUniform4f(gr->solid_shader.color_uniform, + r, 0.0f, 0.0f, 1.0f); + glUniform1f(gr->solid_shader.alpha_uniform, 1.0f); + } glEnable(GL_BLEND); repaint_region(ev, &repaint, &surface_blend); } @@ -613,14 +668,15 @@ out: } static void -repaint_views(struct weston_output *output, pixman_region32_t *damage) +repaint_views(struct weston_output *output, pixman_region32_t *damage, + enum draw_type type) { struct weston_compositor *compositor = output->compositor; struct weston_view *view; wl_list_for_each_reverse(view, &compositor->view_list, link) if (view->plane == &compositor->primary_plane) - draw_view(view, output, damage); + draw_view(view, output, damage, type); } static void @@ -706,11 +762,11 @@ output_has_borders(struct weston_output *output) static void draw_output_borders(struct weston_output *output, - enum gl_border_status border_status) + enum gl_border_status border_status, enum draw_type type) { struct gl_output_state *go = get_output_state(output); struct gl_renderer *gr = get_renderer(output->compositor); - struct gl_shader *shader = &gr->texture_shader_rgba; + struct gl_shader *shader; struct gl_border_image *top, *bottom, *left, *right; struct weston_matrix matrix; int full_width, full_height; @@ -718,6 +774,11 @@ draw_output_borders(struct weston_output *output, if (border_status == BORDER_STATUS_CLEAN) return; /* Clean. Nothing to do. */ + if (type == DRAW_TYPE_NORMAL) { + shader = &gr->texture_shader_rgba; + } else + shader = &gr->solid_shader; + top = &go->borders[GL_RENDERER_BORDER_TOP]; bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM]; left = &go->borders[GL_RENDERER_BORDER_LEFT]; @@ -738,6 +799,8 @@ draw_output_borders(struct weston_output *output, glUniform1i(shader->tex_uniforms[0], 0); glUniform1f(shader->alpha_uniform, 1); + if (type == DRAW_TYPE_MASK) + glUniform4f(shader->color_uniform, 1.0f, 0.0f, 0.0f, 1.0f); glActiveTexture(GL_TEXTURE0); if (border_status & BORDER_TOP_DIRTY) @@ -858,6 +921,103 @@ output_rotate_damage(struct weston_output *output, } static void +use_fb(struct weston_output *output, GLuint *texture) +{ + struct gl_output_state *go = get_output_state(output); + + if (!go->fb) + glGenFramebuffers(1, &go->fb); + glBindFramebuffer(GL_FRAMEBUFFER, go->fb); + + if (!*texture) + glGenTextures(1, texture); + glBindTexture(GL_TEXTURE_2D, *texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, output->width, + output->height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_NEAREST); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, *texture, 0); +} + +static int +draw_fb(struct weston_output *output) +{ + struct gl_output_state *go = get_output_state(output); + struct weston_compositor *compositor = output->compositor; + struct gl_renderer *gr = get_renderer(compositor); + + static GLushort indices [] = { 0, 1, 3, 2 }; + + GLfloat texcoord[] = { + 0.0f, 0.0f, + 1.0f, 0.0f, + 1.0f, 1.0f, + 0.0f, 1.0f, + }; + + GLfloat verts[] = { + output->x, output->y, + output->x + output->width, output->y, + output->x + output->width, output->y + output->height, + output->x, output->y + output->height + }; + + struct weston_matrix matrix; + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + use_shader(gr, &gr->fb_shader); + + glViewport(0, 0, output->width, output->height); + + weston_matrix_init(&matrix); + weston_matrix_translate(&matrix, + -(output->x + output->width / 2.0), + -(output->y + output->height / 2.0), 0); + weston_matrix_scale(&matrix, + 2.0 / output->width, + 2.0 / output->height, 1); + glUniformMatrix4fv(gr->fb_shader.proj_uniform, 1, GL_FALSE, matrix.d); + + glUniform1i(gr->fb_shader.tex_uniforms[0], 0); + glUniform1i(gr->fb_shader.tex_uniforms[1], 1); + glUniform1i(gr->fb_shader.lut_uniform, 2); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, go->fb_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, go->fb_mask_texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_3D_OES, go->lut); + glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, indices); + + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(0); + + return 0; +} + +static void +gl_renderer_attach_output_lut(struct weston_output *output); +static void gl_renderer_repaint_output(struct weston_output *output, pixman_region32_t *output_damage) { @@ -883,6 +1043,9 @@ gl_renderer_repaint_output(struct weston_output *output, if (use_output(output) < 0) return; + if (gr->has_texture_3d && output->clut.data) + use_fb(output, &go->fb_texture); + /* if debugging, redraw everything outside the damage to clean up * debug lines from the previous draw on this buffer: */ @@ -892,7 +1055,7 @@ gl_renderer_repaint_output(struct weston_output *output, pixman_region32_subtract(&undamaged, &output->region, output_damage); gr->fan_debug = 0; - repaint_views(output, &undamaged); + repaint_views(output, &undamaged, DRAW_TYPE_NORMAL); gr->fan_debug = 1; pixman_region32_fini(&undamaged); } @@ -906,14 +1069,24 @@ gl_renderer_repaint_output(struct weston_output *output, pixman_region32_union(&total_damage, &buffer_damage, output_damage); border_damage |= go->border_status; - repaint_views(output, &total_damage); + repaint_views(output, &total_damage, DRAW_TYPE_NORMAL); + draw_output_borders(output, border_damage, DRAW_TYPE_NORMAL); - pixman_region32_fini(&total_damage); - pixman_region32_fini(&buffer_damage); + if (gr->has_texture_3d && output->clut.data) { + use_fb(output, &go->fb_mask_texture); + glClear(GL_COLOR_BUFFER_BIT); + repaint_views(output, &total_damage, DRAW_TYPE_MASK); + draw_output_borders(output, border_damage, DRAW_TYPE_MASK); - draw_output_borders(output, border_damage); + gl_renderer_attach_output_lut(output); + if (draw_fb(output) < 0) + return; + } + pixman_region32_fini(&total_damage); + pixman_region32_fini(&buffer_damage); pixman_region32_copy(&output->previous_damage, output_damage); + wl_signal_emit(&output->frame_signal, output); #ifdef EGL_EXT_swap_buffers_with_damage @@ -1141,20 +1314,32 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer, switch (wl_shm_buffer_get_format(shm_buffer)) { case WL_SHM_FORMAT_XRGB8888: - gs->shader = &gr->texture_shader_rgbx; + if (gr->has_texture_3d && es->clut.data) + gs->shader = &gr->texture_shader_rgbx_lut; + else + gs->shader = &gr->texture_shader_rgbx; pitch = wl_shm_buffer_get_stride(shm_buffer) / 4; break; case WL_SHM_FORMAT_ARGB8888: - gs->shader = &gr->texture_shader_rgba; + if (gr->has_texture_3d && es->clut.data) + gs->shader = &gr->texture_shader_rgba_lut; + else + gs->shader = &gr->texture_shader_rgba; pitch = wl_shm_buffer_get_stride(shm_buffer) / 4; break; case WL_SHM_FORMAT_RGB565: - gs->shader = &gr->texture_shader_rgbx; + if (gr->has_texture_3d && es->clut.data) + gs->shader = &gr->texture_shader_rgbx_lut; + else + gs->shader = &gr->texture_shader_rgbx; pitch = wl_shm_buffer_get_stride(shm_buffer) / 2; break; default: weston_log("warning: unknown shm buffer format\n"); - gs->shader = &gr->texture_shader_rgba; + if (gr->has_texture_3d && es->clut.data) + gs->shader = &gr->texture_shader_rgba_lut; + else + gs->shader = &gr->texture_shader_rgba; pitch = wl_shm_buffer_get_stride(shm_buffer) / 4; } @@ -1208,12 +1393,18 @@ gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer, case EGL_TEXTURE_RGBA: default: num_planes = 1; - gs->shader = &gr->texture_shader_rgba; + if (gr->has_texture_3d && es->clut.data) + gs->shader = &gr->texture_shader_rgba_lut; + else + gs->shader = &gr->texture_shader_rgba; break; case EGL_TEXTURE_EXTERNAL_WL: num_planes = 1; gs->target = GL_TEXTURE_EXTERNAL_OES; - gs->shader = &gr->texture_shader_egl_external; + if (gr->has_texture_3d && es->clut.data) + gs->shader = &gr->texture_shader_egl_external_lut; + else + gs->shader = &gr->texture_shader_egl_external; break; case EGL_TEXTURE_Y_UV_WL: num_planes = 2; @@ -1258,6 +1449,64 @@ gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer, } static void +gl_renderer_attach_lut(struct weston_surface *es) +{ + struct weston_compositor *ec = es->compositor; + struct gl_renderer *gr = get_renderer(ec); + struct gl_surface_state *gs = get_surface_state(es); + + if (!gs->lut) { + glGenTextures(1, &gs->lut); + glBindTexture(GL_TEXTURE_3D_OES, gs->lut); + glTexParameteri(GL_TEXTURE_3D_OES, + GL_TEXTURE_WRAP_R_OES, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D_OES, + GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D_OES, + GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } else + glBindTexture(GL_TEXTURE_3D_OES, gs->lut); + +#ifdef GL_EXT_unpack_subimage + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); +#endif + gr->teximage3d(GL_TEXTURE_3D_OES, 0, GL_RGB, + es->clut.points, es->clut.points, es->clut.points, + 0, GL_RGB, GL_UNSIGNED_BYTE, es->clut.data); +} + +static void +gl_renderer_attach_output_lut(struct weston_output *output) +{ + struct gl_renderer *gr = get_renderer(output->compositor); + struct gl_output_state *go = get_output_state(output); + + if (!go->lut) { + glGenTextures(1, &go->lut); + glBindTexture(GL_TEXTURE_3D_OES, go->lut); + glTexParameteri(GL_TEXTURE_3D_OES, + GL_TEXTURE_WRAP_R_OES, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D_OES, + GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D_OES, + GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } else + glBindTexture(GL_TEXTURE_3D_OES, go->lut); + +#ifdef GL_EXT_unpack_subimage + glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); + glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0); + glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0); +#endif + gr->teximage3d(GL_TEXTURE_3D_OES, 0, GL_RGB, + output->clut.points, output->clut.points, + output->clut.points, 0, GL_RGB, GL_UNSIGNED_BYTE, + output->clut.data); +} + +static void gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) { struct weston_compositor *ec = es->compositor; @@ -1277,6 +1526,8 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) gs->num_images = 0; glDeleteTextures(gs->num_textures, gs->textures); gs->num_textures = 0; + if (gs->lut) + glDeleteTextures(1, &gs->lut); gs->buffer_type = BUFFER_TYPE_NULL; gs->y_inverted = 1; return; @@ -1295,6 +1546,9 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer) gs->buffer_type = BUFFER_TYPE_NULL; gs->y_inverted = 1; } + + if (gr->has_texture_3d && es->clut.data) + gl_renderer_attach_lut(es); } static void @@ -1323,6 +1577,8 @@ surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr) gs->surface->renderer_state = NULL; glDeleteTextures(gs->num_textures, gs->textures); + if (gs->lut) + glDeleteTextures(1, &gs->lut); for (i = 0; i < gs->num_images; i++) gr->destroy_image(gr->egl_display, gs->images[i]); @@ -1877,6 +2133,13 @@ gl_renderer_output_destroy(struct weston_output *output) for (i = 0; i < 2; i++) pixman_region32_fini(&go->buffer_damage[i]); + if (go->fb_texture) + glDeleteTextures(1, &go->fb_texture); + if (go->fb_mask_texture) + glDeleteTextures(1, &go->fb_mask_texture); + if (go->fb) + glDeleteFramebuffers(1, &go->fb); + eglDestroySurface(gr->egl_display, go->egl_surface); free(go); -- 1.9.1 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel