[PATCH v4 4/4] add detailed implementation for fullscreen support
juan.j.zhao at linux.intel.com
juan.j.zhao at linux.intel.com
Mon Jan 16 08:47:57 PST 2012
From: Juan Zhao <juan.j.zhao at linux.intel.com>
Signed-off-by: Juan Zhao <juan.j.zhao at linux.intel.com>
Signed-off-by: Zhiwen Wu <zhiwen.wu at linux.intel.com>
---
src/compositor-drm.c | 162 +++++++++++++++++++++++++++++++++++++++
src/compositor.c | 206 ++++++++++++++++++++++++++++++++++++++++++--------
src/shell.c | 11 +++
3 files changed, 348 insertions(+), 31 deletions(-)
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 8f6c8fc..3048fd7 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -78,6 +78,23 @@ struct drm_output {
uint32_t pending_fs_surf_fb_id;
};
+static struct drm_mode *
+choose_mode (struct drm_output *output, int32_t width, int32_t height, uint32_t refresh)
+{
+ struct drm_mode *tmp_mode = NULL, *mode, *next;
+
+ wl_list_for_each_safe(mode, next, &output->base.mode_list,base.link) {
+ if (mode->mode_info.hdisplay == width && mode->mode_info.vdisplay == height) {
+ if (mode->mode_info.vrefresh == refresh)
+ return mode;
+ else if (!tmp_mode)
+ tmp_mode = mode;
+ }
+ }
+
+ return tmp_mode;
+}
+
static int
drm_output_prepare_render(struct weston_output *output_base)
{
@@ -258,6 +275,147 @@ out:
return ret;
}
+static int
+drm_output_set_mode (struct weston_output *output_base, int32_t width, int32_t height, uint32_t refresh)
+{
+ struct drm_output *output;
+ struct drm_mode *drm_mode;
+ int i, ret;
+ unsigned handle, stride;
+ struct drm_compositor *ec;
+
+ if (output_base == NULL) {
+ fprintf(stderr, "output is NULL.\n");
+ return -1;
+ }
+
+ ec = (struct drm_compositor *)output_base->compositor;
+ output = (struct drm_output *)output_base;
+ drm_mode = (struct drm_mode *)(output->base.current);
+
+ printf ("current mode: %s, w=%d, h=%d, refresh=%u, flags=%u\n",
+ drm_mode->mode_info.name, drm_mode->base.width,
+ drm_mode->base.height, drm_mode->base.refresh,
+ drm_mode->base.flags);
+
+ drm_mode = choose_mode (output, width, height, refresh);
+
+ if (!drm_mode) {
+ printf ("%s, invalid resolution:%dx%d\n", __FUNCTION__, width, height);
+ return -1;
+ }
+
+ printf ("next mode: %s, w=%d, h=%d, refresh=%u, flags=%u\n",
+ drm_mode->mode_info.name, drm_mode->base.width,
+ drm_mode->base.height, drm_mode->base.refresh,
+ drm_mode->base.flags);
+
+
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER, 0);
+
+
+ /* Destroy output buffers */
+ for (i = 0; i < 2; i++) {
+ drmModeRmFB(ec->drm.fd, output->fb_id[i]);
+ ec->base.destroy_image(ec->base.display, output->image[i]);
+ gbm_bo_destroy(output->bo[i]);
+ }
+
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ glDeleteRenderbuffers(2, output->rbo);
+ weston_output_destroy(output_base);
+
+ output->base.current = &drm_mode->base;
+ drm_mode->base.flags =
+ WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+
+ /* create new output buffers */
+ glGenRenderbuffers(2, output->rbo);
+ for (i = 0; i < 2; i++) {
+ glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
+
+ output->bo[i] =
+ gbm_bo_create(ec->gbm,
+ output->base.current->width,
+ output->base.current->height,
+ GBM_BO_FORMAT_XRGB8888,
+ GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
+
+ if (!output->bo[i])
+ goto err_bufs;
+
+ output->image[i] = ec->base.create_image(ec->base.display,
+ NULL,
+ EGL_NATIVE_PIXMAP_KHR,
+ output->bo[i], NULL);
+ if (!output->image[i])
+ goto err_bufs;
+
+ ec->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
+ output->image[i]);
+ stride = gbm_bo_get_pitch(output->bo[i]);
+ handle = gbm_bo_get_handle(output->bo[i]).u32;
+
+ ret = drmModeAddFB(ec->drm.fd,
+ output->base.current->width,
+ output->base.current->height,
+ 24, 32, stride, handle, &output->fb_id[i]);
+
+ if (ret) {
+ fprintf(stderr, "failed to add fb %d: %m\n", i);
+ goto err_bufs;
+ }
+ }
+
+ output->current = 0;
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER,
+ output->rbo[output->current]);
+
+ ret = drmModeSetCrtc(ec->drm.fd,
+ output->crtc_id,
+ output->fb_id[output->current ^ 1], 0, 0,
+ &output->connector_id, 1, &drm_mode->mode_info);
+
+ if (ret) {
+ fprintf(stderr, "failed to set mode: %m\n");
+ goto err_fb;
+ }
+
+ output->base.x = 0;
+ output->base.y = 0;
+ output->base.mm_width = output->base.current->width;
+ output->base.mm_height = output->base.current->height;
+ weston_output_move(&output->base, 0, 0);
+
+ printf ("%s: ret 0\n", __FUNCTION__);
+ return 0;
+
+err_fb:
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER, 0);
+err_bufs:
+ for (i = 0; i < 2; i++) {
+ if (output->fb_id[i] != -1)
+ drmModeRmFB(ec->drm.fd, output->fb_id[i]);
+ if (output->image[i])
+ ec->base.destroy_image(ec->base.display,
+ output->image[i]);
+ if (output->bo[i])
+ gbm_bo_destroy(output->bo[i]);
+ }
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ glDeleteRenderbuffers(2, output->rbo);
+
+ printf ("%s: ret -1\n", __FUNCTION__);
+ return -1;
+}
+
+
static void
drm_output_destroy(struct weston_output *output_base)
{
@@ -488,7 +646,10 @@ create_output_for_connector(struct drm_compositor *ec,
drm_mode = container_of(output->base.mode_list.next,
struct drm_mode, base.link);
+
output->base.current = &drm_mode->base;
+ output->base.saved_mode = NULL;
+ output->base.fs_dirty = NULL;
drm_mode->base.flags =
WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
@@ -553,6 +714,7 @@ create_output_for_connector(struct drm_compositor *ec,
output->base.prepare_scanout_surface =
drm_output_prepare_scanout_surface;
output->base.set_hardware_cursor = drm_output_set_cursor;
+ output->base.set_mode = drm_output_set_mode;
output->base.destroy = drm_output_destroy;
return 0;
diff --git a/src/compositor.c b/src/compositor.c
index 1f0cb2d..3529ca1 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -75,6 +75,29 @@ sigchld_handler(int signal_number, void *data)
return 1;
}
+static int
+weston_output_restore_mode (struct weston_output *output)
+{
+ int ret;
+
+ if(!output->saved_mode ||
+ (output->saved_mode->width == output->current->width &&
+ output->saved_mode->height == output->current->height))
+ return 0;
+
+ if (output->set_mode) {
+ if ((ret = output->set_mode(output, output->saved_mode->width, output->saved_mode->height, output->saved_mode->refresh)) == 0)
+ printf("set mode '%dx%d', ret %d\n", output->saved_mode->width, output->saved_mode->height, ret);
+ output->saved_mode = NULL;
+ }
+ else {
+ fprintf(stderr, "Can't restore display mode\n");
+ ret = -1;
+ }
+
+ return ret;
+}
+
WL_EXPORT void
weston_watch_process(struct weston_process *process)
{
@@ -229,8 +252,11 @@ weston_surface_create(struct weston_compositor *compositor,
surface->alpha = 255;
surface->fs_support.fullscreen_output = NULL;
+ surface->fs_support.fs_method = WESTON_SURFACE_FULLSCREEN_DEFAULT;
+ surface->fs_support.fs_transform = NULL;
surface->buffer = NULL;
surface->output = NULL;
+ surface->type = WESTON_SURFACE_TYPE_GENERAL;
pixman_region32_init(&surface->damage);
pixman_region32_init(&surface->opaque);
@@ -321,7 +347,65 @@ int
weston_surface_set_fullscreen( struct weston_output *output,
struct weston_surface *surface)
{
- /*do the real set fullscreen*/
+ struct weston_transform *fs_transform=surface->fs_support.fs_transform;
+
+ switch(surface->fs_support.fs_method) {
+ case WESTON_SURFACE_FULLSCREEN_DEFAULT:
+ output->fs_dirty = 1;
+ weston_surface_center_on_output(surface, output);
+ weston_surface_damage(surface);
+ break;
+ case WESTON_SURFACE_FULLSCREEN_SCALE:
+ if(output->current->width == surface->width &&
+ output->current->height == surface->height)
+ return 0;
+ output->fs_dirty = 1;
+ /*do not forgot to release them, Juan*/
+ if(!fs_transform) {
+ fs_transform = malloc(sizeof *fs_transform);
+ surface->fs_support.fs_transform = fs_transform;
+ }
+ weston_matrix_init(&fs_transform->matrix);
+ /*preserve aspect ratio*/
+ weston_matrix_scale(&fs_transform->matrix,
+ (float)output->current->width/(float)surface->width,
+ (float)output->current->width/(float)surface->width,
+ 1.0);
+ weston_surface_damage(surface);
+ break;
+ case WESTON_SURFACE_FULLSCREEN_DRIVER:
+ if(output->current->width == surface->width &&
+ output->current->height == surface->height)
+ return 0;
+ output->saved_mode = output->current;
+ uint32_t refresh = surface->fs_support.framerate;
+ if (!output->set_mode) {
+ output->saved_mode = NULL;
+ fprintf(stderr,
+ "set_mode not implemented, \
+ fallback to FILL method\n");
+ } else if(output->set_mode(output, surface->width, surface->height, refresh) == 0) {
+ weston_surface_damage(surface);
+ break;
+ } else {
+ /*did not find the mode, fall back */
+ output->current = output->saved_mode;
+ output->saved_mode = NULL;
+ fprintf(stderr,
+ "failed to set mode, \
+ fallback to FILL method\n");
+ }
+ case WESTON_SURFACE_FULLSCREEN_FILL:
+ /*make it on the center at first*/
+ output->fs_dirty = 1;
+ weston_surface_center_on_output(surface, output);
+ weston_surface_damage(surface);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
}
static void
@@ -509,7 +593,7 @@ texture_region(struct weston_surface *es, pixman_region32_t *region)
static void
transform_vertex(struct weston_surface *surface,
- GLfloat x, GLfloat y, GLfloat u, GLfloat v, GLfloat *r)
+ GLfloat x, GLfloat y, GLfloat u, GLfloat v, GLfloat *r, uint32_t fs_scale)
{
struct weston_vector t;
@@ -518,7 +602,11 @@ transform_vertex(struct weston_surface *surface,
t.f[2] = 0.0;
t.f[3] = 1.0;
- weston_matrix_transform(&surface->transform->matrix, &t);
+ if(!fs_scale)
+ weston_matrix_transform(&surface->transform->matrix, &t);
+ else
+ weston_matrix_transform(&surface->fs_support.fs_transform->matrix,
+ &t);
r[ 0] = t.f[0];
r[ 1] = t.f[1];
@@ -527,7 +615,7 @@ transform_vertex(struct weston_surface *surface,
}
static int
-texture_transformed_surface(struct weston_surface *es)
+texture_transformed_surface(struct weston_surface *es, uint32_t fs_scale)
{
struct weston_compositor *ec = es->compositor;
GLfloat *v;
@@ -536,11 +624,11 @@ texture_transformed_surface(struct weston_surface *es)
v = wl_array_add(&ec->vertices, 16 * sizeof *v);
p = wl_array_add(&ec->indices, 6 * sizeof *p);
- transform_vertex(es, es->x, es->y, 0.0, 0.0, &v[0]);
- transform_vertex(es, es->x, es->y + es->height, 0.0, 1.0, &v[4]);
- transform_vertex(es, es->x + es->width, es->y, 1.0, 0.0, &v[8]);
+ transform_vertex(es, es->x, es->y, 0.0, 0.0, &v[0], fs_scale);
+ transform_vertex(es, es->x, es->y + es->height, 0.0, 1.0, &v[4], fs_scale);
+ transform_vertex(es, es->x + es->width, es->y, 1.0, 0.0, &v[8], fs_scale);
transform_vertex(es, es->x + es->width, es->y + es->height,
- 1.0, 1.0, &v[12]);
+ 1.0, 1.0, &v[12], fs_scale);
p[0] = 0;
p[1] = 1;
@@ -565,7 +653,7 @@ weston_surface_draw(struct weston_surface *es,
pixman_region32_init_rect(&repaint,
es->x, es->y, es->width, es->height);
pixman_region32_intersect(&repaint, &repaint, clip);
- if (!pixman_region32_not_empty(&repaint))
+ if (!pixman_region32_not_empty(&repaint) || !ec)
return;
switch (es->visual) {
@@ -587,14 +675,18 @@ weston_surface_draw(struct weston_surface *es,
ec->current_alpha = es->alpha;
}
- if (es->transform == NULL) {
+ if ((es->transform == NULL) && (es->fs_support.fs_transform == NULL)) {
filter = GL_NEAREST;
n = texture_region(es, &repaint);
+ } else if (es->fs_support.fs_transform) {
+ filter = GL_LINEAR;
+ n = texture_transformed_surface(es, 1);
} else {
filter = GL_LINEAR;
- n = texture_transformed_surface(es);
+ n = texture_transformed_surface(es, 0);
}
+
glBindTexture(GL_TEXTURE_2D, es->texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
@@ -696,6 +788,11 @@ fade_output(struct weston_output *output,
surface.height = output->current->height;
surface.texture = GL_NONE;
surface.transform = NULL;
+ surface.fs_support.fullscreen_output = NULL;
+ surface.fs_support.fs_method = WESTON_SURFACE_FULLSCREEN_DEFAULT;
+ surface.fs_support.fs_transform = NULL;
+ surface.type = WESTON_SURFACE_TYPE_GENERAL;
+
surface.alpha = compositor->current_alpha;
if (tint <= 1.0)
@@ -781,13 +878,11 @@ static void
weston_output_repaint(struct weston_output *output)
{
struct weston_compositor *ec = output->compositor;
- struct weston_surface *es;
+ struct weston_surface *es, *tmp_es = NULL, *fs_es = NULL;
pixman_region32_t opaque, new_damage, total_damage, repaint;
output->prepare_render(output);
- glViewport(0, 0, output->current->width, output->current->height);
-
glUseProgram(ec->texture_shader.program);
glUniformMatrix4fv(ec->texture_shader.proj_uniform,
1, GL_FALSE, output->matrix.d);
@@ -814,31 +909,79 @@ weston_output_repaint(struct weston_output *output)
pixman_region32_fini(&opaque);
pixman_region32_fini(&new_damage);
+
es = container_of(ec->surface_list.next, struct weston_surface, link);
if (setup_scanout_surface(output, es) == 0)
/* We're drawing nothing, just let the damage accumulate */
return;
- if (es->fs_support.fullscreen_output == output) {
- if (es->width < output->current->width ||
- es->height < output->current->height)
- glClear(GL_COLOR_BUFFER_BIT);
- weston_surface_draw(es, output, &total_damage);
- } else {
- wl_list_for_each(es, &ec->surface_list, link) {
- pixman_region32_copy(&es->damage, &total_damage);
- pixman_region32_subtract(&total_damage, &total_damage, &es->opaque);
+ wl_list_for_each(tmp_es, &ec->surface_list, link) {
+ if ( tmp_es->type == WESTON_SURFACE_TYPE_GENERAL ) {
+ if( tmp_es->fs_support.fullscreen_output == output ){
+ fs_es = tmp_es;
+ }
+ break;
}
+ }
- wl_list_for_each_reverse(es, &ec->surface_list, link) {
- pixman_region32_init(&repaint);
- pixman_region32_intersect(&repaint, &output->region,
- &es->damage);
- weston_surface_draw(es, output, &repaint);
- pixman_region32_subtract(&es->damage,
- &es->damage, &output->region);
- pixman_region32_fini(&repaint);
+ if (fs_es) {
+ if (fs_es->width != output->current->width ||
+ fs_es->height != output->current->height) {
+ weston_surface_set_fullscreen(output, fs_es);
+ output->prepare_render(output);
+ glViewport( 0, 0, (GLint) output->current->width,
+ (GLint) output->current->height);
+ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+ }
+
+ /* draw all the surface above fullscreen es except panel */
+ wl_list_for_each_reverse(tmp_es, fs_es->link.next, link) {
+ if (tmp_es->type != WESTON_SURFACE_TYPE_PANEL) {
+ weston_surface_draw(tmp_es, output, &total_damage);
+ }
+ if (tmp_es == es)
+ break;
+ }
+ } else {
+ if( output->saved_mode &&
+ (output->saved_mode->width!=output->current->width ||
+ output->saved_mode->height!=output->current->height) ) {
+ weston_output_restore_mode(output);
+ output->saved_mode = NULL;
+ output->fs_dirty = 0;
+ output->prepare_render(output);
+ glViewport( 0, 0,
+ (GLint) output->current->width,
+ (GLint) output->current->height);
+ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+ weston_output_damage(output);
+ weston_output_repaint(output);
+ } else if (output->fs_dirty) {
+ output->fs_dirty = 0;
+ weston_output_damage(output);
+ weston_output_repaint(output);
+ } else {
+ glViewport(0, 0,
+ output->current->width,
+ output->current->height);
+ wl_list_for_each(es, &ec->surface_list, link) {
+ pixman_region32_copy(&es->damage,
+ &total_damage);
+ pixman_region32_subtract(&total_damage,
+ &total_damage,
+ &es->opaque);
+ }
+ wl_list_for_each_reverse(es, &ec->surface_list, link) {
+ pixman_region32_init(&repaint);
+ pixman_region32_intersect(&repaint,
+ &output->region,
+ &es->damage);
+ weston_surface_draw(es, output, &repaint);
+ pixman_region32_subtract(&es->damage,
+ &es->damage,
+ &output->region);
+ }
}
}
@@ -1563,6 +1706,7 @@ input_device_attach(struct wl_client *client,
weston_surface_create(compositor,
device->input_device.x,
device->input_device.y, 32, 32);
+ device->sprite->type = WESTON_SURFACE_TYPE_CURSOR;
wl_list_init(&device->sprite->link);
}
diff --git a/src/shell.c b/src/shell.c
index a131ae5..f57f660 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -331,6 +331,10 @@ reset_shell_surface_type(struct shell_surface *surface)
surface->surface->x = surface->saved_x;
surface->surface->y = surface->saved_y;
surface->surface->fs_support.fullscreen_output = NULL;
+ if(surface->surface->fs_support.fs_transform) {
+ free(surface->surface->fs_support.fs_transform);
+ surface->surface->fs_support.fs_transform = NULL;
+ }
break;
case SHELL_SURFACE_PANEL:
case SHELL_SURFACE_BACKGROUND:
@@ -345,6 +349,10 @@ reset_shell_surface_type(struct shell_surface *surface)
return -1;
case SHELL_SURFACE_NONE:
case SHELL_SURFACE_TOPLEVEL:
+ if(surface->saved_x || surface->saved_y) {
+ surface->surface->x = surface->saved_x;
+ surface->surface->y = surface->saved_y;
+ }
case SHELL_SURFACE_TRANSIENT:
case SHELL_SURFACE_POPUP:
break;
@@ -366,6 +374,8 @@ shell_surface_set_toplevel(struct wl_client *client,
weston_surface_damage(surface->surface);
surface->type = SHELL_SURFACE_TOPLEVEL;
+ if(surface->surface->output)
+ surface->surface->output->fs_dirty = 1;
}
static void
@@ -780,6 +790,7 @@ desktop_shell_set_panel(struct wl_client *client,
}
shsurf->type = SHELL_SURFACE_PANEL;
+ surface->type = WESTON_SURFACE_TYPE_PANEL;
shsurf->output = output_resource->data;
wl_list_insert(&shell->panels, &shsurf->link);
--
1.7.5.4
More information about the wayland-devel
mailing list