Exemple #1
0
static void checkScaleChange(_GLFWwindow* window)
{
    int scaledWidth, scaledHeight;
    int scale = 1;
    int i;
    int monitorScale;

    // Check if we will be able to set the buffer scale or not.
    if (_glfw.wl.compositorVersion < 3)
        return;

    // Get the scale factor from the highest scale monitor.
    for (i = 0; i < window->wl.monitorsCount; ++i)
    {
        monitorScale = window->wl.monitors[i]->wl.scale;
        if (scale < monitorScale)
            scale = monitorScale;
    }

    // Only change the framebuffer size if the scale changed.
    if (scale != window->wl.scale)
    {
        window->wl.scale = scale;
        scaledWidth = window->wl.width * scale;
        scaledHeight = window->wl.height * scale;
        wl_surface_set_buffer_scale(window->wl.surface, scale);
        wl_egl_window_resize(window->wl.native, scaledWidth, scaledHeight, 0, 0);
        _glfwInputFramebufferSize(window, scaledWidth, scaledHeight);
    }
}
bool WaylandEGLContext::create_context ()
{
    int scale = gdk_window_get_scale_factor (gdk_window);
    gdk_window_get_geometry (gdk_window, &x, &y, &width, &height);

    EGLint surface_attribs[] = {
        EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
        EGL_RED_SIZE, 8,
        EGL_BLUE_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_NONE
    };

    EGLint context_attribs[] = {
        EGL_CONTEXT_OPENGL_PROFILE_MASK, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT,
        EGL_NONE
    };

    EGLint num_configs = 0;

    if (!subsurface)
        return false;

    egl_display = eglGetDisplay ((EGLNativeDisplayType) display);
    eglInitialize (egl_display, NULL, NULL);

    if (!eglChooseConfig (egl_display, surface_attribs, &egl_config, 1, &num_configs))
    {
        printf ("Couldn't find matching config.\n");
        return false;
    }
    eglBindAPI (EGL_OPENGL_API);

    egl_window  = wl_egl_window_create (child, width * scale, height * scale);
    if (!egl_window)
    {
        printf ("Couldn't create window.\n");
        return false;
    }

    egl_surface = eglCreateWindowSurface (egl_display, egl_config, (EGLNativeWindowType) egl_window, NULL);
    if (!egl_surface)
    {
        printf ("Couldn't create surface.\n");
        return false;
    }

    egl_context = eglCreateContext (egl_display, egl_config, EGL_NO_CONTEXT, context_attribs);
    if (!egl_context)
    {
        printf ("Couldn't create context.\n");
        return false;
    }

    wl_surface_set_buffer_scale (child, scale);
    gdk_window_invalidate_rect (gdk_window, NULL, FALSE);

    return true;
}
Exemple #3
0
int window_render(struct window *window) {
	window->frame_cb = wl_surface_frame(window->surface);
	wl_callback_add_listener(window->frame_cb, &listener, window);

	wl_surface_attach(window->surface, window->buffer->buffer, 0, 0);
	wl_surface_set_buffer_scale(window->surface, window->scale);
	wl_surface_damage(window->surface, 0, 0, window->width, window->height);
	wl_surface_commit(window->surface);

	return 1;
}
Exemple #4
0
void render_frame(struct swaynag *swaynag) {
	if (!swaynag->run_display) {
		return;
	}

	cairo_surface_t *recorder = cairo_recording_surface_create(
			CAIRO_CONTENT_COLOR_ALPHA, NULL);
	cairo_t *cairo = cairo_create(recorder);
	cairo_save(cairo);
	cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR);
	cairo_paint(cairo);
	cairo_restore(cairo);
	uint32_t height = render_to_cairo(cairo, swaynag);
	if (height != swaynag->height) {
		zwlr_layer_surface_v1_set_size(swaynag->layer_surface, 0, height);
		zwlr_layer_surface_v1_set_exclusive_zone(swaynag->layer_surface,
				height);
		wl_surface_commit(swaynag->surface);
		wl_display_roundtrip(swaynag->display);
	} else {
		swaynag->current_buffer = get_next_buffer(swaynag->shm,
				swaynag->buffers,
				swaynag->width * swaynag->scale,
				swaynag->height * swaynag->scale);
		if (!swaynag->current_buffer) {
			sway_log(SWAY_DEBUG, "Failed to get buffer. Skipping frame.");
			goto cleanup;
		}

		cairo_t *shm = swaynag->current_buffer->cairo;
		cairo_save(shm);
		cairo_set_operator(shm, CAIRO_OPERATOR_CLEAR);
		cairo_paint(shm);
		cairo_restore(shm);
		cairo_set_source_surface(shm, recorder, 0.0, 0.0);
		cairo_paint(shm);

		wl_surface_set_buffer_scale(swaynag->surface, swaynag->scale);
		wl_surface_attach(swaynag->surface,
				swaynag->current_buffer->buffer, 0, 0);
		wl_surface_damage(swaynag->surface, 0, 0,
				swaynag->width, swaynag->height);
		wl_surface_commit(swaynag->surface);
		wl_display_roundtrip(swaynag->display);
	}

