diff --git a/gtk3/gb_screen.c b/gtk3/gb_screen.c index 446f7a3..37aef51 100644 --- a/gtk3/gb_screen.c +++ b/gtk3/gb_screen.c @@ -7,7 +7,6 @@ struct _GbScreen { GtkBin parent; GtkGLArea *gl_area; - GtkDrawingArea *fallback; bool use_gl; shader_t shader; @@ -73,54 +72,44 @@ static void gb_screen_get_natural_size(GbScreen *self, gint *natural_width, gint if (scale_y_ptr) *scale_y_ptr = scale_y; } -static gboolean gb_screen_draw(GtkWidget *widget, cairo_t *cr) { - GTK_WIDGET_CLASS(gb_screen_parent_class)->draw(widget, cr); +static void gb_screen_calculate_viewport(GbScreen *self, Rect *viewport_ptr, gint *scaled_width_ptr, gint *scaled_height_ptr, double *scale_x_ptr, double *scale_y_ptr) { + gint scaled_width, scaled_height; + double scale_x, scale_y; - static gint scaled_width, scaled_height; - static double scale_x, scale_y; - - GbScreen *self = (GbScreen *) widget; - - GtkStyleContext *context = gtk_widget_get_style_context(widget); + GtkWidget *widget = GTK_WIDGET(self); int width = gtk_widget_get_allocated_width(widget); int height = gtk_widget_get_allocated_height(widget); - - gtk_render_background(context, cr, 0, 0, width, height); - gtk_render_frame(context, cr, 0, 0, width, height); gb_screen_get_natural_size(self, &scaled_width, &scaled_height, &scale_x, &scale_y); - Rect viewport = { - (width - scaled_width) / 2, - (height - scaled_height) / 2, - scaled_width, - scaled_height - }; - - if (self->use_gl) { - glViewport(viewport.x, viewport.y, scaled_width, scaled_height); - - uint32_t *pixels = gb_screen_get_current_buffer(self); - uint32_t *previous = gb_screen_get_previous_buffer(self); - - static void *_pixels = NULL; - - if (pixels) { - _pixels = pixels; - } - - glClearColor(0, 0, 0, 1); - glClear(GL_COLOR_BUFFER_BIT); - - render_bitmap_with_shader( - &self->shader, _pixels, previous, - self->screen_width, self->screen_height, - viewport.x, viewport.y, viewport.width, viewport.height, - self->blending_mode - ); - - // gtk_gl_area_queue_render(self->gl_area); + if (viewport_ptr) { + *viewport_ptr = (Rect){ + (width - scaled_width) / 2, + (height - scaled_height) / 2, + scaled_width, + scaled_height + }; } - else { + if (scaled_width_ptr) *scaled_width_ptr = scaled_width; + if (scaled_height_ptr) *scaled_height_ptr = scaled_height; + if (scale_x_ptr) *scale_x_ptr = scale_x; + if (scale_y_ptr) *scale_y_ptr = scale_y; +} + +static gboolean gb_screen_draw(GtkWidget *widget, cairo_t *cr) { + GbScreen *self = (GbScreen *)widget; + + if (!self->use_gl) { + int width = gtk_widget_get_allocated_width(widget); + int height = gtk_widget_get_allocated_height(widget); + + GtkStyleContext *context = gtk_widget_get_style_context(widget); + gtk_render_background(context, cr, 0, 0, width, height); + gtk_render_frame(context, cr, 0, 0, width, height); + + Rect viewport; + double scale_x, scale_y; + gb_screen_calculate_viewport(self, &viewport, NULL, NULL, &scale_x, &scale_y); + cairo_surface_t *surface = cairo_image_surface_create_for_data( (unsigned char *) gb_screen_get_current_buffer(self), CAIRO_FORMAT_RGB24, @@ -137,6 +126,9 @@ static gboolean gb_screen_draw(GtkWidget *widget, cairo_t *cr) { cairo_surface_destroy(surface); } + else { + GTK_WIDGET_CLASS(gb_screen_parent_class)->draw(widget, cr); + } return false; } @@ -181,6 +173,35 @@ static void gb_screen_get_property(GObject *object, guint property_id, GValue *v } } +static void gb_screen_gl_area_render(GtkGLArea *gl_area, GdkGLContext *context, GObject *object) { + GbScreen *self = (GbScreen *)object; + + Rect viewport; + gint scaled_width, scaled_height; + gb_screen_calculate_viewport(self, &viewport, &scaled_width, &scaled_height, NULL, NULL); + + glViewport(viewport.x, viewport.y, scaled_width, scaled_height); + + uint32_t *pixels = gb_screen_get_current_buffer(self); + uint32_t *previous = gb_screen_get_previous_buffer(self); + + static void *_pixels = NULL; + + if (pixels) { + _pixels = pixels; + } + + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + render_bitmap_with_shader( + &self->shader, _pixels, previous, + self->screen_width, self->screen_height, + viewport.x, viewport.y, viewport.width, viewport.height, + self->blending_mode + ); +} + static void gb_screen_gl_area_realized(GtkWidget *widget, GObject *object) { GbScreen *self = (GbScreen *)object; GtkGLArea *gl_area = GTK_GL_AREA(widget); @@ -231,6 +252,7 @@ static void gb_screen_constructed(GObject *object) { if (self->use_gl) { self->gl_area = GTK_GL_AREA(gtk_gl_area_new()); g_signal_connect(self->gl_area, "realize", G_CALLBACK(gb_screen_gl_area_realized), object); + g_signal_connect(self->gl_area, "render", G_CALLBACK(gb_screen_gl_area_render), object); gtk_gl_area_set_required_version(self->gl_area, 3, 2); gtk_gl_area_set_auto_render(self->gl_area, false); @@ -249,7 +271,7 @@ static void gb_screen_class_init(GbScreenClass *class) { obj_properties[PROP_USE_GL] = g_param_spec_boolean( "use-gl", "Use OpenGL", "Whether to use OpenGL for rendering.", true, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_PRIVATE + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE ); G_OBJECT_CLASS(class)->finalize = gb_screen_finalize; @@ -270,7 +292,6 @@ static void gb_screen_init(GbScreen *self) { } GbScreen *gb_screen_new(bool force_fallback) { - g_debug("force_fallback: %d", force_fallback); return g_object_new(GB_SCREEN_TYPE, "use-gl", !force_fallback, NULL); } @@ -337,3 +358,11 @@ void gb_screen_set_shader(GbScreen *self, const char *shader_name) { free_shader(&self->shader); init_shader_with_name(&self->shader, shader_name); } + +void gb_screen_queue_render(GbScreen *self) { + if (self->use_gl) { + gtk_gl_area_queue_render(self->gl_area); + } + + gtk_widget_queue_draw(GTK_WIDGET(self)); +} \ No newline at end of file diff --git a/gtk3/gb_screen.h b/gtk3/gb_screen.h index 91803fe..fc0f1d3 100644 --- a/gtk3/gb_screen.h +++ b/gtk3/gb_screen.h @@ -21,5 +21,6 @@ void gb_screen_flip(GbScreen *self); void gb_screen_set_resolution(GbScreen *self, unsigned width, unsigned height); void gb_screen_set_blending_mode(GbScreen *self, GB_frame_blending_mode_t mode); void gb_screen_set_shader(GbScreen *self, const char *shader_name); +void gb_screen_queue_render(GbScreen *self); #endif diff --git a/gtk3/main.c b/gtk3/main.c index d4caa4a..2d68f2c 100644 --- a/gtk3/main.c +++ b/gtk3/main.c @@ -671,7 +671,7 @@ static void stop(void) { } static gboolean on_vblank(GB_gameboy_t *gb) { - gtk_widget_queue_draw(GTK_WIDGET(gui_data.screen)); + gb_screen_queue_render(gui_data.screen); gtk_widget_queue_draw(GTK_WIDGET(gui_data.vram_viewer)); return false; @@ -1384,8 +1384,6 @@ static void shutdown(GApplication *app, GFile **files, gint n_files, const gchar stop(); SDL_Quit(); - - gtk_widget_destroy(GTK_WIDGET(gui_data.screen)); GB_free(&gb); g_object_unref(gui_data.builder); @@ -1449,7 +1447,7 @@ static void close_rom(void) { GB_free(&gb); gb_screen_clear(gui_data.screen); - gtk_widget_queue_draw(GTK_WIDGET(gui_data.screen)); + gb_screen_queue_render(gui_data.screen); vram_viewer_clear(gui_data.vram_viewer); gtk_widget_queue_draw(GTK_WIDGET(gui_data.vram_viewer));