--- src/compositor.h | 5 ++ src/gles2-renderer.c | 164 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 152 insertions(+), 17 deletions(-)
diff --git a/src/compositor.h b/src/compositor.h index 733f423..c24545d 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -169,6 +169,11 @@ struct weston_output { uint32_t frame_time; int disable_planes; + int indirect_disable; + int indirect_drawing; + GLuint indirect_texture; + GLuint indirect_fbo; + char *make, *model; uint32_t subpixel; uint32_t transform; diff --git a/src/gles2-renderer.c b/src/gles2-renderer.c index 54d380a..1136cba 100644 --- a/src/gles2-renderer.c +++ b/src/gles2-renderer.c @@ -533,23 +533,12 @@ triangle_fan_debug(struct weston_surface *surface, int first, int count) } static void -repaint_region(struct weston_surface *es, pixman_region32_t *region, - pixman_region32_t *surf_region) +repaint_region(struct weston_compositor *ec, struct weston_surface *es, + int nfans) { - struct weston_compositor *ec = es->compositor; GLfloat *v; unsigned int *vtxcnt; - int i, first, nfans; - - /* The final region to be painted is the intersection of - * 'region' and 'surf_region'. However, 'region' is in the global - * coordinates, and 'surf_region' is in the surface-local - * coordinates. texture_region() will iterate over all pairs of - * rectangles from both regions, compute the intersection - * polygon for each pair, and store it as a triangle fan if - * it has a non-zero area (at least 3 vertices, actually). - */ - nfans = texture_region(es, region, surf_region); + int i, first; v = ec->vertices.data; vtxcnt = ec->vtxcnt.data; @@ -564,7 +553,7 @@ repaint_region(struct weston_surface *es, pixman_region32_t *region, for (i = 0, first = 0; i < nfans; i++) { glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]); - if (ec->fan_debug) + if (es && ec->fan_debug) triangle_fan_debug(es, first, vtxcnt[i]); first += vtxcnt[i]; } @@ -577,6 +566,73 @@ repaint_region(struct weston_surface *es, pixman_region32_t *region, } static void +repaint_surface(struct weston_surface *es, pixman_region32_t *region, + pixman_region32_t *surf_region) +{ + /* The final region to be painted is the intersection of + * 'region' and 'surf_region'. However, 'region' is in the global + * coordinates, and 'surf_region' is in the surface-local + * coordinates. texture_region() will iterate over all pairs of + * rectangles from both regions, compute the intersection + * polygon for each pair, and store it as a triangle fan if + * it has a non-zero area (at least 3 vertices, actually). + */ + int nfans = texture_region(es, region, surf_region); + + repaint_region(es->compositor, es, nfans); +} + +static void +output_emit_vertex(struct weston_output *output, GLfloat **v, int32_t x, int32_t y) +{ + struct weston_vector vector; + + /* position: */ + *((*v)++) = x; + *((*v)++) = y; + + /* texcoord: */ + + vector.f[0] = x; + vector.f[1] = y; + vector.f[2] = 0.0f; + vector.f[3] = 1.0f; + + weston_matrix_transform(&output->matrix, &vector); + + *((*v)++) = (vector.f[0] + 1.0f) * 0.5f; + *((*v)++) = (vector.f[1] + 1.0f) * 0.5f; +} + +static void +repaint_output(struct weston_output *output, pixman_region32_t *region) +{ + struct weston_compositor *ec = output->compositor; + GLfloat *v; + unsigned int *vtxcnt, nvtx = 0; + pixman_box32_t *rects; + int i, nrects; + + rects = pixman_region32_rectangles(region, &nrects); + + v = wl_array_add(&ec->vertices, nrects * 4 * 4 * sizeof *v); + vtxcnt = wl_array_add(&ec->vtxcnt, nrects * sizeof *vtxcnt); + + for (i = 0; i < nrects; i++) { + pixman_box32_t *rect = &rects[i]; + + output_emit_vertex(output, &v, rect->x1, rect->y1); + output_emit_vertex(output, &v, rect->x2, rect->y1); + output_emit_vertex(output, &v, rect->x2, rect->y2); + output_emit_vertex(output, &v, rect->x1, rect->y2); + + vtxcnt[nvtx++] = 4; + } + + repaint_region(ec, NULL, nvtx); +} + +static void weston_compositor_use_shader(struct weston_compositor *compositor, struct weston_shader *shader) { @@ -588,6 +644,69 @@ weston_compositor_use_shader(struct weston_compositor *compositor, } static void +repaint_surfaces_start(struct weston_output *output, pixman_region32_t *damage) +{ + output->indirect_drawing = 0 && !output->indirect_disable; + + if(output->indirect_drawing) { + if(!output->indirect_fbo) + glGenFramebuffers(1, &output->indirect_fbo); + + glBindFramebuffer(GL_FRAMEBUFFER, output->indirect_fbo); + + if(!output->indirect_texture) { + glGenTextures(1, &output->indirect_texture); + + glBindTexture(GL_TEXTURE_2D, output->indirect_texture); + + glTexParameteri(GL_TEXTURE_2D, 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); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, output->current->width, output->current->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, output->indirect_texture, 0); + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if(status != GL_FRAMEBUFFER_COMPLETE) { + weston_log("unable to create framebuffer for indirect rendering %d\n", (int)status); + output->indirect_drawing = 0; + output->indirect_disable = 1; + + return; + } + } +} + +static void +repaint_surfaces_finish(struct weston_output *output, pixman_region32_t *damage) +{ + struct weston_compositor *ec = output->compositor; + + if(output->indirect_drawing) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + struct weston_shader *shader = &ec->texture_shader_rgba; + + weston_compositor_use_shader(ec, shader); + + glUniformMatrix4fv(shader->proj_uniform, + 1, GL_FALSE, output->matrix.d); + glUniform1f(shader->alpha_uniform, 1.0); + glUniform1i(shader->tex_uniforms[0], 0); + + glDisable(GL_BLEND); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, output->indirect_texture); + + repaint_output(output, damage); + } +} + +static void weston_shader_uniforms(struct weston_shader *shader, struct weston_surface *surface, struct weston_output *output) @@ -669,13 +788,13 @@ draw_surface(struct weston_surface *es, struct weston_output *output, else glDisable(GL_BLEND); - repaint_region(es, &repaint, &es->opaque); + repaint_surface(es, &repaint, &es->opaque); } if (pixman_region32_not_empty(&surface_blend)) { weston_compositor_use_shader(ec, es->shader); glEnable(GL_BLEND); - repaint_region(es, &repaint, &surface_blend); + repaint_surface(es, &repaint, &surface_blend); } pixman_region32_fini(&surface_blend); @@ -690,9 +809,13 @@ repaint_surfaces(struct weston_output *output, pixman_region32_t *damage) struct weston_compositor *compositor = output->compositor; struct weston_surface *surface; + repaint_surfaces_start(output, damage); + wl_list_for_each_reverse(surface, &compositor->surface_list, link) if (surface->plane == &compositor->primary_plane) draw_surface(surface, output, damage); + + repaint_surfaces_finish(output, damage); } static void @@ -1130,11 +1253,18 @@ WL_EXPORT void gles2_renderer_surface_create(struct weston_output *output, EGLSurface egl_surface) { output->egl_surface = egl_surface; + + output->indirect_texture = 0; + output->indirect_fbo = 0; + output->indirect_disable = 0; } WL_EXPORT void gles2_renderer_surface_destroy(struct weston_output *output) { + glDeleteTextures(1, &output->indirect_texture); + glDeleteFramebuffers(1, &output->indirect_fbo); + eglDestroySurface(output->compositor->egl_display, output->egl_surface); } -- 1.7.12 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/wayland-devel