cleanup:
	cairo_surface_destroy(recorder);
	cairo_destroy(cairo);
}
Exemple #5
0
struct window *window_setup(struct registry *registry, uint32_t width, uint32_t height,
		int32_t scale, bool shell_surface) {
	struct window *window = malloc(sizeof(struct window));
	memset(window, 0, sizeof(struct window));
	window->width = width;
	window->height = height;
	window->scale = scale;
	window->registry = registry;
	window->font = "monospace 10";

	window->surface = wl_compositor_create_surface(registry->compositor);
	if (shell_surface) {
		window_make_shell(window);
	}
	if (registry->pointer) {
		wl_pointer_add_listener(registry->pointer, &pointer_listener, window);
	}

	get_next_buffer(window);

	if (registry->pointer) {
		char *cursor_theme = getenv("SWAY_CURSOR_THEME");
		if (!cursor_theme) {
			cursor_theme = "default";
		}
		char *cursor_size = getenv("SWAY_CURSOR_SIZE");
		if (!cursor_size) {
			cursor_size = "16";
		}

		sway_log(L_DEBUG, "Cursor scale: %d", scale);
		window->cursor.cursor_theme = wl_cursor_theme_load(cursor_theme,
				atoi(cursor_size) * scale, registry->shm);
		window->cursor.cursor = wl_cursor_theme_get_cursor(window->cursor.cursor_theme, "left_ptr");
		window->cursor.surface = wl_compositor_create_surface(registry->compositor);

		struct wl_cursor_image *image = window->cursor.cursor->images[0];
		struct wl_buffer *cursor_buf = wl_cursor_image_get_buffer(image);
		wl_surface_attach(window->cursor.surface, cursor_buf, 0, 0);
		wl_surface_set_buffer_scale(window->cursor.surface, scale);
		wl_surface_damage(window->cursor.surface, 0, 0,
				image->width, image->height);
		wl_surface_commit(window->cursor.surface);
	}

	return window;
}
Exemple #6
0
static void egl_resize(struct vo_wayland_state *wl)
{
    int32_t x = wl->window.sh_x;
    int32_t y = wl->window.sh_y;
    int32_t width = wl->window.sh_width;
    int32_t height = wl->window.sh_height;
    int32_t scale = 1;

    if (!wl->egl_context.egl_window)
        return;

    if (wl->display.current_output)
        scale = wl->display.current_output->scale;

    // get the real size of the window
    // this improves moving the window while resizing it
    wl_egl_window_get_attached_size(wl->egl_context.egl_window,
                                    &wl->window.width,
                                    &wl->window.height);

    MP_VERBOSE(wl, "resizing %dx%d -> %dx%d\n", wl->window.width,
                                                wl->window.height,
                                                width,
                                                height);

    if (x != 0)
        x = wl->window.width - width;

    if (y != 0)
        y = wl->window.height - height;

    wl_surface_set_buffer_scale(wl->window.video_surface, scale);
    wl_egl_window_resize(wl->egl_context.egl_window, scale*width, scale*height, x, y);

    wl->window.width = width;
    wl->window.height = height;

    /* set size for mplayer */
    wl->vo->dwidth  = scale*wl->window.width;
    wl->vo->dheight = scale*wl->window.height;

    wl->vo->want_redraw = true;
    wl->window.events = 0;
}
Exemple #7
0
static void setCursor(_GLFWwindow* window, const char* name)
{
    struct wl_buffer* buffer;
    struct wl_cursor* cursor;
    struct wl_cursor_image* image;
    struct wl_surface* surface = _glfw.wl.cursorSurface;
    struct wl_cursor_theme* theme = _glfw.wl.cursorTheme;
    int scale = 1;

    if (window->wl.scale > 1 && _glfw.wl.cursorThemeHiDPI)
    {
        // We only support up to scale=2 for now, since libwayland-cursor
        // requires us to load a different theme for each size.
        scale = 2;
        theme = _glfw.wl.cursorThemeHiDPI;
    }

    cursor = wl_cursor_theme_get_cursor(theme, name);
    if (!cursor)
    {
        _glfwInputError(GLFW_PLATFORM_ERROR,
                        "Wayland: Standard cursor not found");
        return;
    }
    // TODO: handle animated cursors too.
    image = cursor->images[0];

    if (!image)
        return;

    buffer = wl_cursor_image_get_buffer(image);
    if (!buffer)
        return;
    wl_pointer_set_cursor(_glfw.wl.pointer, _glfw.wl.serial,
                          surface,
                          image->hotspot_x / scale,
                          image->hotspot_y / scale);
    wl_surface_set_buffer_scale(surface, scale);
    wl_surface_attach(surface, buffer, 0, 0);
    wl_surface_damage(surface, 0, 0,
                      image->width, image->height);
    wl_surface_commit(surface);
}
Exemple #8
0
static void
redraw(void *data, struct wl_callback *callback, uint32_t time)
{
	struct window *window = data;
	struct buffer *buffer;
	int off_x, off_y, bwidth, bheight, bborder, bpitch, bradius;
	uint32_t *buffer_data;
	float bx, by;

	buffer = window_next_buffer(window);
	if (!buffer) {
		fprintf(stderr,
			!callback ? "Failed to create the first buffer.\n" :
			"Both buffers busy at redraw(). Server bug?\n");
		abort();
	}

	/* Rotate the damage, but keep the even/odd parity so the
	 * dimensions of the buffers don't change */
	if (window->flags & WINDOW_FLAG_ROTATING_TRANSFORM)
		window->transform = (window->transform + 2) % 8;

	switch (window->transform) {
	default:
	case WL_OUTPUT_TRANSFORM_NORMAL:
	case WL_OUTPUT_TRANSFORM_180:
	case WL_OUTPUT_TRANSFORM_FLIPPED:
	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
		bwidth = window->width * window->scale;
		bheight = window->height * window->scale;
		break;
	case WL_OUTPUT_TRANSFORM_90:
	case WL_OUTPUT_TRANSFORM_270:
	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
		bwidth = window->height * window->scale;
		bheight = window->width * window->scale;
		break;
	}

	bpitch = bwidth;

	bborder = window->border * window->scale;
	bradius = window->ball.radius * window->scale;

	buffer_data = buffer->shm_data;
	if (window->viewport) {
		/* Fill the whole thing with red to detect viewport errors */
		paint_box(buffer->shm_data, bpitch, 0, 0, bwidth, bheight,
			  0xffff0000);

		/* The buffer is the same size.  However, we crop it
		 * and scale it up by a factor of 2 */
		bborder /= 2;
		bradius /= 2;
		bwidth /= 2;
		bheight /= 2;

		/* Offset the drawing region */
		off_x = (window->width / 3) * window->scale;
		off_y = (window->height / 5) * window->scale;
		switch (window->transform) {
		default:
		case WL_OUTPUT_TRANSFORM_NORMAL:
			buffer_data += off_y * bpitch + off_x;
			break;
		case WL_OUTPUT_TRANSFORM_90:
			buffer_data += off_x * bpitch + (bwidth - off_y);
			break;
		case WL_OUTPUT_TRANSFORM_180:
			buffer_data += (bheight - off_y) * bpitch +
				       (bwidth - off_x);
			break;
		case WL_OUTPUT_TRANSFORM_270:
			buffer_data += (bheight - off_x) * bpitch + off_y;
			break;
		case WL_OUTPUT_TRANSFORM_FLIPPED:
			buffer_data += off_y * bpitch + (bwidth - off_x);
			break;
		case WL_OUTPUT_TRANSFORM_FLIPPED_90:
			buffer_data += (bheight - off_x) * bpitch +
				       (bwidth - off_y);
			break;
		case WL_OUTPUT_TRANSFORM_FLIPPED_180:
			buffer_data += (bheight - off_y) * bpitch + off_x;
			break;
		case WL_OUTPUT_TRANSFORM_FLIPPED_270:
			buffer_data += off_x * bpitch + off_y;
			break;
		}
		wl_viewport_set_source(window->viewport,
				       wl_fixed_from_int(window->width / 3),
				       wl_fixed_from_int(window->height / 5),
				       wl_fixed_from_int(window->width / 2),
				       wl_fixed_from_int(window->height / 2));
	}

	/* Paint the border */
	paint_box(buffer_data, bpitch, 0, 0, bwidth, bborder, 0xffffffff);
	paint_box(buffer_data, bpitch, 0, 0, bborder, bheight, 0xffffffff);
	paint_box(buffer_data, bpitch,
		  bwidth - bborder, 0, bborder, bheight, 0xffffffff);
	paint_box(buffer_data, bpitch,
		  0, bheight - bborder, bwidth, bborder, 0xffffffff);

	/* fill with translucent */
	paint_box(buffer_data, bpitch, bborder, bborder,
		  bwidth - 2 * bborder, bheight - 2 * bborder, 0x80000000);

	/* Damage where the ball was */
	wl_surface_damage(window->surface,
			  window->ball.x - window->ball.radius,
			  window->ball.y - window->ball.radius,
			  window->ball.radius * 2 + 1,
			  window->ball.radius * 2 + 1);

	window_advance_game(window, time);

	window_get_transformed_ball(window, &bx, &by);

	/* Paint the ball */
	paint_circle(buffer_data, bpitch, bx, by, bradius, 0xff00ff00);

	if (print_debug) {
		printf("Ball now located at (%f, %f)\n",
		       window->ball.x, window->ball.y);

		printf("Circle painted at (%f, %f), radius %d\n", bx, by,
		       bradius);

		printf("Buffer damage rectangle: (%d, %d) @ %dx%d\n",
		       (int)(bx - bradius), (int)(by - bradius),
		       bradius * 2 + 1, bradius * 2 + 1);
	}

	/* Damage where the ball is now */
	wl_surface_damage(window->surface,
			  window->ball.x - window->ball.radius,
			  window->ball.y - window->ball.radius,
			  window->ball.radius * 2 + 1,
			  window->ball.radius * 2 + 1);

	wl_surface_attach(window->surface, buffer->buffer, 0, 0);

	if (window->display->compositor_version >= 2 &&
	    (window->transform != WL_OUTPUT_TRANSFORM_NORMAL ||
	     window->flags & WINDOW_FLAG_ROTATING_TRANSFORM))
		wl_surface_set_buffer_transform(window->surface,
						window->transform);

	if (window->viewport)
		wl_viewport_set_destination(window->viewport,
					    window->width,
					    window->height);

	if (window->scale != 1)
		wl_surface_set_buffer_scale(window->surface,
					    window->scale);

	if (callback)
		wl_callback_destroy(callback);

	window->callback = wl_surface_frame(window->surface);
	wl_callback_add_listener(window->callback, &frame_listener, window);
	wl_surface_commit(window->surface);
	buffer->busy = 1;
}
Exemple #9
0
static bool gfx_ctx_wl_set_video_mode(void *data,
      video_frame_info_t *video_info,
      unsigned width, unsigned height,
      bool fullscreen)
{
#ifdef HAVE_EGL
   EGLint egl_attribs[16];
   EGLint *attr              = egl_fill_attribs(
         (gfx_ctx_wayland_data_t*)data, egl_attribs);
#endif
   gfx_ctx_wayland_data_t *wl = (gfx_ctx_wayland_data_t*)data;

   wl->width                  = width  ? width  : DEFAULT_WINDOWED_WIDTH;
   wl->height                 = height ? height : DEFAULT_WINDOWED_HEIGHT;

   wl->surface                = wl_compositor_create_surface(wl->compositor);

   wl_surface_set_buffer_scale(wl->surface, wl->buffer_scale);

   switch (wl_api)
   {
      case GFX_CTX_OPENGL_API:
      case GFX_CTX_OPENGL_ES_API:
      case GFX_CTX_OPENVG_API:
#ifdef HAVE_EGL
         wl->win        = wl_egl_window_create(wl->surface, wl->width, wl->height);
#endif
         break;
      case GFX_CTX_NONE:
      default:
         break;
   }
   wl->shell_surf = wl_shell_get_shell_surface(wl->shell, wl->surface);

   wl_shell_surface_add_listener(wl->shell_surf, &shell_surface_listener, wl);
   wl_shell_surface_set_toplevel(wl->shell_surf);
   wl_shell_surface_set_class(wl->shell_surf, "RetroArch");
   wl_shell_surface_set_title(wl->shell_surf, "RetroArch");

   switch (wl_api)
   {
      case GFX_CTX_OPENGL_API:
      case GFX_CTX_OPENGL_ES_API:
      case GFX_CTX_OPENVG_API:
#ifdef HAVE_EGL

         if (!egl_create_context(&wl->egl, (attr != egl_attribs) ? egl_attribs : NULL))
         {
            egl_report_error();
            goto error;
         }

         if (!egl_create_surface(&wl->egl, (EGLNativeWindowType)wl->win))
            goto error;
         egl_set_swap_interval(&wl->egl, wl->egl.interval);
#endif
         break;
      case GFX_CTX_NONE:
      default:
         break;
   }

   if (fullscreen)
      wl_shell_surface_set_fullscreen(wl->shell_surf,
            WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, NULL);

   flush_wayland_fd(&wl->input);

   switch (wl_api)
   {
      case GFX_CTX_VULKAN_API:
         wl_display_roundtrip(wl->input.dpy);

#ifdef HAVE_VULKAN
         if (!vulkan_surface_create(&wl->vk, VULKAN_WSI_WAYLAND,
                  wl->input.dpy, wl->surface, 
                  wl->width, wl->height, wl->swap_interval))
            goto error;
#endif
         break;
      case GFX_CTX_NONE:
      default:
         break;
   }

   if (fullscreen)
   {
      wl->cursor.visible = false;
      gfx_ctx_wl_show_mouse(wl, false);
   }
   else
      wl->cursor.visible = true;

   return true;

error:
   gfx_ctx_wl_destroy(data);
   return false;
}
Exemple #10
0
static gboolean
_eventd_nd_wl_create_buffer(EventdNdSurface *self)
{
    struct wl_shm_pool *pool;
    struct wl_buffer *buffer;
    gint fd;
    gpointer data;
    gint width, height, stride;
    gsize size;

    width = self->width * self->context->scale;
    height = self->height * self->context->scale;
    stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
    size = stride * height;

    gchar *filename;
    filename = g_build_filename(g_get_user_runtime_dir(), PACKAGE_NAME G_DIR_SEPARATOR_S "wayland-surface", NULL);
    fd = g_open(filename, O_CREAT | O_RDWR | O_CLOEXEC, 0);
    g_unlink(filename);
    g_free(filename);
    if ( fd < 0 )
    {
        g_warning("creating a buffer file for %zu B failed: %s\n", size, g_strerror(errno));
        return FALSE;
    }
    if ( ftruncate(fd, size) < 0 )
    {
        close(fd);
        return FALSE;
    }

    data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if ( data == MAP_FAILED )
    {
        g_warning("mmap failed: %s\n", g_strerror(errno));
        close(fd);
        return FALSE;
    }

    cairo_surface_t *cairo_surface;
    cairo_surface = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, width, height, 4 * width);
    cairo_surface_set_device_scale(cairo_surface, self->context->scale, self->context->scale);
    self->context->nd->notification_draw(self->notification, cairo_surface, TRUE);
    cairo_surface_destroy(cairo_surface);

    munmap(data, size);

    pool = wl_shm_create_pool(self->context->shm, fd, size);
    buffer = wl_shm_pool_create_buffer(pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888);
    wl_shm_pool_destroy(pool);
    close(fd);

    if ( self->buffer != NULL )
        _eventd_nd_wl_buffer_release(self->buffer, self->buffer->buffer);

    self->buffer = g_new0(EventdNdWlBuffer, 1);
    self->buffer->buffer = buffer;
    self->buffer->data = data;
    self->buffer->size = size;

    wl_buffer_add_listener(buffer, &_eventd_nd_wl_buffer_listener, self->buffer);

    wl_surface_damage(self->surface, 0, 0, self->width, self->height);
    wl_surface_attach(self->surface, self->buffer->buffer, 0, 0);
    if ( wl_surface_get_version(self->surface) >= WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION )
        wl_surface_set_buffer_scale(self->surface, self->context->scale);
    wl_surface_commit(self->surface);

    return TRUE;
}
Exemple #11
0
static bool wayland_vk_init(struct ra_ctx *ctx)
{
    struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
    struct mpvk_ctx *vk = &p->vk;
    int msgl = ctx->opts.probing ? MSGL_V : MSGL_ERR;

    if (!mpvk_instance_init(vk, ctx->log, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
                            ctx->opts.debug))
        goto error;

    if (!vo_wayland_init(ctx->vo))
        goto error;

    VkWaylandSurfaceCreateInfoKHR wlinfo = {
         .sType   = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
         .display = ctx->vo->wl->display,
         .surface = ctx->vo->wl->surface,
    };

    VkResult res = vkCreateWaylandSurfaceKHR(vk->inst, &wlinfo, MPVK_ALLOCATOR,
                                             &vk->surf);
    if (res != VK_SUCCESS) {
        MP_MSG(ctx, msgl, "Failed creating Wayland surface: %s\n", vk_err(res));
        goto error;
    }

    /* Because in Wayland clients render whenever they receive a callback from
     * the compositor, and the fact that the compositor usually stops sending
     * callbacks once the surface is no longer visible, using FIFO here would
     * mean the entire player would block on acquiring swapchain images. Hence,
     * use MAILBOX to guarantee that there'll always be a swapchain image and
     * the player won't block waiting on those */
    if (!ra_vk_ctx_init(ctx, vk, VK_PRESENT_MODE_MAILBOX_KHR))
        goto error;

    return true;

error:
    wayland_vk_uninit(ctx);
    return false;
}

static void resize(struct ra_ctx *ctx)
{
    struct vo_wayland_state *wl = ctx->vo->wl;

    MP_VERBOSE(wl, "Handling resize on the vk side\n");

    const int32_t width = wl->scaling*mp_rect_w(wl->geometry);
    const int32_t height = wl->scaling*mp_rect_h(wl->geometry);

    wl_surface_set_buffer_scale(wl->surface, wl->scaling);

    wl->vo->dwidth  = width;
    wl->vo->dheight = height;
}

static bool wayland_vk_reconfig(struct ra_ctx *ctx)
{
    if (!vo_wayland_reconfig(ctx->vo))
        return false;

    return true;
}

static int wayland_vk_control(struct ra_ctx *ctx, int *events, int request, void *arg)
{
    int ret = vo_wayland_control(ctx->vo, events, request, arg);
    if (*events & VO_EVENT_RESIZE) {
        resize(ctx);
        if (ra_vk_ctx_resize(ctx->swapchain, ctx->vo->dwidth, ctx->vo->dheight))
            return VO_ERROR;
    }
    return ret;
}