Introduction
Source Code
By this article I want to start a series telling how to work with Vulkan API using Kotlin Native. What is Kotlin Native? It supposed to
compile your code to binaries not requiring Java VM or any other VM. So, it supposed to be platform independent code (except
parts that really platform dependant). Kotlin Native can produce arm32, arm64, x86_64, wasm32, etc. We're interested in arm and
x86 binaries. Kotlin Native can work with c and c++ libraries via so-called cinterop. It's still in development stage so there are some
difficulties with it to work. First of all there are no IDE that has a good support for it. What I tried: IntelliJ Clion trial version, I could
create a project, but I could not get a working multiplatform one. Android Studio - works fine for Android but not for other
platforms. IntelliJ IDEA community edition - the only one that worked with some limitations. And no one of them could debug a
project. So it would be nice to have some help with Vulkan debug layers and RenderDoc. The compile process is not quite fast for
now. And some other issues... I' ll tell about their workarounds during this article. Anyway it seems to be a good choice to use
alongside with c++ to develop graphics, math, science and so on libraries when it becomes mature. At first we will work with
Windows and Linux platforms and at the end of the series we'll add Android support. As for Vulkan API I would recommend good
examples in c++ by Sascha Willems or for beginners the set from Kronos:
If you are interested in Kotlin/Native because of performance, you really should choose something else. Kotlin/Native is
native not for performance. It is for situations, where you can’t afford a JVM (like an iOS app) and want to share logic
between platforms, or just write clean readable code. Kotlin/JVM is faster than K/N, and Rust is faster than both.
ark1JetBrains Team
If we compare development time and time to market performance I would say that Kotlin/Native shall be way faster :).
Jokes aside, it really depends on workloads, for truly heavy computational workloads like image processing and heavy
crypto I would suggest to use neither language, and rely on C. For tasks Kotlin/Native was intended for, performance shall
be acceptable or even brilliant, especially if measure not raw throughput, but perceived performance.
Nikolay_Igotti Kotlin team
As you will see in this project Kotlin is a good language. It's easy to learn. It's easy to use. And I very hope both Jetbrain team and
Kotlin team will change their minds concerning Kotlin Native performance and Kotlin Native will evolve this way.
Compile to arm and x86 platform. All variants are available from presets
https://www.codeproject.com/Articles/1288159/Vulkan-API-with-Kotlin-Native-Project-Setup?display=Print 1/9
27/03/2019 Vulkan API with Kotlin Native - Project Setup - CodeProject
Produce executable
Produce static or dynamic library
Produce Apple framework
Use external static/dynamic libraries or Apple framework
Debug project
Use macroses from c/c++ part
I didn' t find a way to check if we're in debug mode or at runtime
No intrinsic functions or inline assembly - only in C/C++ part.
No coroutines yet
Let' s begin...
Tools
IntelliJ IDEA
Vulkan SDK
RenderDoc
MINGW for Windows
Android Studio
Android NDK
For Linux - build essentials, gcc-multilib, g++-multilib, xcb, xkb, xkbcommon, xkbcommon-x11, xcb-xkb, Xxf86vm, xkb
extensions, Mesa libraries
Let' s take a look at project gradle file. Change yellowed "args '' " in runProgram block to "args []" so it won' t irritate us
anymore and rename it to runReleaseLinuxProgram . Then copy/paste this block rename it to runDebugLinuxProgram and change
builldType to "DEBUG". We will work with this.
Now if you will open "Gradle panel" at the left of IDE you will see two tasks, that we can run:
runDebugLinuxProgram
runReleaseLinuxProgram
https://www.codeproject.com/Articles/1288159/Vulkan-API-with-Kotlin-Native-Project-Setup?display=Print 2/9
27/03/2019 Vulkan API with Kotlin Native - Project Setup - CodeProject
Right click it and run. Now you can hav a cup of coffe until cinerops are done. Luckily it's just onse, after that IDE will use alredy
compiled binaries. As a result you will see " Hello, Kotlin/Native!" as a result in " Run" tab at the bottom of IDE:
To access Vulkan SDK include files and libraries add " VULKAN_SDK_ROOT" environment variable and for Windows
"MINGW_ROOT" environment variable also. Set their values to corresponding folders. Now we can use them in our gradle file:
https://www.codeproject.com/Articles/1288159/Vulkan-API-with-Kotlin-Native-Project-Setup?display=Print 3/9
27/03/2019 Vulkan API with Kotlin Native - Project Setup - CodeProject
Now we can add interop with C libraries. For this create nativeInterop/cinterop folder in the project source folder and add following
files:
Lvulkan.def (for Linux) - here we' ll add all needed include file and define xkb_event as we can't add union in Kotlin
package = vulkan
headers = vulkan/vulkan.h X11/Xlib.h X11/Xatom.h X11/keysym.h X11/extensions/xf86vmode.h X11/XKBlib.h
X11/extensions/XKBproto.h stdio.h stdlib.h locale.h unistd.h termios.h xcb/xkb.h xkbcommon/xkbcommon-
x11.h xkbcommon/xkbcommon-compose.h
---
union xkb_event {
struct {
uint8_t response_type;
uint8_t xkbType;
uint16_t sequence;
xcb_timestamp_t time;
uint8_t deviceID;
} any;
xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify;
xcb_xkb_map_notify_event_t map_notify;
xcb_xkb_state_notify_event_t state_notify;
};
package = vulkan
headers = vulkan/vulkan.h
And global.def (to pass data between threads, taken from Kotlin Native samples. )
package = kvn.global
---
typedef struct {
void* kotlinObject;
} SharedDataStruct;
SharedDataStruct sharedData;
Now to use them change the gradle file as following - we' ll add kotlin targets sections:
For Linux
configure([linux]) {
compilations.main.cinterops {
lvulkan {
includeDirs "/usr/include", "${project.VULKAN}/include"
compilerOpts "-DVK_USE_PLATFORM_XCB_KHR"
}
global
}
}
https://www.codeproject.com/Articles/1288159/Vulkan-API-with-Kotlin-Native-Project-Setup?display=Print 4/9
27/03/2019 Vulkan API with Kotlin Native - Project Setup - CodeProject
For Windows
configure([mingw]) {
compilations.main.cinterops {
vulkan {
compilerOpts "-DVK_USE_PLATFORM_WIN32_KHR"
includeDirs "${project.MINGW}\\include", "${project.VULKAN}\\include"
}
global
}
}
What's just happened. In "outputKinds" we said that wee need an executable file. We the program entry pount to "kvarc.main"
function - "kvarc" is the package name like in Java. In "linkerOpts" we set a path to libraries and libraries needed.
Now if you try to run program it will crash while loading libraries. On Windows just add a path to them to the PATH variable and on
Linux add to LD_LIBRARY_PATH.
After that let' s do some more modifications to the gradle build file. But first let's add shaders to the project. Add shaders folder
to the project and add triangle vertex and fragment shaders there (thanks to Sascha Willems):
Vertex shader:
#version 450
out gl_PerVertex
{
vec4 gl_Position;
};
void main()
{
outColor = inColor;
gl_Position = ubo.projectionMatrix * ubo.viewMatrix * ubo.modelMatrix * vec4(inPos.xyz, 1.0);
}
Fragment shader:
#version 450
void main()
{
outFragColor = vec4(inColor, 1.0);
}
https://www.codeproject.com/Articles/1288159/Vulkan-API-with-Kotlin-Native-Project-Setup?display=Print 5/9
27/03/2019 Vulkan API with Kotlin Native - Project Setup - CodeProject
// Task create function to compile project, compile shaders and run program
def createRunTask(def buildType, def platform ) {
return tasks.create("tmpRunProgram${buildType.capitalize()}${platform}") {
dependsOn "link${buildType.capitalize()}Executable$depends"
doLast {
exec {
workingDir "."
commandLine "${project.VULKAN}/bin/glslangValidator", "-V",
"$projectDir/src/shaders/$shader", "-o", "$folder/${shader}.spv"
}
}
}
What is it? It creates a task with a name depending on selected platform and selected build type. Then it goes through all shader
files in source folder, compiles them and save to assets folder. After that it runs the app with "LD_LIBRARY_PATH" set with Vulkan
SDK libraries path.
https://www.codeproject.com/Articles/1288159/Vulkan-API-with-Kotlin-Native-Project-Setup?display=Print 6/9
27/03/2019 Vulkan API with Kotlin Native - Project Setup - CodeProject
// Windows debug build
task runWindowsDebugProgram {
dependsOn createRunTask("debug", "mingw")
}
And last step - add common code, so we won' t return to the gradle build file anymore - for now we'll just create common/kvarc
folder in the project source folder. Then modify the gradle build file again, in sourceSets:
// Windows build
mingwMain {
kotlin.srcDirs += file("src/common")
}
// Linux build
linuxMain {
kotlin.srcDirs += file("src/common")
}
Note: don' t follow their note to enable common source sets, you won' t be able to use native platform dependent libraries in
this case.
The problem with common code we just added - every time you open the project or changing the gradle build file you will need to
change the project structure - remove the common code from there for not platform you' re working on and set "use project
properties" check for every module. Go to Preferences->Build, Execution, Deployment->Compiler->Kotlin Compiler and append
to Additional command line parameters the following key "-Xmulti-platform".
Now the common code part. We we'll need to know on which platform we're in during runtime. For this we will use enum class with
platform list:
package kvarc.utils
/**
* Supported platforms
*/
internal enum class PlatformEnum {
WINDOWS,
LINUX,
ANDROID //TODO
}
package kvarc
import kvarc.utils.PlatformEnum
companion object {
val type: PlatformEnum
}
Here "expect" keyword means that our class expects "actual" class to be implemented by each platform. And here they are,
changing:
MainLinux.kt:
package kvarc
import kvarc.utils.PlatformEnum
MainMingw.kt
package kvarc
import kvarc.utils.PlatformEnum
package kvarc
import kvarc.utils.PlatformEnum
when (Platform.type) {
PlatformEnum.WINDOWS -> println("Windows platform")
PlatformEnum.LINUX -> println("Linux platform")
PlatformEnum.ANDROID -> println("Android platform")
}
That's it. All out preparations are finished. Now, after we'll implement native windows for each platform we will work only with
common code
To be continued...
Resources
Kotlin Native Overview
IntelliJ IDEA for Windows
IntelliJ IDEA for Linux
Vulkan SDK - please use a version not later than 1.1.92.1. In later version something changed with debug layers, I didn't
check it yet.
MinGW
RenderDoc
Android Studio
Android NDK
Vulkan Documentation
Sascha Willems - Examples and demos for the new Vulkan API
Beginners Guide to Vulkan
Kotlin Native Repository
https://www.codeproject.com/Articles/1288159/Vulkan-API-with-Kotlin-Native-Project-Setup?display=Print 8/9
27/03/2019 Vulkan API with Kotlin Native - Project Setup - CodeProject
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile Article Copyright 2019 by Igor Kushnarev
Web01 | 2.8.190306.1 | Last Updated 27 Mar 2019 Everything else Copyright © CodeProject, 1999-2019
https://www.codeproject.com/Articles/1288159/Vulkan-API-with-Kotlin-Native-Project-Setup?display=Print 9/9