GTK4 + GSK Cairo / Vulkan

Submitted by Dickens A S on Sat, 12/07/2019 - 09:52

GitHubhttps://github.com/dickensas/kotlin-gradle-templates/tree/master/gtk4-gsk

This demo kotlin code explains how to render a cairo+graphene rectangle region using GSK

Kotlin Code

package plot

import kotlinx.cinterop.*
import gtk4.*

var app:CPointer<GtkApplication>? = null

fun realize_callback(widget:CPointer<GtkWidget>?) = memScoped {
    println("realize_callback")
}

fun render_callback(glarea:CPointer<GtkDrawingArea>?, cr:CPointer<cairo_t>?) = memScoped {
    println("render_callback")
    var csurface = cairo_get_target(cr)
    var region = gdk_cairo_region_create_from_surface(csurface)
    var rbga = allocArray<GdkRGBA>(1).apply {
        this[0].red = 1.0f
        this[0].green = 0.0f
        this[0].blue = 0.0f
        this[0].alpha = 1.0f
    }
    
    var grect = graphene_rect_alloc()
    grect = graphene_rect_init(grect, 50.0f, 50.0f, 300.0f, 300.0f)
    var gsknode = gsk_color_node_new(rbga, grect)
    
    gsk_render_node_draw(gsknode, cr)
    
    graphene_rect_free(grect)
    cairo_region_destroy(region)
}

fun activate_callback(app:CPointer<GtkApplication>?) = memScoped {
    println("activate")
	
    var window = gtk_application_window_new (app);
    gtk_window_set_default_size(window!!.reinterpret<GtkWindow>(), 400, 400)
    gtk_window_set_title(window.reinterpret<GtkWindow>(), "Demo Window")
    
    gtk_window_set_resizable(window.reinterpret<GtkWindow>(), 0)
    gtk_window_set_decorated(window.reinterpret<GtkWindow>(), 0)
    gtk_window_set_mnemonics_visible(window.reinterpret<GtkWindow>(), 0)

    val box = gtk_drawing_area_new()
    gtk_widget_set_size_request (box, 400, 400);
    gtk_window_set_child (window.reinterpret(), box)
    
	g_signal_connect_data(
        box!!.reinterpret(), 
        "realize", 
        staticCFunction {  glarea:CPointer<GtkWidget>?
            -> realize_callback(glarea)
        }.reinterpret(), 
        null, 
        null, 
        0u
    )

    gtk_drawing_area_set_draw_func(
        box.reinterpret(),
        staticCFunction {  glarea:CPointer<GtkDrawingArea>?, cr:CPointer<cairo_t>?
            -> render_callback(glarea,cr)
        }.reinterpret(),
        null, 
        null
    )
	
    gtk_widget_show (window);
}

fun main() = memScoped {
	app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE)
	
	g_signal_connect_data(
        app!!.reinterpret(), 
        "activate", 
        staticCFunction {  app:CPointer<GtkApplication>?
            -> activate_callback(app)
        }.reinterpret(), 
        null, 
        null, 
        0u
    )
	
    run_app(app, 0, null)
    g_object_unref (app)
    
}

 

The "run_app" method is C code -- this method exists in gtk4.def

---
void inline run_app(GtkApplication *app, int argc, char **argv) {
   g_application_run (G_APPLICATION (app), argc, argv);
}

 

Demo output

GSK GTK4

For vulkan set environment variable

GSK_RENDERER = vulkan

The entire GTK will be rendered using Vulkan

as of now custom shader cannot be submited to swapchain or framebuffers, none of those function are exposed

Experiment with your own risk: you can use below functions to create a custom context and do offscreen rendering

in realize callback

gdk_surface_create_vulkan_context gdk_draw_context_get_surface gsk_renderer_new_for_surface gdk_display_flush gdk_display_sync

in render callback

gdk_draw_context_begin_frame gdk_vulkan_context_get_draw_semaphore gdk_vulkan_context_get_draw_index vkQueuePresentKHR vkQueueWaitIdle gdk_draw_context_end_frame

To compile GTK4 refer this article gtk4 msys2

Add new comment