GTK4 + GSK Cairo / Vulkan

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

Cairo is a ancient 2D library to draw shapes on linux platform.

It can be used in windows with proper library DLL extensions.

There a few software still uses cairo.

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

Source Code

End Of Article

 

Add new comment