You've already forked android_translation_layer
mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-10-27 11:48:10 -07:00
refactor SurfaceViewWidget for frame_callback in the Wayland server
SurfaceViewWidget is now always a child of a GtkGraphicsOffload and handles the GdkTexture on its own. This way the extra GtkPicture is no longer needed and also the frame_callback of the Wayland server can be implemented.
This commit is contained in:
@@ -33,6 +33,7 @@
|
|||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
#include "../defines.h"
|
#include "../defines.h"
|
||||||
#include "../../libandroid/native_window.h"
|
#include "../../libandroid/native_window.h"
|
||||||
|
#include "../widgets/android_view_SurfaceView.h"
|
||||||
|
|
||||||
struct ATL_codec_context {
|
struct ATL_codec_context {
|
||||||
AVCodecContext *codec;
|
AVCodecContext *codec;
|
||||||
@@ -42,7 +43,7 @@ struct ATL_codec_context {
|
|||||||
} audio;
|
} audio;
|
||||||
struct {
|
struct {
|
||||||
struct SwsContext *sws; // for software decoding
|
struct SwsContext *sws; // for software decoding
|
||||||
GtkPicture *gtk_picture;
|
SurfaceViewWidget *surface_view_widget;
|
||||||
#if !GTK_CHECK_VERSION(4, 14, 0)
|
#if !GTK_CHECK_VERSION(4, 14, 0)
|
||||||
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
|
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
|
||||||
struct wp_viewporter *wp_viewporter;
|
struct wp_viewporter *wp_viewporter;
|
||||||
@@ -147,7 +148,7 @@ static enum AVPixelFormat get_hw_format(AVCodecContext *ctx,
|
|||||||
struct render_frame_data {
|
struct render_frame_data {
|
||||||
AVFrame *frame;
|
AVFrame *frame;
|
||||||
GdkTexture *texture; // for software decoding
|
GdkTexture *texture; // for software decoding
|
||||||
GtkPicture *gtk_picture;
|
SurfaceViewWidget *surface_view_widget;
|
||||||
#if !GTK_CHECK_VERSION(4, 14, 0)
|
#if !GTK_CHECK_VERSION(4, 14, 0)
|
||||||
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
|
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
|
||||||
struct ANativeWindow *native_window;
|
struct ANativeWindow *native_window;
|
||||||
@@ -351,21 +352,9 @@ JNIEXPORT void JNICALL Java_android_media_MediaCodec_native_1configure_1video(JN
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
GtkWidget *surface_view_widget = _PTR(_GET_LONG_FIELD(surface_obj, "widget"));
|
SurfaceViewWidget *surface_view_widget = SURFACE_VIEW_WIDGET(gtk_widget_get_first_child(_PTR(_GET_LONG_FIELD(surface_obj, "widget"))));
|
||||||
#if GTK_CHECK_VERSION(4, 14, 0)
|
ctx->video.surface_view_widget = surface_view_widget;
|
||||||
GtkWidget *graphics_offload = gtk_widget_get_first_child(surface_view_widget);
|
#if !GTK_CHECK_VERSION(4, 14, 0)
|
||||||
if (!GTK_IS_GRAPHICS_OFFLOAD(graphics_offload)) {
|
|
||||||
graphics_offload = gtk_graphics_offload_new(gtk_picture_new());
|
|
||||||
gtk_widget_insert_after(graphics_offload, surface_view_widget, NULL);
|
|
||||||
}
|
|
||||||
ctx->video.gtk_picture = GTK_PICTURE(gtk_graphics_offload_get_child(GTK_GRAPHICS_OFFLOAD(graphics_offload)));
|
|
||||||
#else
|
|
||||||
GtkWidget *gtk_picture = gtk_widget_get_first_child(surface_view_widget);
|
|
||||||
if (!GTK_IS_PICTURE(gtk_picture)) {
|
|
||||||
gtk_picture = gtk_picture_new();
|
|
||||||
gtk_widget_insert_after(gtk_picture, surface_view_widget, NULL);
|
|
||||||
}
|
|
||||||
ctx->video.gtk_picture = GTK_PICTURE(gtk_picture);
|
|
||||||
struct ANativeWindow *native_window = ANativeWindow_fromSurface(env, surface_obj);
|
struct ANativeWindow *native_window = ANativeWindow_fromSurface(env, surface_obj);
|
||||||
ctx->video.native_window = native_window;
|
ctx->video.native_window = native_window;
|
||||||
ctx->video.surface_width = gtk_widget_get_width(native_window->surface_view_widget);
|
ctx->video.surface_width = gtk_widget_get_width(native_window->surface_view_widget);
|
||||||
@@ -528,8 +517,7 @@ static gboolean render_frame(void *data)
|
|||||||
|
|
||||||
#if GTK_CHECK_VERSION(4, 14, 0)
|
#if GTK_CHECK_VERSION(4, 14, 0)
|
||||||
GdkTexture *texture = import_drm_frame_desc_as_texture(drm_frame_desc, drm_frame->width, drm_frame->height, drm_frame);
|
GdkTexture *texture = import_drm_frame_desc_as_texture(drm_frame_desc, drm_frame->width, drm_frame->height, drm_frame);
|
||||||
gtk_picture_set_paintable(d->gtk_picture, GDK_PAINTABLE(texture));
|
surface_view_widget_set_texture(d->surface_view_widget, texture);
|
||||||
g_object_unref(texture);
|
|
||||||
#else
|
#else
|
||||||
struct wl_buffer *wl_buffer = import_drm_frame_desc(d->zwp_linux_dmabuf_v1,
|
struct wl_buffer *wl_buffer = import_drm_frame_desc(d->zwp_linux_dmabuf_v1,
|
||||||
drm_frame_desc, drm_frame->width, drm_frame->height);
|
drm_frame_desc, drm_frame->width, drm_frame->height);
|
||||||
@@ -553,8 +541,7 @@ static gboolean render_frame(void *data)
|
|||||||
static gboolean render_texture(void *data) {
|
static gboolean render_texture(void *data) {
|
||||||
struct render_frame_data *d = (struct render_frame_data *)data;
|
struct render_frame_data *d = (struct render_frame_data *)data;
|
||||||
|
|
||||||
gtk_picture_set_paintable(d->gtk_picture, GDK_PAINTABLE(d->texture));
|
surface_view_widget_set_texture(d->surface_view_widget, d->texture);
|
||||||
g_object_unref(d->texture);
|
|
||||||
|
|
||||||
free(d);
|
free(d);
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
@@ -608,7 +595,7 @@ JNIEXPORT void JNICALL Java_android_media_MediaCodec_native_1releaseOutputBuffer
|
|||||||
GdkTexture *texture = gdk_memory_texture_new(frame->width, frame->height, gdk_mem_fmt, bytes, stride);
|
GdkTexture *texture = gdk_memory_texture_new(frame->width, frame->height, gdk_mem_fmt, bytes, stride);
|
||||||
struct render_frame_data *data = malloc(sizeof(struct render_frame_data));
|
struct render_frame_data *data = malloc(sizeof(struct render_frame_data));
|
||||||
data->texture = texture;
|
data->texture = texture;
|
||||||
data->gtk_picture = ctx->video.gtk_picture;
|
data->surface_view_widget = ctx->video.surface_view_widget;
|
||||||
g_idle_add(render_texture, data);
|
g_idle_add(render_texture, data);
|
||||||
g_bytes_unref (bytes);
|
g_bytes_unref (bytes);
|
||||||
av_frame_free(&frame);
|
av_frame_free(&frame);
|
||||||
@@ -618,7 +605,7 @@ JNIEXPORT void JNICALL Java_android_media_MediaCodec_native_1releaseOutputBuffer
|
|||||||
struct render_frame_data *data = malloc(sizeof(struct render_frame_data));
|
struct render_frame_data *data = malloc(sizeof(struct render_frame_data));
|
||||||
data->frame = frame;
|
data->frame = frame;
|
||||||
#if GTK_CHECK_VERSION(4, 14, 0)
|
#if GTK_CHECK_VERSION(4, 14, 0)
|
||||||
data->gtk_picture = ctx->video.gtk_picture;
|
data->surface_view_widget = ctx->video.surface_view_widget;
|
||||||
#else
|
#else
|
||||||
data->native_window = ctx->video.native_window;
|
data->native_window = ctx->video.native_window;
|
||||||
data->zwp_linux_dmabuf_v1 = ctx->video.zwp_linux_dmabuf_v1;
|
data->zwp_linux_dmabuf_v1 = ctx->video.zwp_linux_dmabuf_v1;
|
||||||
|
|||||||
@@ -7,20 +7,7 @@
|
|||||||
#include "marshal.h"
|
#include "marshal.h"
|
||||||
|
|
||||||
#include "../generated_headers/android_view_SurfaceView.h"
|
#include "../generated_headers/android_view_SurfaceView.h"
|
||||||
|
#include "android_view_SurfaceView.h"
|
||||||
// TODO: currently this widget class doesn't do anything special, will we ever need it to?
|
|
||||||
G_DECLARE_FINAL_TYPE (SurfaceViewWidget, surface_view_widget, SURFACE_VIEW, WIDGET, GtkWidget)
|
|
||||||
|
|
||||||
struct _SurfaceViewWidget
|
|
||||||
{
|
|
||||||
GtkWidget parent_instance;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _SurfaceViewWidgetClass
|
|
||||||
{
|
|
||||||
GtkWidgetClass parent_class;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
G_DEFINE_TYPE(SurfaceViewWidget, surface_view_widget, GTK_TYPE_WIDGET)
|
G_DEFINE_TYPE(SurfaceViewWidget, surface_view_widget, GTK_TYPE_WIDGET)
|
||||||
|
|
||||||
@@ -45,12 +32,36 @@ static void surface_view_widget_size_allocate(GtkWidget *widget, int width, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void surface_view_widget_snapshot(GtkWidget *widget, GdkSnapshot *snapshot)
|
||||||
|
{
|
||||||
|
SurfaceViewWidget *surface_view_widget = SURFACE_VIEW_WIDGET(widget);
|
||||||
|
if (surface_view_widget->texture) {
|
||||||
|
graphene_rect_t bounds = GRAPHENE_RECT_INIT(0, 0, gtk_widget_get_width(widget), gtk_widget_get_height(widget));
|
||||||
|
gtk_snapshot_append_texture(snapshot, surface_view_widget->texture, &bounds);
|
||||||
|
}
|
||||||
|
if (surface_view_widget->frame_callback) {
|
||||||
|
surface_view_widget->frame_callback(surface_view_widget);
|
||||||
|
surface_view_widget->frame_callback = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void surface_view_widget_dispose(GObject *object) {
|
||||||
|
SurfaceViewWidget *surface_view_widget = SURFACE_VIEW_WIDGET(object);
|
||||||
|
if (surface_view_widget->texture) {
|
||||||
|
g_object_unref(surface_view_widget->texture);
|
||||||
|
surface_view_widget->texture = NULL;
|
||||||
|
}
|
||||||
|
G_OBJECT_CLASS(surface_view_widget_parent_class)->dispose(object);
|
||||||
|
}
|
||||||
|
|
||||||
static void surface_view_widget_class_init(SurfaceViewWidgetClass *class)
|
static void surface_view_widget_class_init(SurfaceViewWidgetClass *class)
|
||||||
{
|
{
|
||||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||||
|
|
||||||
// resize signal copied from GtkDrawingArea
|
// resize signal copied from GtkDrawingArea
|
||||||
widget_class->size_allocate = surface_view_widget_size_allocate;
|
widget_class->size_allocate = surface_view_widget_size_allocate;
|
||||||
|
widget_class->snapshot = surface_view_widget_snapshot;
|
||||||
|
G_OBJECT_CLASS(class)->dispose = surface_view_widget_dispose;
|
||||||
|
|
||||||
signals[RESIZE] =
|
signals[RESIZE] =
|
||||||
g_signal_new("resize",
|
g_signal_new("resize",
|
||||||
@@ -70,6 +81,14 @@ GtkWidget * surface_view_widget_new(void)
|
|||||||
return g_object_new (surface_view_widget_get_type(), NULL);
|
return g_object_new (surface_view_widget_get_type(), NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void surface_view_widget_set_texture(SurfaceViewWidget *surface_view_widget, GdkTexture *texture)
|
||||||
|
{
|
||||||
|
if (surface_view_widget->texture)
|
||||||
|
g_object_unref(surface_view_widget->texture);
|
||||||
|
surface_view_widget->texture = texture;
|
||||||
|
gtk_widget_queue_draw(GTK_WIDGET(surface_view_widget));
|
||||||
|
}
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
struct jni_callback_data { JavaVM *jvm; jobject this; jclass this_class;};
|
struct jni_callback_data { JavaVM *jvm; jobject this; jclass this_class;};
|
||||||
@@ -98,16 +117,20 @@ JNIEXPORT jlong JNICALL Java_android_view_SurfaceView_native_1constructor(JNIEnv
|
|||||||
GtkWidget *wrapper = g_object_ref(wrapper_widget_new());
|
GtkWidget *wrapper = g_object_ref(wrapper_widget_new());
|
||||||
GtkWidget *dummy = surface_view_widget_new();
|
GtkWidget *dummy = surface_view_widget_new();
|
||||||
gtk_widget_set_name(dummy, "dummy widget for SurfaceView");
|
gtk_widget_set_name(dummy, "dummy widget for SurfaceView");
|
||||||
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), dummy);
|
#if GTK_CHECK_VERSION(4, 14, 0)
|
||||||
|
GtkWidget *graphics_offload = gtk_graphics_offload_new(dummy);
|
||||||
|
#else
|
||||||
|
// use a dummy GtkBox, so that the SurfaceViewWidget also becomes a grand child of the WrapperWidget
|
||||||
|
GtkWidget *graphics_offload = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||||
|
gtk_widget_set_vexpand(dummy, TRUE);
|
||||||
|
gtk_widget_set_hexpand(dummy, TRUE);
|
||||||
|
gtk_widget_insert_before(dummy, graphics_offload, NULL);
|
||||||
|
#endif
|
||||||
|
wrapper_widget_set_child(WRAPPER_WIDGET(wrapper), graphics_offload);
|
||||||
wrapper_widget_set_jobject(WRAPPER_WIDGET(wrapper), env, this);
|
wrapper_widget_set_jobject(WRAPPER_WIDGET(wrapper), env, this);
|
||||||
// TODO: is this correct for all usecases? how do we know when it's not?
|
// TODO: is this correct for all usecases? how do we know when it's not?
|
||||||
gtk_widget_set_hexpand(wrapper, true);
|
gtk_widget_set_hexpand(wrapper, true);
|
||||||
gtk_widget_set_vexpand(wrapper, true);
|
gtk_widget_set_vexpand(wrapper, true);
|
||||||
#if GTK_CHECK_VERSION(4, 14, 0)
|
|
||||||
gtk_widget_insert_after(gtk_graphics_offload_new(gtk_picture_new()), dummy, NULL);
|
|
||||||
#else
|
|
||||||
gtk_widget_insert_after(gtk_picture_new(), dummy, NULL);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
JavaVM *jvm;
|
JavaVM *jvm;
|
||||||
(*env)->GetJavaVM(env, &jvm);
|
(*env)->GetJavaVM(env, &jvm);
|
||||||
@@ -120,7 +143,7 @@ JNIEXPORT jlong JNICALL Java_android_view_SurfaceView_native_1constructor(JNIEnv
|
|||||||
g_signal_connect(dummy, "resize", G_CALLBACK(on_resize), callback_data);
|
g_signal_connect(dummy, "resize", G_CALLBACK(on_resize), callback_data);
|
||||||
g_signal_connect(dummy, "realize", G_CALLBACK(on_realize), callback_data);
|
g_signal_connect(dummy, "realize", G_CALLBACK(on_realize), callback_data);
|
||||||
|
|
||||||
return _INTPTR(dummy);
|
return _INTPTR(graphics_offload);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_android_view_SurfaceView_native_1createSnapshot(JNIEnv *env, jclass class)
|
JNIEXPORT jlong JNICALL Java_android_view_SurfaceView_native_1createSnapshot(JNIEnv *env, jclass class)
|
||||||
@@ -133,19 +156,14 @@ extern GtkWindow *window;
|
|||||||
JNIEXPORT void JNICALL Java_android_view_SurfaceView_native_1postSnapshot(JNIEnv *env, jclass class, jlong surface_view, jlong snapshot_ptr)
|
JNIEXPORT void JNICALL Java_android_view_SurfaceView_native_1postSnapshot(JNIEnv *env, jclass class, jlong surface_view, jlong snapshot_ptr)
|
||||||
{
|
{
|
||||||
GtkWidget *view = GTK_WIDGET(_PTR(surface_view));
|
GtkWidget *view = GTK_WIDGET(_PTR(surface_view));
|
||||||
#if GTK_CHECK_VERSION(4, 14, 0)
|
SurfaceViewWidget *surface_view_widget = SURFACE_VIEW_WIDGET(gtk_widget_get_first_child(view));
|
||||||
GtkPicture *picture = GTK_PICTURE(gtk_widget_get_first_child(gtk_widget_get_first_child(view)));
|
|
||||||
#else
|
|
||||||
GtkPicture *picture = GTK_PICTURE(gtk_widget_get_first_child(view));
|
|
||||||
#endif
|
|
||||||
GtkSnapshot *snapshot = GTK_SNAPSHOT(_PTR(snapshot_ptr));
|
GtkSnapshot *snapshot = GTK_SNAPSHOT(_PTR(snapshot_ptr));
|
||||||
GskRenderer *renderer = gsk_renderer_new_for_surface(gtk_native_get_surface(GTK_NATIVE(window)));
|
GskRenderer *renderer = gsk_renderer_new_for_surface(gtk_native_get_surface(GTK_NATIVE(window)));
|
||||||
GskRenderNode *node = gtk_snapshot_free_to_node(snapshot);
|
GskRenderNode *node = gtk_snapshot_free_to_node(snapshot);
|
||||||
GdkTexture *paintable = gsk_renderer_render_texture(renderer, node, NULL);
|
GdkTexture *texture = gsk_renderer_render_texture(renderer, node, NULL);
|
||||||
gsk_render_node_unref(node);
|
gsk_render_node_unref(node);
|
||||||
gsk_renderer_unrealize(renderer);
|
gsk_renderer_unrealize(renderer);
|
||||||
g_object_unref(renderer);
|
g_object_unref(renderer);
|
||||||
|
|
||||||
gtk_picture_set_paintable(picture, GDK_PAINTABLE(paintable));
|
surface_view_widget_set_texture(surface_view_widget, texture);
|
||||||
g_object_unref(paintable);
|
|
||||||
}
|
}
|
||||||
|
|||||||
18
src/api-impl-jni/widgets/android_view_SurfaceView.h
Normal file
18
src/api-impl-jni/widgets/android_view_SurfaceView.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#include <gtk/gtk.h>
|
||||||
|
|
||||||
|
G_DECLARE_FINAL_TYPE (SurfaceViewWidget, surface_view_widget, SURFACE_VIEW, WIDGET, GtkWidget)
|
||||||
|
|
||||||
|
struct _SurfaceViewWidget
|
||||||
|
{
|
||||||
|
GtkWidget parent_instance;
|
||||||
|
GdkTexture *texture;
|
||||||
|
void (*frame_callback)(SurfaceViewWidget *surface_view_widget);
|
||||||
|
gpointer frame_callback_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct _SurfaceViewWidgetClass
|
||||||
|
{
|
||||||
|
GtkWidgetClass parent_class;
|
||||||
|
};
|
||||||
|
|
||||||
|
void surface_view_widget_set_texture(SurfaceViewWidget *surface_view_widget, GdkTexture *texture);
|
||||||
@@ -283,7 +283,7 @@ ANativeWindow * ANativeWindow_fromSurface(JNIEnv* env, jobject surface)
|
|||||||
.global_remove = wl_registry_global_remove_handler
|
.global_remove = wl_registry_global_remove_handler
|
||||||
};
|
};
|
||||||
|
|
||||||
GtkWidget *surface_view_widget = _PTR(_GET_LONG_FIELD(surface, "widget"));
|
GtkWidget *surface_view_widget = gtk_widget_get_first_child(_PTR(_GET_LONG_FIELD(surface, "widget")));
|
||||||
GtkWidget *window = GTK_WIDGET(gtk_widget_get_native(surface_view_widget));
|
GtkWidget *window = GTK_WIDGET(gtk_widget_get_native(surface_view_widget));
|
||||||
while( (width = gtk_widget_get_width(surface_view_widget)) == 0 ) {
|
while( (width = gtk_widget_get_width(surface_view_widget)) == 0 ) {
|
||||||
// FIXME: UGLY: this loop waits until the SurfaceView widget gets mapped
|
// FIXME: UGLY: this loop waits until the SurfaceView widget gets mapped
|
||||||
@@ -312,13 +312,6 @@ ANativeWindow * ANativeWindow_fromSurface(JNIEnv* env, jobject surface)
|
|||||||
GdkDisplay *display = gtk_root_get_display(GTK_ROOT(window));
|
GdkDisplay *display = gtk_root_get_display(GTK_ROOT(window));
|
||||||
|
|
||||||
if (!getenv("ATL_DIRECT_EGL")) {
|
if (!getenv("ATL_DIRECT_EGL")) {
|
||||||
GtkWidget *graphics_offload = gtk_widget_get_first_child(surface_view_widget);
|
|
||||||
if (!GTK_IS_GRAPHICS_OFFLOAD(graphics_offload)) {
|
|
||||||
graphics_offload = gtk_graphics_offload_new(gtk_picture_new());
|
|
||||||
gtk_widget_insert_after(graphics_offload, surface_view_widget, NULL);
|
|
||||||
}
|
|
||||||
GtkPicture *gtk_picture = GTK_PICTURE(gtk_graphics_offload_get_child(GTK_GRAPHICS_OFFLOAD(graphics_offload)));
|
|
||||||
|
|
||||||
if (!wl_compositor) {
|
if (!wl_compositor) {
|
||||||
if (!wl_display_client)
|
if (!wl_display_client)
|
||||||
wl_display_client = wayland_server_start();
|
wl_display_client = wayland_server_start();
|
||||||
@@ -328,10 +321,10 @@ ANativeWindow * ANativeWindow_fromSurface(JNIEnv* env, jobject surface)
|
|||||||
printf("XXX: wl_compositor: %p\n", wl_compositor);
|
printf("XXX: wl_compositor: %p\n", wl_compositor);
|
||||||
}
|
}
|
||||||
struct wl_surface *wayland_surface = wl_compositor_create_surface(wl_compositor);
|
struct wl_surface *wayland_surface = wl_compositor_create_surface(wl_compositor);
|
||||||
// transfer the GtkPicture pointer to the wayland server abusing the set_buffer_scale and set_buffer_transform methods
|
// transfer the SurfaceViewWidget pointer to the wayland server abusing the set_buffer_scale and set_buffer_transform methods
|
||||||
g_object_ref(gtk_picture);
|
g_object_ref(surface_view_widget);
|
||||||
wl_surface_set_buffer_scale(wayland_surface, _INTPTR(gtk_picture));
|
wl_surface_set_buffer_scale(wayland_surface, _INTPTR(surface_view_widget));
|
||||||
wl_surface_set_buffer_transform(wayland_surface, _INTPTR(gtk_picture)>>32);
|
wl_surface_set_buffer_transform(wayland_surface, _INTPTR(surface_view_widget)>>32);
|
||||||
struct wl_egl_window *egl_window = wl_egl_window_create(wayland_surface, width, height);
|
struct wl_egl_window *egl_window = wl_egl_window_create(wayland_surface, width, height);
|
||||||
native_window->egl_window = (EGLNativeWindowType)egl_window;
|
native_window->egl_window = (EGLNativeWindowType)egl_window;
|
||||||
native_window->wayland_display = wl_display_client;
|
native_window->wayland_display = wl_display_client;
|
||||||
|
|||||||
@@ -7,13 +7,15 @@
|
|||||||
#include <gdk/wayland/gdkwayland.h>
|
#include <gdk/wayland/gdkwayland.h>
|
||||||
|
|
||||||
#include "../api-impl-jni/defines.h"
|
#include "../api-impl-jni/defines.h"
|
||||||
|
#include "../api-impl-jni/widgets/android_view_SurfaceView.h"
|
||||||
|
|
||||||
static EGLDisplay egl_display_gtk = NULL;
|
static EGLDisplay egl_display_gtk = NULL;
|
||||||
static GdkGLContext *gl_context_gtk = NULL;
|
static GdkGLContext *gl_context_gtk = NULL;
|
||||||
static struct wl_event_loop *event_loop = NULL;
|
static struct wl_event_loop *event_loop = NULL;
|
||||||
static GMutex mutex;
|
|
||||||
static PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL = NULL;
|
static PFNEGLQUERYWAYLANDBUFFERWL eglQueryWaylandBufferWL = NULL;
|
||||||
static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = NULL;
|
static PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES = NULL;
|
||||||
|
static GMutex mutex; // synchronize access to wl_display_server
|
||||||
|
static struct wl_display *wl_display_server;
|
||||||
|
|
||||||
/* runs on main thread */
|
/* runs on main thread */
|
||||||
static gboolean delete_texture(void *data) {
|
static gboolean delete_texture(void *data) {
|
||||||
@@ -26,7 +28,7 @@ static gboolean delete_texture(void *data) {
|
|||||||
struct _BufferData {
|
struct _BufferData {
|
||||||
GObject parent;
|
GObject parent;
|
||||||
gboolean destroyed;
|
gboolean destroyed;
|
||||||
GtkPicture *picture;
|
SurfaceViewWidget *surface_view_widget;
|
||||||
struct wl_resource *wl_buffer;
|
struct wl_resource *wl_buffer;
|
||||||
GdkGLTextureBuilder *texture_builder;
|
GdkGLTextureBuilder *texture_builder;
|
||||||
};
|
};
|
||||||
@@ -39,7 +41,7 @@ static void buffer_data_dispose(GObject *g_object)
|
|||||||
g_idle_add(delete_texture, _PTR(texture_id));
|
g_idle_add(delete_texture, _PTR(texture_id));
|
||||||
g_object_unref(buffer->texture_builder);
|
g_object_unref(buffer->texture_builder);
|
||||||
}
|
}
|
||||||
g_object_unref(buffer->picture);
|
g_object_unref(buffer->surface_view_widget);
|
||||||
}
|
}
|
||||||
static void buffer_data_class_init(BufferDataClass *cls)
|
static void buffer_data_class_init(BufferDataClass *cls)
|
||||||
{
|
{
|
||||||
@@ -50,13 +52,15 @@ G_DEFINE_TYPE(BufferData, buffer_data, G_TYPE_OBJECT)
|
|||||||
|
|
||||||
struct surface {
|
struct surface {
|
||||||
struct wl_resource *wl_surface;
|
struct wl_resource *wl_surface;
|
||||||
GtkPicture *picture;
|
SurfaceViewWidget *surface_view_widget;
|
||||||
struct wl_resource *frame_callback;
|
struct wl_resource *frame_callback;
|
||||||
|
struct wl_event_source *frame_timer;
|
||||||
BufferData *buffers[3];
|
BufferData *buffers[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
/* runs on main thread */
|
/* runs on main thread */
|
||||||
static void destroy_texture(void *data) {
|
static void destroy_texture(void *data)
|
||||||
|
{
|
||||||
BufferData *buffer = ATL_BUFFER_DATA(data);
|
BufferData *buffer = ATL_BUFFER_DATA(data);
|
||||||
g_mutex_lock(&mutex);
|
g_mutex_lock(&mutex);
|
||||||
if (!buffer->destroyed) {
|
if (!buffer->destroyed) {
|
||||||
@@ -67,7 +71,23 @@ static void destroy_texture(void *data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* runs on main thread */
|
/* runs on main thread */
|
||||||
static gboolean render_texture(void *data) {
|
static void draw_callback(SurfaceViewWidget *surface_view_widget)
|
||||||
|
{
|
||||||
|
g_mutex_lock(&mutex);
|
||||||
|
struct surface *surface = surface_view_widget->frame_callback_data;
|
||||||
|
if (surface && surface->frame_callback) {
|
||||||
|
wl_callback_send_done(surface->frame_callback, g_get_monotonic_time()/1000);
|
||||||
|
wl_resource_destroy(surface->frame_callback);
|
||||||
|
surface->frame_callback = NULL;
|
||||||
|
wl_event_source_timer_update(surface->frame_timer, 0);
|
||||||
|
wl_display_flush_clients(wl_display_server);
|
||||||
|
}
|
||||||
|
g_mutex_unlock(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* runs on main thread */
|
||||||
|
static gboolean render_texture(void *data)
|
||||||
|
{
|
||||||
BufferData *buffer = ATL_BUFFER_DATA(data);
|
BufferData *buffer = ATL_BUFFER_DATA(data);
|
||||||
if (!buffer->texture_builder) {
|
if (!buffer->texture_builder) {
|
||||||
g_mutex_lock(&mutex);
|
g_mutex_lock(&mutex);
|
||||||
@@ -98,8 +118,7 @@ static gboolean render_texture(void *data) {
|
|||||||
|
|
||||||
GdkTexture *texture = gdk_gl_texture_builder_build(buffer->texture_builder, destroy_texture, buffer);
|
GdkTexture *texture = gdk_gl_texture_builder_build(buffer->texture_builder, destroy_texture, buffer);
|
||||||
|
|
||||||
gtk_picture_set_paintable(buffer->picture, GDK_PAINTABLE(texture));
|
surface_view_widget_set_texture(buffer->surface_view_widget, texture);
|
||||||
g_object_unref(texture);
|
|
||||||
|
|
||||||
return G_SOURCE_REMOVE;
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
@@ -126,14 +145,20 @@ static void surface_attach(struct wl_client *client, struct wl_resource *resourc
|
|||||||
g_object_unref(buffer);
|
g_object_unref(buffer);
|
||||||
buffer = g_object_new(buffer_data_get_type(), NULL);
|
buffer = g_object_new(buffer_data_get_type(), NULL);
|
||||||
buffer->wl_buffer = wl_buffer;
|
buffer->wl_buffer = wl_buffer;
|
||||||
buffer->picture = g_object_ref(surface->picture);
|
buffer->surface_view_widget = g_object_ref(surface->surface_view_widget);
|
||||||
surface->buffers[0] = buffer;
|
surface->buffers[0] = buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback)
|
static void surface_frame(struct wl_client *client, struct wl_resource *resource, uint32_t callback)
|
||||||
{
|
{
|
||||||
struct surface *surface = wl_resource_get_user_data(resource);
|
struct surface *surface = wl_resource_get_user_data(resource);
|
||||||
|
if (surface->frame_callback)
|
||||||
|
wl_resource_destroy(surface->frame_callback);
|
||||||
surface->frame_callback = wl_resource_create(client, &wl_callback_interface, 1, callback);
|
surface->frame_callback = wl_resource_create(client, &wl_callback_interface, 1, callback);
|
||||||
|
surface->surface_view_widget->frame_callback = draw_callback;
|
||||||
|
surface->surface_view_widget->frame_callback_data = surface;
|
||||||
|
// this timer is required in case the main thread and the wayland server thread deadlock each other waiting for the next frame_callback
|
||||||
|
wl_event_source_timer_update(surface->frame_timer, 1000/20);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void surface_damage(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
|
static void surface_damage(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
|
||||||
@@ -142,9 +167,12 @@ static void surface_damage(struct wl_client *client, struct wl_resource *resourc
|
|||||||
|
|
||||||
static int frame_timer(void *data)
|
static int frame_timer(void *data)
|
||||||
{
|
{
|
||||||
struct wl_resource *frame_callback = data;
|
struct surface *surface = data;
|
||||||
wl_callback_send_done(frame_callback, g_get_monotonic_time()/1000);
|
if (surface->frame_callback) {
|
||||||
wl_resource_destroy(frame_callback);
|
wl_callback_send_done(surface->frame_callback, g_get_monotonic_time()/1000);
|
||||||
|
wl_resource_destroy(surface->frame_callback);
|
||||||
|
surface->frame_callback = NULL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,8 +180,6 @@ static void surface_commit(struct wl_client *client, struct wl_resource *resourc
|
|||||||
{
|
{
|
||||||
struct surface *surface = wl_resource_get_user_data(resource);
|
struct surface *surface = wl_resource_get_user_data(resource);
|
||||||
g_idle_add(render_texture, g_object_ref(surface->buffers[0]));
|
g_idle_add(render_texture, g_object_ref(surface->buffers[0]));
|
||||||
struct wl_event_source *timer = wl_event_loop_add_timer(event_loop, frame_timer, surface->frame_callback);
|
|
||||||
wl_event_source_timer_update(timer, 1000/60);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void surface_destroy(struct wl_client *client, struct wl_resource *resource) {
|
static void surface_destroy(struct wl_client *client, struct wl_resource *resource) {
|
||||||
@@ -162,8 +188,14 @@ static void surface_destroy(struct wl_client *client, struct wl_resource *resour
|
|||||||
surface->buffers[i]->destroyed = TRUE;
|
surface->buffers[i]->destroyed = TRUE;
|
||||||
g_object_unref(surface->buffers[i]);
|
g_object_unref(surface->buffers[i]);
|
||||||
}
|
}
|
||||||
g_object_unref(surface->picture);
|
surface->surface_view_widget->frame_callback = NULL;
|
||||||
|
surface->surface_view_widget->frame_callback_data = NULL;
|
||||||
|
g_object_unref(surface->surface_view_widget);
|
||||||
wl_resource_destroy(surface->wl_surface);
|
wl_resource_destroy(surface->wl_surface);
|
||||||
|
wl_event_source_timer_update(surface->frame_timer, 0);
|
||||||
|
if (surface->frame_callback)
|
||||||
|
wl_resource_destroy(surface->frame_callback);
|
||||||
|
surface->frame_callback = NULL;
|
||||||
g_free(surface);
|
g_free(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,14 +203,14 @@ static void surface_destroy(struct wl_client *client, struct wl_resource *resour
|
|||||||
static void surface_set_buffer_scale(struct wl_client *client, struct wl_resource *resource, int32_t scale)
|
static void surface_set_buffer_scale(struct wl_client *client, struct wl_resource *resource, int32_t scale)
|
||||||
{
|
{
|
||||||
struct surface *surface = wl_resource_get_user_data(resource);
|
struct surface *surface = wl_resource_get_user_data(resource);
|
||||||
surface->picture = _PTR((((uint64_t)(uintptr_t)surface->picture) & 0xffffffff00000000L) | ((uintptr_t)(uint32_t)scale));
|
surface->surface_view_widget = _PTR((((uint64_t)(uintptr_t)surface->surface_view_widget) & 0xffffffff00000000L) | ((uintptr_t)(uint32_t)scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we abuse this method to set higher 32 bits of the GtkPicture pointer */
|
/* we abuse this method to set higher 32 bits of the GtkPicture pointer */
|
||||||
static void surface_set_buffer_transform(struct wl_client *client, struct wl_resource *resource, int32_t transform)
|
static void surface_set_buffer_transform(struct wl_client *client, struct wl_resource *resource, int32_t transform)
|
||||||
{
|
{
|
||||||
struct surface *surface = wl_resource_get_user_data(resource);
|
struct surface *surface = wl_resource_get_user_data(resource);
|
||||||
surface->picture = _PTR((((uint64_t)(uintptr_t)surface->picture) & 0x00000000ffffffffL) | ((uintptr_t)(uint32_t)transform)<<32);
|
surface->surface_view_widget = _PTR((((uint64_t)(uintptr_t)surface->surface_view_widget) & 0x00000000ffffffffL) | ((uintptr_t)(uint32_t)transform)<<32);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct wl_surface_interface surface_implementation = {
|
static struct wl_surface_interface surface_implementation = {
|
||||||
@@ -197,6 +229,7 @@ static void compositor_create_surface(struct wl_client *client, struct wl_resour
|
|||||||
struct surface *surface = g_new0(struct surface, 1);
|
struct surface *surface = g_new0(struct surface, 1);
|
||||||
wl_resource_set_implementation(wl_surface, &surface_implementation, surface, NULL);
|
wl_resource_set_implementation(wl_surface, &surface_implementation, surface, NULL);
|
||||||
surface->wl_surface = wl_surface;
|
surface->wl_surface = wl_surface;
|
||||||
|
surface->frame_timer = wl_event_loop_add_timer(event_loop, frame_timer, surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct wl_compositor_interface compositor_implementation = {
|
static struct wl_compositor_interface compositor_implementation = {
|
||||||
@@ -234,7 +267,7 @@ struct wl_display *wayland_server_start()
|
|||||||
egl_display_gtk = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, wl_display_gtk, NULL);
|
egl_display_gtk = eglGetPlatformDisplay(EGL_PLATFORM_WAYLAND_KHR, wl_display_gtk, NULL);
|
||||||
gl_context_gtk = gdk_surface_create_gl_context(gtk_native_get_surface(GTK_NATIVE(window)), NULL);
|
gl_context_gtk = gdk_surface_create_gl_context(gtk_native_get_surface(GTK_NATIVE(window)), NULL);
|
||||||
|
|
||||||
struct wl_display *wl_display_server = wl_display_create();
|
wl_display_server = wl_display_create();
|
||||||
char tmpname[] = "/tmp/tmpdir.XXXXXX\0socket";
|
char tmpname[] = "/tmp/tmpdir.XXXXXX\0socket";
|
||||||
int tmplen = strlen(tmpname);
|
int tmplen = strlen(tmpname);
|
||||||
mkdtemp(tmpname);
|
mkdtemp(tmpname);
|
||||||
|
|||||||
Reference in New Issue
Block a user