Skip to content
Snippets Groups Projects

EGL_KHR_partial_update

Merged Daniel Stone requested to merge daniels/weston:egl-partial-update into master
@@ -180,7 +180,7 @@ struct gl_surface_state {
enum buffer_type buffer_type;
int pitch; /* in pixels */
int height; /* in pixels */
int y_inverted;
bool y_inverted;
/* Extension needed for SHM YUV texture */
int offset[3]; /* offset per plane */
@@ -199,8 +199,8 @@ struct gl_surface_state {
struct gl_renderer {
struct weston_renderer base;
int fragment_shader_debug;
int fan_debug;
bool fragment_shader_debug;
bool fan_debug;
struct weston_binding *fragment_binding;
struct weston_binding *fan_binding;
@@ -221,27 +221,29 @@ struct gl_renderer {
PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC create_platform_window;
int has_unpack_subimage;
bool has_unpack_subimage;
PFNEGLBINDWAYLANDDISPLAYWL bind_display;
PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
int has_bind_display;
bool has_bind_display;
int has_context_priority;
bool has_context_priority;
int has_egl_image_external;
bool has_egl_image_external;
int has_egl_buffer_age;
bool has_egl_buffer_age;
bool has_egl_partial_update;
PFNEGLSETDAMAGEREGIONKHRPROC set_damage_region;
int has_configless_context;
bool has_configless_context;
int has_surfaceless_context;
bool has_surfaceless_context;
int has_dmabuf_import;
bool has_dmabuf_import;
struct wl_list dmabuf_images;
int has_gl_texture_rg;
bool has_gl_texture_rg;
struct gl_shader texture_shader_rgba;
struct gl_shader texture_shader_rgbx;
@@ -257,16 +259,16 @@ struct gl_renderer {
struct wl_listener output_destroy_listener;
int has_dmabuf_import_modifiers;
bool has_dmabuf_import_modifiers;
PFNEGLQUERYDMABUFFORMATSEXTPROC query_dmabuf_formats;
PFNEGLQUERYDMABUFMODIFIERSEXTPROC query_dmabuf_modifiers;
int has_native_fence_sync;
bool has_native_fence_sync;
PFNEGLCREATESYNCKHRPROC create_sync;
PFNEGLDESTROYSYNCKHRPROC destroy_sync;
PFNEGLDUPNATIVEFENCEFDANDROIDPROC dup_native_fence_fd;
int has_wait_sync;
bool has_wait_sync;
PFNEGLWAITSYNCKHRPROC wait_sync;
};
@@ -1352,6 +1354,71 @@ output_rotate_damage(struct weston_output *output,
go->border_damage[go->buffer_damage_index] = border_status;
}
/**
* Given a region in Weston's (top-left-origin) global co-ordinate space,
* translate it to the co-ordinate space used by GL for our output
* rendering. This requires shifting it into output co-ordinate space:
* translating for output offset within the global co-ordinate space,
* multiplying by output scale to get buffer rather than logical size.
*
* Finally, if borders are drawn around the output, we translate the area
* to account for the border region around the outside, and add any
* damage if the borders have been redrawn.
*
* @param output The output whose co-ordinate space we are after
* @param global_region The affected region in global co-ordinate space
* @param[out] rects Y-inverted quads in {x,y,w,h} order; caller must free
* @param[out] nrects Number of quads (4x number of co-ordinates)
*/
static void
pixman_region_to_egl_y_invert(struct weston_output *output,
struct pixman_region32 *global_region,
EGLint **rects,
EGLint *nrects)
{
struct gl_output_state *go = get_output_state(output);
pixman_region32_t transformed;
struct pixman_box32 *box;
int buffer_height;
EGLint *d;
int i;
/* Translate from global to output co-ordinate space. */
pixman_region32_init(&transformed);
weston_transformed_region(output->width, output->height,
output->transform,
output->current_scale,
global_region, &transformed);
/* If we have borders drawn around the output, shift our output damage
* to account for borders being drawn around the outside, adding any
* damage resulting from borders being redrawn. */
if (output_has_borders(output)) {
pixman_region32_translate(&transformed,
go->borders[GL_RENDERER_BORDER_LEFT].width,
go->borders[GL_RENDERER_BORDER_TOP].height);
output_get_border_damage(output, go->border_status,
&transformed);
}
/* Convert from a Pixman region into {x,y,w,h} quads, flipping in the
* Y axis to account for GL's lower-left-origin co-ordinate space. */
box = pixman_region32_rectangles(&transformed, nrects);
*rects = malloc(*nrects * 4 * sizeof(EGLint));
buffer_height = go->borders[GL_RENDERER_BORDER_TOP].height +
output->current_mode->height +
go->borders[GL_RENDERER_BORDER_BOTTOM].height;
d = *rects;
for (i = 0; i < *nrects; ++i) {
*d++ = box[i].x1;
*d++ = buffer_height - box[i].y2;
*d++ = box[i].x2 - box[i].x1;
*d++ = box[i].y2 - box[i].y1;
}
}
/* NOTE: We now allow falling back to ARGB gl visuals when XRGB is
* unavailable, so we're assuming the background has no transparency
* and that everything with a blend, like drop shadows, will have something
@@ -1369,11 +1436,11 @@ gl_renderer_repaint_output(struct weston_output *output,
struct gl_renderer *gr = get_renderer(compositor);
EGLBoolean ret;
static int errored;
int i, nrects, buffer_height;
EGLint *egl_damage, *d;
pixman_box32_t *rects;
pixman_region32_t buffer_damage, total_damage;
enum gl_border_status border_damage = BORDER_STATUS_CLEAN;
/* areas we've damaged since we last used this buffer */
pixman_region32_t previous_damage;
/* total area we need to repaint this time */
pixman_region32_t total_damage;
enum gl_border_status border_status = BORDER_STATUS_CLEAN;
struct weston_view *view;
if (use_output(output) < 0)
@@ -1411,75 +1478,76 @@ gl_renderer_repaint_output(struct weston_output *output,
2.0 / output->current_mode->width,
-2.0 / output->current_mode->height, 1);
/* if debugging, redraw everything outside the damage to clean up
* debug lines from the previous draw on this buffer:
*/
/* In fan debug mode, redraw everything to make sure that we clear any
* fans left over from previous draws on this buffer.
* This precludes the use of EGL_EXT_swap_buffers_with_damage and
* EGL_KHR_partial_update, since we damage the whole area. */
if (gr->fan_debug) {
pixman_region32_t undamaged;
pixman_region32_init(&undamaged);
pixman_region32_subtract(&undamaged, &output->region,
output_damage);
gr->fan_debug = 0;
gr->fan_debug = false;
repaint_views(output, &undamaged);
gr->fan_debug = 1;
gr->fan_debug = true;
pixman_region32_fini(&undamaged);
}
pixman_region32_init(&total_damage);
pixman_region32_init(&buffer_damage);
/* previous_damage covers regions damaged in previous paints since we
* last used this buffer */
pixman_region32_init(&previous_damage);
pixman_region32_init(&total_damage); /* total area to redraw */
output_get_damage(output, &buffer_damage, &border_damage);
/* Update previous_damage using buffer_age (if available), and store
* current damaged region for future use. */
output_get_damage(output, &previous_damage, &border_status);
output_rotate_damage(output, output_damage, go->border_status);
pixman_region32_union(&total_damage, &buffer_damage, output_damage);
border_damage |= go->border_status;
/* Redraw both areas which have changed since we last used this buffer,
* as well as the areas we now want to repaint, to make sure the
* buffer is up to date. */
pixman_region32_union(&total_damage, &previous_damage, output_damage);
border_status |= go->border_status;
if (gr->has_egl_partial_update && !gr->fan_debug) {
int n_egl_rects;
EGLint *egl_rects;
/* For partial_update, we need to pass the region which has
* changed since we last rendered into this specific buffer;
* this is total_damage. */
pixman_region_to_egl_y_invert(output, &total_damage,
&egl_rects, &n_egl_rects);
gr->set_damage_region(gr->egl_display, go->egl_surface,
egl_rects, n_egl_rects);
free(egl_rects);
}
repaint_views(output, &total_damage);
pixman_region32_fini(&total_damage);
pixman_region32_fini(&buffer_damage);
pixman_region32_fini(&previous_damage);
draw_output_borders(output, border_damage);
draw_output_borders(output, border_status);
pixman_region32_copy(&output->previous_damage, output_damage);
wl_signal_emit(&output->frame_signal, output);
go->end_render_sync = create_render_sync(gr);
if (gr->swap_buffers_with_damage) {
pixman_region32_init(&buffer_damage);
weston_transformed_region(output->width, output->height,
output->transform,
output->current_scale,
output_damage, &buffer_damage);
if (output_has_borders(output)) {
pixman_region32_translate(&buffer_damage,
go->borders[GL_RENDERER_BORDER_LEFT].width,
go->borders[GL_RENDERER_BORDER_TOP].height);
output_get_border_damage(output, go->border_status,
&buffer_damage);
}
rects = pixman_region32_rectangles(&buffer_damage, &nrects);
egl_damage = malloc(nrects * 4 * sizeof(EGLint));
if (gr->swap_buffers_with_damage && !gr->fan_debug) {
int n_egl_rects;
EGLint *egl_rects;
buffer_height = go->borders[GL_RENDERER_BORDER_TOP].height +
output->current_mode->height +
go->borders[GL_RENDERER_BORDER_BOTTOM].height;
d = egl_damage;
for (i = 0; i < nrects; ++i) {
*d++ = rects[i].x1;
*d++ = buffer_height - rects[i].y2;
*d++ = rects[i].x2 - rects[i].x1;
*d++ = rects[i].y2 - rects[i].y1;
}
/* For swap_buffers_with_damage, we need to pass the region
* which has changed since the previous SwapBuffers on this
* surface - this is output_damage. */
pixman_region_to_egl_y_invert(output, output_damage,
&egl_rects, &n_egl_rects);
ret = gr->swap_buffers_with_damage(gr->egl_display,
go->egl_surface,
egl_damage, nrects);
free(egl_damage);
pixman_region32_fini(&buffer_damage);
egl_rects, n_egl_rects);
free(egl_rects);
} else {
ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
}
@@ -1809,7 +1877,7 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
gs->gl_pixel_type = gl_pixel_type;
gs->buffer_type = BUFFER_TYPE_SHM;
gs->needs_full_upload = true;
gs->y_inverted = 1;
gs->y_inverted = true;
gs->surface = es;
@@ -2497,7 +2565,7 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
glDeleteTextures(gs->num_textures, gs->textures);
gs->num_textures = 0;
gs->buffer_type = BUFFER_TYPE_NULL;
gs->y_inverted = 1;
gs->y_inverted = true;
es->is_opaque = false;
return;
}
@@ -2521,7 +2589,7 @@ gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
weston_buffer_reference(&gs->buffer_ref, NULL);
weston_buffer_release_reference(&gs->buffer_release_ref, NULL);
gs->buffer_type = BUFFER_TYPE_NULL;
gs->y_inverted = 1;
gs->y_inverted = true;
es->is_opaque = false;
weston_buffer_send_server_error(buffer,
"disconnecting due to unhandled buffer type");
@@ -2755,7 +2823,7 @@ gl_renderer_create_surface(struct weston_surface *surface)
* by zero there.
*/
gs->pitch = 1;
gs->y_inverted = 1;
gs->y_inverted = true;
gs->surface = surface;
@@ -3394,6 +3462,8 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
(void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
gr->query_buffer =
(void *) eglGetProcAddress("eglQueryWaylandBufferWL");
gr->set_damage_region =
(void *) eglGetProcAddress("eglSetDamageRegionKHR");
extensions =
(const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
@@ -3403,18 +3473,21 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
}
if (weston_check_egl_extension(extensions, "EGL_IMG_context_priority"))
gr->has_context_priority = 1;
gr->has_context_priority = true;
if (weston_check_egl_extension(extensions, "EGL_WL_bind_wayland_display"))
gr->has_bind_display = 1;
gr->has_bind_display = true;
if (gr->has_bind_display) {
ret = gr->bind_display(gr->egl_display, ec->wl_display);
if (!ret)
gr->has_bind_display = 0;
gr->has_bind_display = false;
}
if (weston_check_egl_extension(extensions, "EGL_EXT_buffer_age"))
gr->has_egl_buffer_age = 1;
gr->has_egl_buffer_age = true;
if (weston_check_egl_extension(extensions, "EGL_KHR_partial_update"))
gr->has_egl_partial_update = true;
for (i = 0; i < ARRAY_LENGTH(swap_damage_ext_to_entrypoint); i++) {
if (weston_check_egl_extension(extensions,
@@ -3428,13 +3501,13 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
if (weston_check_egl_extension(extensions, "EGL_KHR_no_config_context") ||
weston_check_egl_extension(extensions, "EGL_MESA_configless_context"))
gr->has_configless_context = 1;
gr->has_configless_context = true;
if (weston_check_egl_extension(extensions, "EGL_KHR_surfaceless_context"))
gr->has_surfaceless_context = 1;
gr->has_surfaceless_context = true;
if (weston_check_egl_extension(extensions, "EGL_EXT_image_dma_buf_import"))
gr->has_dmabuf_import = 1;
gr->has_dmabuf_import = true;
if (weston_check_egl_extension(extensions,
"EGL_EXT_image_dma_buf_import_modifiers")) {
@@ -3442,7 +3515,7 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
(void *) eglGetProcAddress("eglQueryDmaBufFormatsEXT");
gr->query_dmabuf_modifiers =
(void *) eglGetProcAddress("eglQueryDmaBufModifiersEXT");
gr->has_dmabuf_import_modifiers = 1;
gr->has_dmabuf_import_modifiers = true;
}
if (weston_check_egl_extension(extensions, "EGL_KHR_fence_sync") &&
@@ -3453,7 +3526,7 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
(void *) eglGetProcAddress("eglDestroySyncKHR");
gr->dup_native_fence_fd =
(void *) eglGetProcAddress("eglDupNativeFenceFDANDROID");
gr->has_native_fence_sync = 1;
gr->has_native_fence_sync = true;
} else {
weston_log("warning: Disabling render GPU timeline and explicit "
"synchronization due to missing "
@@ -3462,7 +3535,7 @@ gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
if (weston_check_egl_extension(extensions, "EGL_KHR_wait_sync")) {
gr->wait_sync = (void *) eglGetProcAddress("eglWaitSyncKHR");
gr->has_wait_sync = 1;
gr->has_wait_sync = true;
} else {
weston_log("warning: Disabling explicit synchronization due"
"to missing EGL_KHR_wait_sync extension\n");
@@ -3799,7 +3872,7 @@ fragment_debug_binding(struct weston_keyboard *keyboard,
struct gl_renderer *gr = get_renderer(ec);
struct weston_output *output;
gr->fragment_shader_debug ^= 1;
gr->fragment_shader_debug = !gr->fragment_shader_debug;
shader_release(&gr->texture_shader_rgba);
shader_release(&gr->texture_shader_rgbx);
@@ -3952,14 +4025,14 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
if (gr->gl_version >= GR_GL_VERSION(3, 0) ||
weston_check_egl_extension(extensions, "GL_EXT_unpack_subimage"))
gr->has_unpack_subimage = 1;
gr->has_unpack_subimage = true;
if (gr->gl_version >= GR_GL_VERSION(3, 0) ||
weston_check_egl_extension(extensions, "GL_EXT_texture_rg"))
gr->has_gl_texture_rg = 1;
gr->has_gl_texture_rg = true;
if (weston_check_egl_extension(extensions, "GL_OES_EGL_image_external"))
gr->has_egl_image_external = 1;
gr->has_egl_image_external = true;
glActiveTexture(GL_TEXTURE0);
Loading