static void
display_handle_geometry(void *data,
- struct wl_output *output,
- int32_t x, int32_t y, int32_t width, int32_t height)
+ struct wl_output *wl_output,
+ int x,
+ int y,
+ int physical_width,
+ int physical_height,
+ int subpixel,
+ const char *make,
+ const char *model)
+{
+}
+
+static void
+display_handle_mode(void *data,
+ struct wl_output *wl_output,
+ uint32_t flags,
+ int width,
+ int height,
+ int refresh)
{
output_width = width;
output_height = height;
static const struct wl_output_listener output_listener = {
display_handle_geometry,
+ display_handle_mode
};
static void
static void
display_handle_geometry(void *data,
- struct wl_output *output,
- int32_t x, int32_t y, int32_t width, int32_t height)
+ struct wl_output *wl_output,
+ int x, int y,
+ int physical_width,
+ int physical_height,
+ int subpixel,
+ const char *make,
+ const char *model)
{
struct display *display = data;
display->screen_allocation.x = x;
display->screen_allocation.y = y;
+}
+
+static void
+display_handle_mode(void *data,
+ struct wl_output *wl_output,
+ uint32_t flags,
+ int width,
+ int height,
+ int refresh)
+{
+ struct display *display = data;
+
display->screen_allocation.width = width;
display->screen_allocation.height = height;
}
static const struct wl_output_listener output_listener = {
display_handle_geometry,
+ display_handle_mode
};
static void
PFNEGLEXPORTDRMIMAGEMESA export_drm_image;
};
+struct drm_mode {
+ struct wlsc_mode base;
+ drmModeModeInfo mode_info;
+};
+
struct drm_output {
struct wlsc_output base;
- drmModeModeInfo mode;
uint32_t crtc_id;
uint32_t connector_id;
GLuint rbo[2];
if (es->x != output->base.x ||
es->y != output->base.y ||
- es->width != output->base.width ||
- es->height != output->base.height ||
+ es->width != output->base.current->width ||
+ es->height != output->base.current->height ||
es->image == EGL_NO_IMAGE_KHR)
return -1;
return -1;
ret = drmModeAddFB(c->drm.fd,
- output->base.width, output->base.height,
+ output->base.current->width,
+ output->base.current->height,
32, 32, stride, handle, &fb_id);
if (ret)
pixman_region32_intersect_rect(&cursor_region, &cursor_region,
output->base.x, output->base.y,
- output->base.width, output->base.height);
+ output->base.current->width,
+ output->base.current->height);
if (!pixman_region32_not_empty(&cursor_region)) {
ret = 0;
"1024x768"
};
+
+static int
+drm_output_add_mode(struct drm_output *output, drmModeModeInfo *info)
+{
+ struct drm_mode *mode;
+
+ mode = malloc(sizeof *mode);
+ if (mode == NULL)
+ return -1;
+
+ mode->base.flags = 0;
+ mode->base.width = info->hdisplay;
+ mode->base.height = info->vdisplay;
+ mode->base.refresh = info->vrefresh;
+ mode->mode_info = *info;
+ wl_list_insert(output->base.mode_list.prev, &mode->base.link);
+
+ return 0;
+}
+
+static int
+drm_subpixel_to_wayland(int drm_value)
+{
+ switch (drm_value) {
+ default:
+ case DRM_MODE_SUBPIXEL_UNKNOWN:
+ return WL_OUTPUT_SUBPIXEL_UNKNOWN;
+ case DRM_MODE_SUBPIXEL_NONE:
+ return WL_OUTPUT_SUBPIXEL_NONE;
+ case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
+ return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
+ case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
+ return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
+ case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
+ return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
+ case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
+ return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
+ }
+}
+
static int
create_output_for_connector(struct drm_compositor *ec,
drmModeRes *resources,
int x, int y)
{
struct drm_output *output;
+ struct drm_mode *drm_mode;
drmModeEncoder *encoder;
- drmModeModeInfo *mode;
int i, ret;
EGLint handle, stride, attribs[] = {
EGL_WIDTH, 0,
EGL_NONE
};
- output = malloc(sizeof *output);
- if (output == NULL)
- return -1;
-
- if (connector->count_modes > 0)
- mode = &connector->modes[0];
- else
- mode = &builtin_1024x768;
-
encoder = drmModeGetEncoder(ec->drm.fd, connector->encoders[0]);
if (encoder == NULL) {
fprintf(stderr, "No encoder for connector.\n");
return -1;
}
+ output = malloc(sizeof *output);
+ if (output == NULL)
+ return -1;
+
memset(output, 0, sizeof *output);
- wlsc_output_init(&output->base, &ec->base, x, y,
- mode->hdisplay, mode->vdisplay, 0);
+ output->base.x = x;
+ output->base.y = y;
+ output->base.mm_width = connector->mmWidth;
+ output->base.mm_height = connector->mmHeight;
+ output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
+ output->base.make = "unknown";
+ output->base.model = "unknown";
+ wl_list_init(&output->base.mode_list);
output->crtc_id = resources->crtcs[i];
ec->crtc_allocator |= (1 << output->crtc_id);
-
output->connector_id = connector->connector_id;
ec->connector_allocator |= (1 << output->connector_id);
- output->mode = *mode;
+
+ for (i = 0; i < connector->count_modes; i++)
+ drm_output_add_mode(output, &connector->modes[i]);
+ if (connector->count_modes == 0)
+ drm_output_add_mode(output, &builtin_1024x768);
+
+ drm_mode = container_of(output->base.mode_list.next,
+ struct drm_mode, base.link);
+ output->base.current = &drm_mode->base;
+ drm_mode->base.flags =
+ WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+
+ wlsc_output_init(&output->base, &ec->base, x, y, 200, 100, 0);
+
+ wl_list_insert(ec->base.output_list.prev, &output->base.link);
drmModeFreeEncoder(encoder);
for (i = 0; i < 2; i++) {
glBindRenderbuffer(GL_RENDERBUFFER, output->rbo[i]);
- attribs[1] = output->base.width;
- attribs[3] = output->base.height;
+ attribs[1] = output->base.current->width;
+ attribs[3] = output->base.current->height;
output->image[i] =
ec->create_drm_image(ec->base.display, attribs);
ec->base.image_target_renderbuffer_storage(GL_RENDERBUFFER,
NULL, &handle, &stride);
ret = drmModeAddFB(ec->drm.fd,
- output->base.width, output->base.height,
+ output->base.current->width,
+ output->base.current->height,
32, 32, stride, handle, &output->fb_id[i]);
if (ret) {
fprintf(stderr, "failed to add fb %d: %m\n", i);
output->rbo[output->current]);
ret = drmModeSetCrtc(ec->drm.fd, output->crtc_id,
output->fb_id[output->current ^ 1], 0, 0,
- &output->connector_id, 1, &output->mode);
+ &output->connector_id, 1,
+ &drm_mode->mode_info);
if (ret) {
fprintf(stderr, "failed to set mode: %m\n");
return -1;
drm_output_prepare_scanout_surface;
output->base.set_hardware_cursor = drm_output_set_cursor;
- wl_list_insert(ec->base.output_list.prev, &output->base.link);
-
return 0;
}
return -1;
x += container_of(ec->base.output_list.prev, struct wlsc_output,
- link)->width;
+ link)->current->width;
drmModeFreeConnector(connector);
}
/* XXX: not yet needed, we die with 0 outputs */
if (!wl_list_empty(&ec->base.output_list))
- x = last_output->x + last_output->width;
+ x = last_output->x + last_output->current->width;
else
x = 0;
y = 0;
disconnects &= ~(1 << output->connector_id);
printf("connector %d disconnected\n",
output->connector_id);
- x_offset += output->base.width;
+ x_offset += output->base.current->width;
destroy_output(output);
}
}
struct wl_egl_window *egl_window;
} parent;
EGLSurface egl_surface;
+ struct wlsc_mode mode;
};
struct wayland_input {
return -1;
memset(output, 0, sizeof *output);
+ output->mode.flags =
+ WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+ output->mode.width = width;
+ output->mode.height = height;
+ output->mode.refresh = 60;
+ wl_list_init(&output->base.mode_list);
+ wl_list_insert(&output->base.mode_list, &output->mode.link);
+
+ output->base.current = &output->mode;
wlsc_output_init(&output->base, &c->base, 0, 0, width, height,
WL_OUTPUT_FLIPPED);
+
output->parent.surface =
wl_compositor_create_surface(c->parent.compositor);
wl_surface_set_user_data(output->parent.surface, output);
/* parent output interface */
static void
display_handle_geometry(void *data,
- struct wl_output *output,
- int32_t x, int32_t y,
- int32_t width, int32_t height)
+ struct wl_output *wl_output,
+ int x,
+ int y,
+ int physical_width,
+ int physical_height,
+ int subpixel,
+ const char *make,
+ const char *model)
{
struct wayland_compositor *c = data;
c->parent.screen_allocation.x = x;
c->parent.screen_allocation.y = y;
+}
+
+static void
+display_handle_mode(void *data,
+ struct wl_output *wl_output,
+ uint32_t flags,
+ int width,
+ int height,
+ int refresh)
+{
+ struct wayland_compositor *c = data;
+
c->parent.screen_allocation.width = width;
c->parent.screen_allocation.height = height;
}
static const struct wl_output_listener output_listener = {
display_handle_geometry,
+ display_handle_mode
};
/* parent shell interface */
xcb_window_t window;
EGLSurface egl_surface;
+ struct wlsc_mode mode;
};
struct x11_input {
return -1;
memset(output, 0, sizeof *output);
+
+ output->mode.flags =
+ WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+ output->mode.width = width;
+ output->mode.height = height;
+ output->mode.refresh = 60;
+ wl_list_init(&output->base.mode_list);
+ wl_list_insert(&output->base.mode_list, &output->mode.link);
+
+ output->base.current = &output->mode;
wlsc_output_init(&output->base, &c->base, 0, 0, width, height,
WL_OUTPUT_FLIPPED);
background = wlsc_surface_create(output->compositor,
output->x, output->y,
- output->width, output->height);
+ output->current->width,
+ output->current->height);
if (background == NULL)
return NULL;
pixman_region32_union_rect(&compositor->damage_region,
&compositor->damage_region,
output->x, output->y,
- output->width, output->height);
+ output->current->width,
+ output->current->height);
wlsc_compositor_schedule_repaint(compositor);
}
surface.compositor = compositor;
surface.x = output->x;
surface.y = output->y;
- surface.width = output->width;
- surface.height = output->height;
+ surface.width = output->current->width;
+ surface.height = output->current->height;
surface.texture = GL_NONE;
surface.transform = NULL;
output->prepare_render(output);
- glViewport(0, 0, output->width, output->height);
+ glViewport(0, 0, output->current->width, output->current->height);
glUseProgram(ec->texture_shader.program);
glUniformMatrix4fv(ec->texture_shader.proj_uniform,
pixman_region32_intersect_rect(&new_damage,
&ec->damage_region,
output->x, output->y,
- output->width, output->height);
+ output->current->width,
+ output->current->height);
pixman_region32_subtract(&ec->damage_region,
&ec->damage_region, &new_damage);
pixman_region32_union(&total_damage, &new_damage,
}
if (es->fullscreen_output == output) {
- if (es->width < output->width ||
- es->height < output->height)
+ if (es->width < output->current->width ||
+ es->height < output->current->height)
glClear(GL_COLOR_BUFFER_BIT);
wlsc_surface_draw(es, output, &total_damage);
} else {
es->output = NULL;
wl_list_for_each(output, &ec->output_list, link) {
- if (output->x < es->x && es->x < output->x + output->width &&
- output->y < es->y && es->y < output->y + output->height) {
+ if (output->x < es->x && es->x < output->x + output->current->width &&
+ output->y < es->y && es->y < output->y + output->current->height) {
if (output != tmp)
printf("assiging surface %p to output %p\n",
es, output);
wlsc_compositor_wake(ec);
wl_list_for_each(output, &ec->output_list, link) {
- if (output->x <= x && x <= output->x + output->width)
+ if (output->x <= x && x <= output->x + output->current->width)
x_valid = 1;
- if (output->y <= y && y <= output->y + output->height)
+ if (output->y <= y && y <= output->y + output->current->height)
y_valid = 1;
/* FIXME: calculate this only on output addition/deletion */
if (output->y < min_y)
min_y = output->y;
- if (output->x + output->width > max_x)
- max_x = output->x + output->width;
- if (output->y + output->height > max_y)
- max_y = output->y + output->height;
+ if (output->x + output->current->width > max_x)
+ max_x = output->x + output->current->width;
+ if (output->y + output->current->height > max_y)
+ max_y = output->y + output->current->height;
}
if (!x_valid) {
{
struct wlsc_output *output =
container_of(global, struct wlsc_output, object);
+ struct wlsc_mode *mode;
wl_client_post_event(client, global,
WL_OUTPUT_GEOMETRY,
- output->x, output->y,
- output->width, output->height);
+ output->x,
+ output->y,
+ output->mm_width,
+ output->mm_height,
+ output->subpixel,
+ output->make, output->model);
+
+ wl_list_for_each (mode, &output->mode_list, link) {
+ wl_client_post_event(client, global,
+ WL_OUTPUT_MODE,
+ mode->flags,
+ mode->width, mode->height, mode->refresh);
+ }
}
static const char vertex_shader[] =
wlsc_matrix_init(&output->matrix);
wlsc_matrix_translate(&output->matrix,
- -output->x - output->width / 2.0,
- -output->y - output->height / 2.0, 0);
+ -output->x - output->current->width / 2.0,
+ -output->y - output->current->height / 2.0, 0);
flip = (output->flags & WL_OUTPUT_FLIPPED) ? -1 : 1;
wlsc_matrix_scale(&output->matrix,
- 2.0 / output->width,
- flip * 2.0 / output->height, 1);
+ 2.0 / output->current->width,
+ flip * 2.0 / output->current->height, 1);
pixman_region32_union_rect(&c->damage_region,
&c->damage_region,
- x, y, output->width, output->height);
+ x, y,
+ output->current->width,
+ output->current->height);
}
WL_EXPORT void
output->compositor = c;
output->x = x;
output->y = y;
- output->width = width;
- output->height = height;
+ output->mm_width = width;
+ output->mm_height = height;
output->background =
background_create(output, option_background);
struct wlsc_surface;
struct wlsc_input_device;
+struct wlsc_mode {
+ uint32_t flags;
+ int32_t width, height;
+ uint32_t refresh;
+ struct wl_list link;
+};
+
struct wlsc_output {
struct wl_object object;
struct wl_list link;
struct wlsc_compositor *compositor;
struct wlsc_surface *background;
struct wlsc_matrix matrix;
- int32_t x, y, width, height;
+ int32_t x, y, mm_width, mm_height;
pixman_region32_t previous_damage_region;
uint32_t flags;
int repaint_needed;
int finished;
+ char *make, *model;
+ uint32_t subpixel;
+
+ struct wlsc_mode *current;
+ struct wl_list mode_list;
+
int (*prepare_render)(struct wlsc_output *output);
int (*present)(struct wlsc_output *output);
int (*prepare_scanout_surface)(struct wlsc_output *output,
if (!wl_buffer_is_shm(buffer))
return;
- if (buffer->width < output->width || buffer->height < output->height)
+ if (buffer->width < output->current->width ||
+ buffer->height < output->current->height)
return;
glPixelStorei(GL_PACK_ALIGNMENT, 1);
- glReadPixels(0, 0, output->width, output->height,
+ glReadPixels(0, 0, output->current->width, output->current->height,
GL_RGBA, GL_UNSIGNED_BYTE,
wl_shm_buffer_get_data(buffer));
}
es->saved_x = es->x;
es->saved_y = es->y;
- es->x = (output->width - es->width) / 2;
- es->y = (output->height - es->height) / 2;
+ es->x = (output->current->width - es->width) / 2;
+ es->y = (output->current->height - es->height) / 2;
es->fullscreen_output = output;
wlsc_surface_damage(es);
es->map_type = WLSC_SURFACE_MAP_FULLSCREEN;
attach(struct wlsc_shell *shell, struct wlsc_surface *es)
{
if (es->map_type == WLSC_SURFACE_MAP_FULLSCREEN) {
- es->x = (es->fullscreen_output->width - es->width) / 2;
- es->y = (es->fullscreen_output->height - es->height) / 2;
+ es->x = (es->fullscreen_output->current->width - es->width) / 2;
+ es->y = (es->fullscreen_output->current->height - es->height) / 2;
}
}