/* * This function will effectively set the pointer (mouse) cursor * depending on the GLUT_CURSOR_* choice. */ void fghPointerSetCursor( SFG_Window* window, struct wl_pointer* pointer, uint32_t serial ) { struct wl_cursor_image* image; struct wl_buffer* buffer; image = window->Window.pContext.cursor->images[0]; buffer = wl_cursor_image_get_buffer( image ); wl_surface_attach( window->Window.pContext.cursor_surface, buffer, 0, 0 ); wl_surface_damage( window->Window.pContext.cursor_surface, 0, 0, image->width, image->height ); wl_surface_commit( window->Window.pContext.cursor_surface ); wl_pointer_set_cursor( pointer, serial, window->Window.pContext.cursor_surface, image->hotspot_x, image->hotspot_y ); }
static void window_attach_surface(struct window *window) { struct display *display = window->display; struct wl_buffer *buffer; int32_t x, y; if (window->pending_surface != NULL) return; window->pending_surface = window->cairo_surface; window->cairo_surface = NULL; buffer = display_get_buffer_for_surface(display, window->pending_surface); if (window->resize_edges & WINDOW_RESIZING_LEFT) x = window->server_allocation.width - window->allocation.width; else x = 0; if (window->resize_edges & WINDOW_RESIZING_TOP) y = window->server_allocation.height - window->allocation.height; else y = 0; window->server_allocation = window->allocation; window->resize_edges = 0; wl_surface_attach(window->surface, buffer, x, y); wl_display_sync_callback(display->display, free_surface, window); if (!window->mapped) { wl_surface_map_toplevel(window->surface); window->mapped = 1; } wl_surface_damage(window->surface, 0, 0, window->allocation.width, window->allocation.height); }
static Eina_Bool _ecore_wl_input_cursor_update(void *data) { struct wl_cursor_image *cursor_image; struct wl_buffer *buffer; Ecore_Wl_Input *input = data; unsigned int delay; cursor_image = input->cursor->images[input->cursor_current_index]; if (!cursor_image) return ECORE_CALLBACK_RENEW; if ((buffer = wl_cursor_image_get_buffer(cursor_image))) { ecore_wl_input_pointer_set(input, input->cursor_surface, cursor_image->hotspot_x, cursor_image->hotspot_y); wl_surface_attach(input->cursor_surface, buffer, 0, 0); wl_surface_damage(input->cursor_surface, 0, 0, cursor_image->width, cursor_image->height); wl_surface_commit(input->cursor_surface); if ((input->cursor->image_count > 1) && (!input->cursor_frame_cb)) _ecore_wl_input_cb_pointer_frame(input, NULL, 0); } if (input->cursor->image_count <= 1) return ECORE_CALLBACK_CANCEL; delay = cursor_image->delay; input->cursor_current_index = (input->cursor_current_index + 1) % input->cursor->image_count; if (!input->cursor_timer) input->cursor_timer = ecore_timer_loop_add(delay / 1000.0, _ecore_wl_input_cursor_update, input); else ecore_timer_interval_set(input->cursor_timer, delay / 1000.0); return ECORE_CALLBACK_RENEW; }
static void pointer_handle_enter (void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx_w, wl_fixed_t sy_w) { GstGLWindowWaylandEGL *window_egl = data; struct wl_buffer *buffer; struct wl_cursor_image *image = NULL; window_egl->display.serial = serial; if (window_egl->display.default_cursor) { image = window_egl->display.default_cursor->images[0]; buffer = wl_cursor_image_get_buffer (image); wl_pointer_set_cursor (pointer, serial, window_egl->display.cursor_surface, image->hotspot_x, image->hotspot_y); wl_surface_attach (window_egl->display.cursor_surface, buffer, 0, 0); wl_surface_damage (window_egl->display.cursor_surface, 0, 0, image->width, image->height); wl_surface_commit (window_egl->display.cursor_surface); } }
int main(int argc, char **argv) { struct sigaction sigint; struct display *display; struct window *window; int ret = 0; display = create_display(); window = create_window(display, 250, 250); if (!window) return 1; sigint.sa_handler = signal_int; sigemptyset(&sigint.sa_mask); sigint.sa_flags = SA_RESETHAND; sigaction(SIGINT, &sigint, NULL); /* Initialise damage to full surface, so the padding gets painted */ wl_surface_damage(window->surface, 0, 0, window->width, window->height); redraw(window, NULL, 0); while (running && ret != -1) ret = wl_display_dispatch(display->display); fprintf(stderr, "simple-shm exiting\n"); if (window->display->ivi_application) { ivi_surface_destroy(window->ivi_surface); ivi_application_destroy(window->display->ivi_application); } destroy_window(window); destroy_display(display); return 0; }
static void gst_wl_window_resize_video_surface (GstWlWindow * window, gboolean commit) { GstVideoRectangle src = { 0, }; GstVideoRectangle dst = { 0, }; GstVideoRectangle res; /* center the video_subsurface inside area_subsurface */ src.w = window->video_width; src.h = window->video_height; dst.w = window->render_rectangle.w; dst.h = window->render_rectangle.h; if (window->video_viewport) { gst_video_sink_center_rect (src, dst, &res, TRUE); wp_viewport_set_destination (window->video_viewport, res.w, res.h); } else { gst_video_sink_center_rect (src, dst, &res, FALSE); } wl_subsurface_set_position (window->video_subsurface, res.x, res.y); if (commit) { wl_surface_damage (window->video_surface_wrapper, 0, 0, res.w, res.h); wl_surface_commit (window->video_surface_wrapper); } if (gst_wl_window_is_toplevel (window)) { struct wl_region *region; region = wl_compositor_create_region (window->display->compositor); wl_region_add (region, 0, 0, window->render_rectangle.w, window->render_rectangle.h); wl_surface_set_input_region (window->area_surface, region); wl_region_destroy (region); } /* this is saved for use in wl_surface_damage */ window->video_rectangle = res; }
void move_client(struct client *client, int x, int y) { struct surface *surface = client->surface; int done; client->surface->x = x; client->surface->y = y; wl_test_move_surface(client->test->wl_test, surface->wl_surface, surface->x, surface->y); /* The attach here is necessary because commit() will call congfigure * only on surfaces newly attached, and the one that sets the surface * position is the configure. */ wl_surface_attach(surface->wl_surface, surface->wl_buffer, 0, 0); wl_surface_damage(surface->wl_surface, 0, 0, surface->width, surface->height); frame_callback_set(surface->wl_surface, &done); wl_surface_commit(surface->wl_surface); frame_callback_wait(client, &done); }
static void gst_wl_window_resize_internal (GstWlWindow * window, gboolean commit) { GstVideoRectangle src, res; src.w = window->video_width; src.h = window->video_height; gst_video_sink_center_rect (src, window->render_rectangle, &res, TRUE); if (window->subsurface) wl_subsurface_set_position (window->subsurface, window->render_rectangle.x + res.x, window->render_rectangle.y + res.y); wl_viewport_set_destination (window->viewport, res.w, res.h); if (commit) { wl_surface_damage (window->surface, 0, 0, res.w, res.h); wl_surface_commit (window->surface); } /* this is saved for use in wl_surface_damage */ window->surface_width = res.w; window->surface_height = res.h; }
static void redraw(void *data, struct wl_callback *callback, uint32_t time) { struct window *window = data; uint32_t *p; int i, end, offset; p = window->shm_data; end = window->width * window->height; offset = time >> 4; for (i = 0; i < end; i++) p[i] = (i + offset) * 0x0080401; wl_surface_attach(window->surface, window->buffer, 0, 0); wl_surface_damage(window->surface, 0, 0, window->width, window->height); if (callback) wl_callback_destroy(callback); window->callback = wl_surface_frame(window->surface); wl_callback_add_listener(window->callback, &frame_listener, window); }
static gboolean gst_vaapi_window_wayland_render (GstVaapiWindow * window, GstVaapiSurface * surface, const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect, guint flags) { GstVaapiWindowWaylandPrivate *const priv = GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window); GstVaapiDisplay *const display = GST_VAAPI_OBJECT_DISPLAY (window); struct wl_display *const wl_display = GST_VAAPI_OBJECT_NATIVE_DISPLAY (window); struct wl_buffer *buffer; FrameState *frame; guint width, height, va_flags; VAStatus status; gboolean need_vpp = FALSE; /* Check that we don't need to crop source VA surface */ gst_vaapi_surface_get_size (surface, &width, &height); if (src_rect->x != 0 || src_rect->y != 0) need_vpp = TRUE; if (src_rect->width != width || src_rect->height != height) need_vpp = TRUE; /* Check that we don't render to a subregion of this window */ if (dst_rect->x != 0 || dst_rect->y != 0) need_vpp = TRUE; if (dst_rect->width != window->width || dst_rect->height != window->height) need_vpp = TRUE; /* Try to construct a Wayland buffer from VA surface as is (without VPP) */ if (!need_vpp) { GST_VAAPI_OBJECT_LOCK_DISPLAY (window); va_flags = from_GstVaapiSurfaceRenderFlags (flags); status = vaGetSurfaceBufferWl (GST_VAAPI_DISPLAY_VADISPLAY (display), GST_VAAPI_OBJECT_ID (surface), va_flags & (VA_TOP_FIELD | VA_BOTTOM_FIELD), &buffer); GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window); if (status == VA_STATUS_ERROR_FLAG_NOT_SUPPORTED) need_vpp = TRUE; else if (!vaapi_check_status (status, "vaGetSurfaceBufferWl()")) return FALSE; } /* Try to construct a Wayland buffer with VPP */ if (need_vpp) { if (priv->use_vpp) { GstVaapiSurface *const vpp_surface = vpp_convert (window, surface, src_rect, dst_rect, flags); if (G_UNLIKELY (!vpp_surface)) need_vpp = FALSE; else { surface = vpp_surface; width = window->width; height = window->height; } } GST_VAAPI_OBJECT_LOCK_DISPLAY (window); status = vaGetSurfaceBufferWl (GST_VAAPI_DISPLAY_VADISPLAY (display), GST_VAAPI_OBJECT_ID (surface), VA_FRAME_PICTURE, &buffer); GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window); if (!vaapi_check_status (status, "vaGetSurfaceBufferWl()")) return FALSE; } /* Wait for the previous frame to complete redraw */ if (!gst_vaapi_window_wayland_sync (window)) { wl_buffer_destroy (buffer); return !priv->sync_failed; } frame = frame_state_new (window); if (!frame) return FALSE; g_atomic_pointer_set (&priv->last_frame, frame); g_atomic_int_inc (&priv->num_frames_pending); if (need_vpp && priv->use_vpp) { frame->surface = surface; frame->surface_pool = gst_vaapi_video_pool_ref (priv->surface_pool); } /* XXX: attach to the specified target rectangle */ GST_VAAPI_OBJECT_LOCK_DISPLAY (window); wl_surface_attach (priv->surface, buffer, 0, 0); wl_surface_damage (priv->surface, 0, 0, width, height); if (priv->opaque_region) { wl_surface_set_opaque_region (priv->surface, priv->opaque_region); wl_region_destroy (priv->opaque_region); priv->opaque_region = NULL; } wl_proxy_set_queue ((struct wl_proxy *) buffer, priv->event_queue); wl_buffer_add_listener (buffer, &frame_buffer_listener, frame); frame->callback = wl_surface_frame (priv->surface); wl_callback_add_listener (frame->callback, &frame_callback_listener, frame); wl_surface_commit (priv->surface); wl_display_flush (wl_display); GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window); return TRUE; }
static GstFlowReturn gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) { GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); gboolean mem_cpy = TRUE; GstVideoRectangle src, dst, res; GST_LOG_OBJECT (sink, "render buffer %p, data = %p, timestamp = %" GST_TIME_FORMAT, buffer, GST_BUFFER_DATA (buffer), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer))); if (!sink->window) create_window (sink, sink->display, sink->video_width, sink->video_height); if (sink->render_finish) { if (GST_IS_WLBUFFER (buffer)) { GstWlBuffer *tmp_buffer = (GstWlBuffer *) buffer; /* Does it have a waylandbuffer ? */ if (tmp_buffer->wbuffer) { mem_cpy = FALSE; GST_DEBUG_OBJECT (sink, "we have a buffer (%p) we allocated " "ourselves and it has a wayland buffer, no memcpy then", buffer); sink->window->buffer = tmp_buffer->wbuffer; } else { /* No wayland buffer, that's a malloc */ GST_DEBUG_OBJECT (sink, "we have a buffer (%p) we allocated " "ourselves but it does not hold a wayland buffer", buffer); } } else { /* Not our baby! */ GST_DEBUG_OBJECT (sink, "we have a buffer (%p) we did not allocate", buffer); } if (mem_cpy) { GstWlBuffer *wlbuf = wayland_buffer_create (sink); memcpy (GST_BUFFER_DATA (wlbuf), GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer)); sink->window->buffer = wlbuf->wbuffer; } src.w = sink->video_width; src.h = sink->video_height; dst.w = sink->window->width; dst.h = sink->window->height; gst_video_sink_center_rect (src, dst, &res, FALSE); sink->render_finish = FALSE; wl_surface_attach (sink->window->surface, sink->window->buffer, 0, 0); wl_surface_damage (sink->window->surface, 0, 0, res.w, res.h); if (sink->callback) wl_callback_destroy (sink->callback); sink->callback = wl_surface_frame (sink->window->surface); wl_callback_add_listener (sink->callback, &frame_listener, sink); wl_surface_commit (sink->window->surface); } else GST_LOG_OBJECT (sink, "Waiting to get the signal from compositor to render the next frame.."); wl_display_dispatch (sink->display->display); return GST_FLOW_OK; }
static GstStateChangeReturn gst_wayland_sink_change_state (GstElement * element, GstStateChange transition) { GstWaylandSink *sink = GST_WAYLAND_SINK (element); GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: if (!gst_wayland_sink_find_display (sink)) return GST_STATE_CHANGE_FAILURE; break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: gst_buffer_replace (&sink->last_buffer, NULL); if (sink->window) { if (gst_wl_window_is_toplevel (sink->window)) { g_clear_object (&sink->window); } else { /* remove buffer from surface, show nothing */ wl_surface_attach (sink->window->surface, NULL, 0, 0); wl_surface_damage (sink->window->surface, 0, 0, sink->window->surface_width, sink->window->surface_height); wl_surface_commit (sink->window->surface); wl_display_flush (sink->display->display); } } break; case GST_STATE_CHANGE_READY_TO_NULL: g_mutex_lock (&sink->display_lock); /* If we had a toplevel window, we most likely have our own connection * to the display too, and it is a good idea to disconnect and allow * potentially the application to embed us with GstVideoOverlay * (which requires to re-use the same display connection as the parent * surface). If we didn't have a toplevel window, then the display * connection that we have is definitely shared with the application * and it's better to keep it around (together with the window handle) * to avoid requesting them again from the application if/when we are * restarted (GstVideoOverlay behaves like that in other sinks) */ if (sink->display && !sink->window) { /* -> the window was toplevel */ /* Force all buffers to return to the pool, regardless of * whether the compositor has released them or not. We are * going to kill the display, so we need to return all buffers * to be destroyed before this happens. * Note that this is done here instead of the pool destructor * because the buffers hold a reference to the pool. Also, * the buffers can only be unref'ed from the display's event loop * and the pool holds a reference to the display. If we drop * our references here, when the compositor releases the buffers, * they will be unref'ed from the event loop thread, which will * unref the pool and therefore the display, which will try to * stop the thread from within itself and cause a deadlock. */ if (sink->pool) { gst_wayland_compositor_release_all_buffers (GST_WAYLAND_BUFFER_POOL (sink->pool)); } g_clear_object (&sink->display); g_clear_object (&sink->pool); } g_mutex_unlock (&sink->display_lock); break; default: break; } return ret; }
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; }
static GstFlowReturn gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) { GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); GstVideoRectangle src, dst, res; GstBuffer *to_render; GstWlMeta *meta; GstFlowReturn ret; struct window *window; struct display *display; GST_LOG_OBJECT (sink, "render buffer %p", buffer); if (!sink->window) create_window (sink, sink->display, sink->video_width, sink->video_height); window = sink->window; display = sink->display; meta = gst_buffer_get_wl_meta (buffer); if (window->redraw_pending) { wl_display_dispatch (display->display); } if (meta && meta->sink == sink) { GST_LOG_OBJECT (sink, "buffer %p from our pool, writing directly", buffer); to_render = buffer; } else { GstMapInfo src; GST_LOG_OBJECT (sink, "buffer %p not from our pool, copying", buffer); if (!sink->pool) goto no_pool; if (!gst_buffer_pool_set_active (sink->pool, TRUE)) goto activate_failed; ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL); if (ret != GST_FLOW_OK) goto no_buffer; gst_buffer_map (buffer, &src, GST_MAP_READ); gst_buffer_fill (to_render, 0, src.data, src.size); gst_buffer_unmap (buffer, &src); meta = gst_buffer_get_wl_meta (to_render); } src.w = sink->video_width; src.h = sink->video_height; dst.w = sink->window->width; dst.h = sink->window->height; gst_video_sink_center_rect (src, dst, &res, FALSE); wl_surface_attach (sink->window->surface, meta->wbuffer, 0, 0); wl_surface_damage (sink->window->surface, 0, 0, res.w, res.h); window->redraw_pending = TRUE; window->callback = wl_surface_frame (window->surface); wl_callback_add_listener (window->callback, &frame_callback_listener, window); wl_surface_commit (window->surface); wl_display_dispatch (display->display); if (buffer != to_render) gst_buffer_unref (to_render); return GST_FLOW_OK; no_buffer: { GST_WARNING_OBJECT (sink, "could not create image"); return ret; } no_pool: { GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, ("Internal error: can't allocate images"), ("We don't have a bufferpool negotiated")); return GST_FLOW_ERROR; } activate_failed: { GST_ERROR_OBJECT (sink, "failed to activate bufferpool."); ret = GST_FLOW_ERROR; return ret; } }
int WaylandNativeWindow::queueBuffer(BaseNativeWindowBuffer* buffer, int fenceFd) { WaylandNativeWindowBuffer *wnb = (WaylandNativeWindowBuffer*) buffer; int ret = 0; HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer", "-%p", wnb); lock(); wnb->busy = 1; unlock(); /* XXX locking/something is a bit fishy here */ HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_wait_for_frame_callback", "-%p", wnb); while (this->frame_callback && ret != -1) { ret = wl_display_dispatch_queue(m_display, this->wl_queue); } if (ret < 0) { TRACE("wl_display_dispatch_queue returned an error"); HYBRIS_TRACE_END("wayland-platform", "queueBuffer_wait_for_frame_callback", "-%p", wnb); check_fatal_error(m_display); return ret; } HYBRIS_TRACE_END("wayland-platform", "queueBuffer_wait_for_frame_callback", "-%p", wnb); lock(); if (debugenvchecked == 0) { if (getenv("HYBRIS_WAYLAND_DUMP_BUFFERS") != NULL) debugenvchecked = 2; else debugenvchecked = 1; } if (debugenvchecked == 2) { HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_dumping_buffer", "-%p", wnb); hybris_dump_buffer_to_file(wnb->getNativeBuffer()); HYBRIS_TRACE_END("wayland-platform", "queueBuffer_dumping_buffer", "-%p", wnb); } #if ANDROID_VERSION_MAJOR>=4 && ANDROID_VERSION_MINOR>=2 HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_waiting_for_fence", "-%p", wnb); sync_wait(fenceFd, -1); close(fenceFd); HYBRIS_TRACE_END("wayland-platform", "queueBuffer_waiting_for_fence", "-%p", wnb); #endif this->frame_callback = wl_surface_frame(m_window->surface); wl_callback_add_listener(this->frame_callback, &frame_listener, this); wl_proxy_set_queue((struct wl_proxy *) this->frame_callback, this->wl_queue); if (wnb->wlbuffer == NULL) { wnb->wlbuffer_from_native_handle(m_android_wlegl); TRACE("%p add listener with %p inside", wnb, wnb->wlbuffer); wl_buffer_add_listener(wnb->wlbuffer, &wl_buffer_listener, this); wl_proxy_set_queue((struct wl_proxy *) wnb->wlbuffer, this->wl_queue); } TRACE("%p DAMAGE AREA: %dx%d", wnb, wnb->width, wnb->height); HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_attachdamagecommit", "-resource@%i", wl_proxy_get_id((struct wl_proxy *) wnb->wlbuffer)); wl_surface_attach(m_window->surface, wnb->wlbuffer, 0, 0); wl_surface_damage(m_window->surface, 0, 0, wnb->width, wnb->height); wl_surface_commit(m_window->surface); wl_display_flush(m_display); HYBRIS_TRACE_END("wayland-platform", "queueBuffer_attachdamagecommit", "-resource@%i", wl_proxy_get_id((struct wl_proxy *) wnb->wlbuffer)); //--m_freeBufs; //pthread_cond_signal(&cond); fronted.push_back(wnb); HYBRIS_TRACE_COUNTER("wayland-platform", "fronted.size", "%i", fronted.size()); if (fronted.size() == m_bufList.size()) { HYBRIS_TRACE_BEGIN("wayland-platform", "queueBuffer_wait_for_nonfronted_buffer", "-%p", wnb); /* We have fronted all our buffers, let's wait for one of them to be free */ do { unlock(); ret = wl_display_dispatch_queue(m_display, this->wl_queue); lock(); if (ret == -1) { check_fatal_error(m_display); break; } HYBRIS_TRACE_COUNTER("wayland-platform", "fronted.size", "%i", fronted.size()); if (fronted.size() != m_bufList.size()) break; } while (1); HYBRIS_TRACE_END("wayland-platform", "queueBuffer_wait_for_nonfronted_buffer", "-%p", wnb); } HYBRIS_TRACE_END("wayland-platform", "queueBuffer", "-%p", wnb); unlock(); return NO_ERROR; }
int WaylandNativeWindow::postBuffer(ANativeWindowBuffer* buffer) { TRACE(""); WaylandNativeWindowBuffer *wnb = NULL; lock(); std::list<WaylandNativeWindowBuffer *>::iterator it = post_registered.begin(); for (; it != post_registered.end(); it++) { if ((*it)->other == buffer) { wnb = (*it); break; } } unlock(); if (!wnb) { wnb = new WaylandNativeWindowBuffer(buffer); wnb->common.incRef(&wnb->common); buffer->common.incRef(&buffer->common); } int ret = 0; lock(); wnb->busy = 1; unlock(); /* XXX locking/something is a bit fishy here */ while (this->frame_callback && ret != -1) { ret = wl_display_dispatch_queue(m_display, this->wl_queue); } if (ret < 0) { TRACE("wl_display_dispatch_queue returned an error:%i", ret); check_fatal_error(m_display); return ret; } lock(); this->frame_callback = wl_surface_frame(m_window->surface); wl_callback_add_listener(this->frame_callback, &frame_listener, this); wl_proxy_set_queue((struct wl_proxy *) this->frame_callback, this->wl_queue); if (wnb->wlbuffer == NULL) { wnb->wlbuffer_from_native_handle(m_android_wlegl); TRACE("%p add listener with %p inside", wnb, wnb->wlbuffer); wl_buffer_add_listener(wnb->wlbuffer, &wl_buffer_listener, this); wl_proxy_set_queue((struct wl_proxy *) wnb->wlbuffer, this->wl_queue); post_registered.push_back(wnb); } TRACE("%p DAMAGE AREA: %dx%d", wnb, wnb->width, wnb->height); wl_surface_attach(m_window->surface, wnb->wlbuffer, 0, 0); wl_surface_damage(m_window->surface, 0, 0, wnb->width, wnb->height); wl_surface_commit(m_window->surface); //--m_freeBufs; //pthread_cond_signal(&cond); posted.push_back(wnb); unlock(); return NO_ERROR; }
/** * Called via eglSwapBuffers(), drv->API.SwapBuffers(). */ static EGLBoolean dri2_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv); struct wl_callback *callback; if (dri2_surf->block_swap_buffers) { wl_display_flush(dri2_dpy->wl_dpy); while (dri2_surf->block_swap_buffers) wl_display_iterate(dri2_dpy->wl_dpy, WL_DISPLAY_READABLE); } dri2_surf->block_swap_buffers = EGL_TRUE; callback = wl_surface_frame(dri2_surf->wl_win->surface); wl_callback_add_listener(callback, &frame_listener, dri2_surf); if (dri2_surf->base.Type == EGL_WINDOW_BIT) { pointer_swap( (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT], (const void **) &dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]); dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]->attachment = __DRI_BUFFER_FRONT_LEFT; dri2_surf->dri_buffers[__DRI_BUFFER_BACK_LEFT]->attachment = __DRI_BUFFER_BACK_LEFT; swap_wl_buffers(dri2_surf, WL_BUFFER_FRONT, WL_BUFFER_BACK); if (!dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT]) dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT] = wayland_create_buffer(dri2_surf, dri2_surf->dri_buffers[__DRI_BUFFER_FRONT_LEFT]); wl_buffer_damage(dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], 0, 0, dri2_surf->base.Width, dri2_surf->base.Height); wl_surface_attach(dri2_surf->wl_win->surface, dri2_surf->wl_drm_buffer[WL_BUFFER_FRONT], dri2_surf->dx, dri2_surf->dy); dri2_surf->wl_buffer_lock[WL_BUFFER_FRONT] = 1; dri2_surf->wl_win->attached_width = dri2_surf->base.Width; dri2_surf->wl_win->attached_height = dri2_surf->base.Height; /* reset resize growing parameters */ dri2_surf->dx = 0; dri2_surf->dy = 0; wl_surface_damage(dri2_surf->wl_win->surface, 0, 0, dri2_surf->base.Width, dri2_surf->base.Height); } _EGLContext *ctx; if (dri2_drv->glFlush) { ctx = _eglGetCurrentContext(); if (ctx && ctx->DrawSurface == &dri2_surf->base) dri2_drv->glFlush(); } (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable); (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable); return EGL_TRUE; }
static gboolean gst_vaapi_window_wayland_render( GstVaapiWindow *window, GstVaapiSurface *surface, const GstVaapiRectangle *src_rect, const GstVaapiRectangle *dst_rect, guint flags ) { GstVaapiWindowWaylandPrivate * const priv = GST_VAAPI_WINDOW_WAYLAND(window)->priv; GstVaapiDisplay * const display = GST_VAAPI_OBJECT_DISPLAY(window); struct wl_display * const wl_display = GST_VAAPI_OBJECT_WL_DISPLAY(window); struct wl_buffer *buffer; struct wl_callback *callback; guint width, height, va_flags; VASurfaceID surface_id; VAStatus status; /* XXX: use VPP to support unusual source and destination rectangles */ gst_vaapi_surface_get_size(surface, &width, &height); if (src_rect->x != 0 || src_rect->y != 0 || src_rect->width != width || src_rect->height != height) { GST_ERROR("unsupported source rectangle for rendering"); return FALSE; } if (0 && (dst_rect->width != width || dst_rect->height != height)) { GST_ERROR("unsupported target rectangle for rendering"); return FALSE; } surface_id = GST_VAAPI_OBJECT_ID(surface); if (surface_id == VA_INVALID_ID) return FALSE; GST_VAAPI_OBJECT_LOCK_DISPLAY(window); /* Wait for the previous frame to complete redraw */ if (priv->redraw_pending) wl_display_iterate(wl_display, WL_DISPLAY_READABLE); /* XXX: use VA/VPP for other filters */ va_flags = from_GstVaapiSurfaceRenderFlags(flags); status = vaGetSurfaceBufferWl( GST_VAAPI_DISPLAY_VADISPLAY(display), surface_id, va_flags & (VA_TOP_FIELD|VA_BOTTOM_FIELD), &buffer ); if (status == VA_STATUS_ERROR_FLAG_NOT_SUPPORTED) { /* XXX: de-interlacing flags not supported, try with VPP? */ status = vaGetSurfaceBufferWl( GST_VAAPI_DISPLAY_VADISPLAY(display), surface_id, VA_FRAME_PICTURE, &buffer ); } if (!vaapi_check_status(status, "vaGetSurfaceBufferWl()")) return FALSE; /* XXX: attach to the specified target rectangle */ wl_surface_attach(priv->surface, buffer, 0, 0); wl_surface_damage(priv->surface, 0, 0, width, height); wl_display_iterate(wl_display, WL_DISPLAY_WRITABLE); priv->redraw_pending = TRUE; priv->buffer = buffer; callback = wl_surface_frame(priv->surface); wl_callback_add_listener(callback, &frame_callback_listener, priv); GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window); return TRUE; }
static struct window * create_window(struct display *display, int width, int height, enum wl_output_transform transform, int scale, enum window_flags flags) { struct window *window; if (display->compositor_version < 2 && (transform != WL_OUTPUT_TRANSFORM_NORMAL || flags & WINDOW_FLAG_ROTATING_TRANSFORM)) { fprintf(stderr, "wl_surface.buffer_transform unsupported in " "wl_surface version %d\n", display->compositor_version); exit(1); } if (display->compositor_version < 3 && (! (flags & WINDOW_FLAG_USE_VIEWPORT)) && scale != 1) { fprintf(stderr, "wl_surface.buffer_scale unsupported in " "wl_surface version %d\n", display->compositor_version); exit(1); } if (display->scaler == NULL && (flags & WINDOW_FLAG_USE_VIEWPORT)) { fprintf(stderr, "Compositor does not support wl_viewport"); exit(1); } window = calloc(1, sizeof *window); if (!window) return NULL; window->callback = NULL; window->display = display; window->width = width; window->height = height; window->border = 10; window->flags = flags; window->transform = transform; window->scale = scale; window_init_game(window); window->surface = wl_compositor_create_surface(display->compositor); if (window->flags & WINDOW_FLAG_USE_VIEWPORT) window->viewport = wl_scaler_get_viewport(display->scaler, window->surface); if (display->shell) { window->xdg_surface = xdg_shell_get_xdg_surface(display->shell, window->surface); assert(window->xdg_surface); xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window); xdg_surface_set_title(window->xdg_surface, "simple-damage"); } else if (display->fshell) { _wl_fullscreen_shell_present_surface(display->fshell, window->surface, _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT, NULL); } else { assert(0); } /* Initialise damage to full surface, so the padding gets painted */ wl_surface_damage(window->surface, 0, 0, INT32_MAX, INT32_MAX); return window; }
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; }
void window_damage(struct window *window, int32_t x, int32_t y, int32_t width, int32_t height) { wl_surface_damage(window->surface, x, y, width, height); }
/* Swap the contents of a drawable to the screen */ static WSEGLError wseglSwapDrawable (WSEGLDrawableHandle _drawable, unsigned long data) { struct wl_egl_window *drawable = (struct wl_egl_window *) _drawable; struct wl_callback *callback; if (drawable->numFlipBuffers) { // wsegl_info("PRESENT FLIP"); PVR2DPresentFlip(drawable->display->context, drawable->flipChain, drawable->backBuffers[drawable->currentBackBuffer], 0); } else if (drawable->display->display) { //wsegl_info("wseglSwapDrawable for wayland, %d %p", drawable->currentBackBuffer, drawable->drmbuffers[drawable->currentBackBuffer]); int ret = 0; while (drawable->display->frame_callback && ret != -1) ret = wl_display_dispatch_queue(drawable->display->display, drawable->display->queue); drawable->display->frame_callback = wl_surface_frame(drawable->surface); wl_callback_add_listener(drawable->display->frame_callback, &frame_listener, drawable); wl_proxy_set_queue((struct wl_proxy *)drawable->display->frame_callback, drawable->display->queue); if (!drawable->drmbuffers[drawable->currentBackBuffer]) { int32_t handle; struct wl_resource *wlbuf; handle = drawable->exporthandles[drawable->currentBackBuffer]; wlbuf = sgx_wlegl_create_buffer(drawable->display->sgx_wlegl, drawable->width, drawable->height, drawable->strideBytes, drawable->format, handle); drawable->drmbuffers[drawable->currentBackBuffer] = wlbuf; wsegl_info("sgx_wlegl_create_buffer for %d", drawable->currentBackBuffer); wsegl_info("Add listener for %p with %p (buf %d) inside", drawable, wlbuf, drawable->currentBackBuffer); // TODO: listen for release wl_proxy_set_queue((struct wl_proxy *)wlbuf, drawable->display->queue); } struct wl_resource *wlbuf = drawable->drmbuffers[drawable->currentBackBuffer]; wl_surface_attach(drawable->surface, wlbuf, 0, 0); wl_surface_damage(drawable->surface, 0, 0, drawable->width, drawable->height); wl_surface_commit(drawable->surface); } else { PVR2DBLTINFO blit; memset(&blit, 0, sizeof(blit)); blit.CopyCode = PVR2DROPcopy; blit.BlitFlags = PVR2D_BLIT_DISABLE_ALL; blit.pSrcMemInfo = drawable->backBuffers[drawable->currentBackBuffer]; blit.SrcStride = drawable->strideBytes; blit.SrcX = 0; blit.SrcY = 0; blit.SizeX = drawable->width; blit.SizeY = drawable->height; blit.SrcFormat = wsegl2pvr2dformat(drawable->format); blit.pDstMemInfo = drawable->frontBufferPVRMEM; blit.DstStride = drawable->strideBytes; blit.DstX = 0; blit.DstY = 0; blit.DSizeX = drawable->width; blit.DSizeY = drawable->height; blit.DstFormat = wsegl2pvr2dformat(drawable->format); PVR2DBlt(drawable->display->context, &blit); PVR2DQueryBlitsComplete (drawable->display->context, drawable->frontBufferPVRMEM, 1); assert (drawable->display->fd >= 0); struct omapfb_update_window update_window; update_window.x = update_window.out_x = 0; update_window.y = update_window.out_y = 0; update_window.width = update_window.out_width = drawable->width; update_window.height = update_window.out_height = drawable->height; update_window.format = 0; assert(ioctl(drawable->display->fd, OMAPFB_UPDATE_WINDOW, &update_window) == 0); } drawable->currentBackBuffer = (drawable->currentBackBuffer + 1) % WAYLANDWSEGL_MAX_BACK_BUFFERS; return WSEGL_SUCCESS; }
static gboolean gst_mfx_window_wayland_render (GstMfxWindow * window, GstMfxSurface * surface, const GstMfxRectangle * src_rect, const GstMfxRectangle * dst_rect) { GstMfxWindowWaylandPrivate *const priv = GST_MFX_WINDOW_WAYLAND_GET_PRIVATE (window); GstMfxDisplayWaylandPrivate *const display_priv = GST_MFX_DISPLAY_WAYLAND_GET_PRIVATE (GST_MFX_WINDOW_DISPLAY (window)); struct wl_display *const display = GST_MFX_DISPLAY_HANDLE (GST_MFX_WINDOW_DISPLAY (window)); GstMfxPrimeBufferProxy *buffer_proxy; struct wl_buffer *buffer; FrameState *frame; guintptr fd = 0; guint32 drm_format = 0; gint offsets[3] = { 0 }, pitches[3] = { 0 }, num_planes = 0, i = 0; VaapiImage *vaapi_image; buffer_proxy = gst_mfx_prime_buffer_proxy_new_from_surface (surface); if (!buffer_proxy) return FALSE; fd = GST_MFX_PRIME_BUFFER_PROXY_HANDLE (buffer_proxy); vaapi_image = gst_mfx_prime_buffer_proxy_get_vaapi_image (buffer_proxy); num_planes = vaapi_image_get_plane_count (vaapi_image); if ((dst_rect->height != src_rect->height) || (dst_rect->width != src_rect->width)) { #ifdef USE_WESTON_4_0 if (priv->wp_viewport) { wp_viewport_set_destination (priv->wp_viewport, dst_rect->width, dst_rect->height); } #else if (priv->viewport) { wl_viewport_set_destination (priv->viewport, dst_rect->width, dst_rect->height); } #endif } for (i = 0; i < num_planes; i++) { offsets[i] = vaapi_image_get_offset (vaapi_image, i); pitches[i] = vaapi_image_get_pitch (vaapi_image, i); } if (GST_VIDEO_FORMAT_NV12 == vaapi_image_get_format (vaapi_image)) { drm_format = WL_DRM_FORMAT_NV12; } else if (GST_VIDEO_FORMAT_BGRA == vaapi_image_get_format (vaapi_image)) { drm_format = WL_DRM_FORMAT_ARGB8888; } if (!drm_format) goto error; if (!display_priv->drm) goto error; GST_MFX_DISPLAY_LOCK (GST_MFX_WINDOW_DISPLAY (window)); buffer = wl_drm_create_prime_buffer (display_priv->drm, fd, src_rect->width, src_rect->height, drm_format, offsets[0], pitches[0], offsets[1], pitches[1], offsets[2], pitches[2]); GST_MFX_DISPLAY_UNLOCK (GST_MFX_WINDOW_DISPLAY (window)); if (!buffer) { GST_ERROR ("No wl_buffer created\n"); goto error; } frame = frame_state_new (window); if (!frame) goto error; g_atomic_pointer_set (&priv->last_frame, frame); g_atomic_int_inc (&priv->num_frames_pending); GST_MFX_DISPLAY_LOCK (GST_MFX_WINDOW_DISPLAY (window)); wl_surface_attach (priv->surface, buffer, 0, 0); wl_surface_damage (priv->surface, 0, 0, dst_rect->width, dst_rect->height); if (priv->opaque_region) { wl_surface_set_opaque_region (priv->surface, priv->opaque_region); wl_region_destroy (priv->opaque_region); priv->opaque_region = NULL; } wl_proxy_set_queue ((struct wl_proxy *) buffer, priv->event_queue); wl_buffer_add_listener (buffer, &frame_buffer_listener, frame); frame->callback = wl_surface_frame (priv->surface); wl_callback_add_listener (frame->callback, &frame_callback_listener, frame); wl_surface_commit (priv->surface); wl_display_flush (display); GST_MFX_DISPLAY_UNLOCK (GST_MFX_WINDOW_DISPLAY (window)); vaapi_image_unref (vaapi_image); gst_mfx_prime_buffer_proxy_unref (buffer_proxy); return TRUE; error: { vaapi_image_unref (vaapi_image); gst_mfx_prime_buffer_proxy_unref (buffer_proxy); return FALSE; } }
static void vertical_blank(void *pointer) { struct wayland *wayland = pointer; wl_display_roundtrip(wayland->display); struct timespec tv; int32_t nsec_diff; clock_gettime(CLOCK_MONOTONIC, &tv); if (tv_prev.tv_sec == 0 && tv_prev.tv_nsec == 0) { nsec_diff = 0; tv_prev = tv; } else { nsec_diff = nano_elapsed(&tv_prev, &tv); tv_prev = tv; // assert(sec_diff == 0); cairo_surface_t *cairo_surface = cairo_image_surface_create_for_data( (unsigned char *)wayland->back_data, CAIRO_FORMAT_ARGB32, 256 * SCALE, 240 * SCALE, 256 * SCALE * 4); cairo_t *cairo = cairo_create(cairo_surface); char buffer[200]; double fps = 1000000000.0 / ((double) nsec_diff); sprintf(buffer, "FPS %.1f", fps); cairo_set_source_rgba(cairo, 255, 255, 255, 0.8); cairo_select_font_face(cairo, "Cousine", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size(cairo, 12 * SCALE); cairo_move_to(cairo, 2 * SCALE, 236 * SCALE); cairo_show_text(cairo, buffer); cairo_destroy(cairo); cairo_surface_destroy(cairo_surface); // ++frame_count; } swap_buffers(wayland); wayland->frame_callback = wl_surface_frame(wayland->surface); wl_callback_add_listener(wayland->frame_callback, &frame_callback_listener, wayland); wl_surface_damage(wayland->surface, 0, 0, wayland->width, wayland->height); wl_surface_attach(wayland->surface, wayland->front_buffer, 0, 0); wl_surface_commit(wayland->surface); wl_display_flush(wayland->display); const int32_t NSEC_PER_60FPS_TICK = 16666666; if (nsec_diff != 0) { struct timespec req = { .tv_sec = 0, .tv_nsec = NSEC_PER_60FPS_TICK - nsec_diff, }; struct timespec rem; nanosleep(&req, &rem); } } static uint8_t joypad1_read(void *pointer) { struct wayland *wayland = pointer; wl_display_roundtrip(wayland->display); uint8_t state = wayland->joypad1_state; wayland->joypad1_state = wayland->joypad1_press; return state; } uint8_t nes_emulator_ppu_backend_wayland_init( struct nes_emulator_ppu_backend **ppu_backend) { if (ppu_backend == NULL) { return EXIT_CODE_ARG_ERROR_BIT; } *ppu_backend = NULL; struct nes_emulator_ppu_backend *b = malloc(sizeof(struct nes_emulator_ppu_backend)); if (b == NULL) { return EXIT_CODE_OS_ERROR_BIT; } struct wayland *w = malloc(sizeof(struct wayland)); if (w == NULL) { free(b); return EXIT_CODE_OS_ERROR_BIT; } w->joypad1_state = 0; w->joypad1_press = 0; uint8_t exit_code = init_wayland(w); if (exit_code != 0) { free(w); free(b); return exit_code; } b->pointer = w; b->render_pixel = render_pixel; b->vertical_blank = vertical_blank; b->joypad1_read = joypad1_read; *ppu_backend = b; return 0; } uint8_t nes_emulator_ppu_backend_wayland_fini( struct nes_emulator_ppu_backend **ppu_backend) { uint8_t exit_code = 0; struct wayland *wayland = (struct wayland *) (*ppu_backend)->pointer; exit_code |= fini_wayland(wayland); free(wayland); free(*ppu_backend); *ppu_backend = NULL; return exit_code; }