How Kotlin can change developer experience with modern graphics APIs
CC Attribution 2.0 Belgium:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Barbieri, Giuseppe
Creating modern games in Kotlin forces you to use non-object oriented graphic languages and getting your hand dirty with native resource managemente. With wrappers around OpenGL and Vulkan, we make powerful graphics familiar to jvm devs and type-safe. Vulkan and OpenGL are the cross-platform standard for creating modern games and graphics. However, their respectively stateless and state-based systems have no relation to an object-oriented language like Kotlin and you have to be careful to handle native resources interacting with the API. Wrappers that we have built at Kotlin Graphics allow for them to become object oriented. This talk will teach the attendees how to use our wrappers VKK and GLN for Vulkan and OpenGL respectively in order to create performant, modern graphics. Graphic power meets Kotlin expressiveness VKK and GLN bring features such as type safety through inline classes and enums, DSL constructs, extension functions, typealias, less verbosity, pure jvm allocation strategy and an easy to pick up system. Because of the type-safety guarantee, we can directly call the native methods without performing potentially expensive checks. This allows users of Kotlin to create performant, modern games like those you could build on C or C++.
 So please welcome on stage Giuseppe. He's going to talk about how Kotlin can change developer experience with modern graphics APIs. Please. Hi. Thank you. I, as I said, I'm Giuseppe Berberi. I am a graphic developer by Reno who is working on a software called M-Check, which is a cut-like software for analyzing the visibility field of different types of vehicles. And basically, I followed in law with Kotlin some years ago, and then I started writing some utility leaves to help the developer with graphics. So let's get started. We started with OpGl. I will assume that, yeah, we are all Kotlinians. And some of you, I already know OpGl and maybe Vulkan. How many knows OpGl? Okay. Vulkan? Okay. So for the others, let's say, this is much more about code, so you can still understand most of the stuff. So let's get started with OpGl. So it's a really whole library, say, started in 1991 with STI. Then they left the development in 2006 and basically handover to Chronos, which released a very big version, 3.0, in 2008. They also used the application mechanism and context. The 4.1 is the less available MacOS. This is a little shame. And the last release available for all the other platforms is 4.6, which was released on 2017, two years ago. Vulkan came a little earlier than that. So welcome, GLN. What is about, basically about makes some, I would say, some massive use of inline classes where basically you already know it's an integer. Most of the time it's an integer, but works like classes and also Enums, although they are not really available in Kotlin, but there's a little trick. Then also we have inline functions. So basically you write the nice code and then everything, all the, let's say, I will not say, I agree, but all the boiler code will be then replaced by the compiler. It's also object oriented. So as I say, on the inline classes we have all the methods. DSL, where you can easily wrap some scope, some, let's say, OpenGL object, and then inside the scope do something nice, functional programming. So you can pass around lambdas whenever needed. And there are also some convenience of loading function that basically take maybe some parameter, some, let's say, parameters which are quite obvious out of the question. So we can have some more concise code. And it plays quite well, quite nicely with another library, GLM. It's basically a part of the original CGLM. To the best way is just to start showing code and let's go through a very, very simple Hello World program. So in this case, for example, we have, we start our main, we define some variable where we have, for example, the program variable, then an numerator to identify the two buffer that we're going to use, one for the vertex and one for the element, then the actual variable, which is under the hood, it's direct in buffer, it's native memory. Then we have one integer for the vertex array and two for the uniform, so-called MVP for the model view projection matrix and one for the diffuse color. Then let's dig into our first method, any program. Okay, here you can see in our function, we start just, I will show you first the plain way to do it in Kotlin. So we first create our program, then we want to create our vertex shader. We have another function for that called any vertex shader. We go inside our any vertex shader. We can define here the source, this is a pretty standard shader where we have, for example, matrix to then incoming attribute, vertex attributes and here Kotlin makes very nice because first we have the default vote. So compared to Java, this is already a very nice point, very nice advantages. And if we want, we can also inject, as you see in the comment, we can inject some explicit vertex layout, like for example position. Then we have also one for the color, we have an outside for the color that will be linearly interpreted by the segment shader and then in the main, we simply multiply the incoming position by the matrix. We assign to the GLSL position and then we also pass the color. Then we create our vertex shader. We pass the, we need to pass, of course, the type of vertex shader, the type of the shader that we want to create, in this case, vertex shader. Then we can have a generic in each shader where we give the object we just created and the source. In the in-node shaders, we receive, as I say, the shaders and the source. So first we want to set the source to the shaders. We want them to compile the shaders. It's a lot of redundancy here. Then we want to check if, of course, everything went fine or we want to know if there was some problem. So we retrieve the compile status. GL gets shader i means that, of course, we will get an int. Then we need to, for example, to check this int against one OpenGL concept like glFalse. If the compile failed, then we want to see what went wrong. So we want, of course, to retrieve the info log, but we have to retrieve the info log. We need first to retrieve the info log length. And this is what we are doing here. We pass the shader set and then the concept info log length. We return an int. Then with this, we can call glGetShaderInfo, which will return automatically a string. And then finally we can, through our nice exception, with the reason why the compilation failed. Then we can come back and we can return our vertex, which is an int. So how can we make this nicer? First we will return from the int. We have the shader, glShader. This is an inline classes. The source is the same. Let's comment out for space problems. Then our original glCreateShader will be converted to a static function on the inline class. So we want a glShader and we call create. Passing, in this case, vertex shader. You can think about it like an inline. Then what we do here is basically we scope the glShader. And then we can simply type much shorter code because we scoped it. So we know what this is going about and we don't want any more redundancy. So we call simply source. Maybe this is unfortunately naming. Then we compile our shaders. Compile status. This is also nice. We are inside these, let's say inside these scopes. So compile status is just, let's say, custom get variable, which we return. Of course, the compile status. We already know that the compile status should be a Boolean. So immediately we can return directly a Boolean. And then also the infolog. I don't want to write all the boiler code. So I want to hide in the library. I just want to type glShader infolog and then I'll retrieve all the log that is telling me what went wrong. So we saw here glShader.create.vertexshader. Question is, what is this vertex shader? It's an inline class or a numerator? Well, it's actually both because although Kotlin doesn't have yet inline numerator, there is an issue on U-Track, which I personally hope to implement also inline numerator. It's going to take some time. Hopefully one day we will get them. But in the meantime, there was a user. I don't remember the name, but on the Kotlin forum, we wrote these nitrics where we can basically use inline classes as an numerator. There's just one disadvantage. Let's say basically the end user can create some additional numerator, but of course we want to play nice. So it's a competitive environment. The user will not hurt itself and create an additional maybe wrong numerator. Then in our init, we come back to the init program. We just came back from create a vertex shader. Fragment is basically the same. I will not go inside because it's a matter of time. Then we have to attach the vertex and the fragment to our program. In this case, for example, we bind the attribute location like position and color to some parameterized variable. Then we link our program. Let's for a moment pause here and see what this can become. So program can be also an inline classes where we call basically glprogram create. And then we call apply. Here glprogram will be scoped again. We call our corresponding create vertex and fragment shader, which in this case, they will return inline classes instead of int. Then we can use, for example, the nice overload operator from Kotlin to attach the vertex to the program. We can then instead all of this stuff, glbind attribute location blah blah, we can simply type the string. We are inside the scope. So we offer an extension function on the string that when we will be set, it will be automatically called glbin attribute location behind the curtains. So it's more like, I would say, natural. Then we link, just one call, and then we continue. We continue. Here instead of link status, we have as before just one variable because we are inside this block. Also, infoloc is just one line. Then we detach the shaders. It's not mandatory, but if you want to do the things clear. We detach them from the program. And then we simply delete the shaders. Since they are inline classes, we have a method available on the inline class itself. Honestly, you can do all of this with just one line. Using glprogram init from path, you give the path of the shaders. And then the library will look through in this path for you give up to the name of the shaders, then the shaders need to be, you have all the same name, and then through some standard shader extension like that, frag, jam, test, and so on. We look if they are available. If they are available, we load them, and then it will compile into the program. Also, it will look in the same directory if you have any import on any additional shaders. Remember when we had to bind the attribute location? This, if you remember, need to be done before linking the program. So how can we do? We just pass them as lambda at the end of our init program. And this lambda will be, of course, served to you with the program base. It's an object. It basically offers you all this nice stuff like attribute with an extension variable on the stream. And this will be called before the link program. Then the link program, blah, blah, blah, return the GL program to you. Everything nice and fast. Okay, now init buffer. We go in the init buffer. This is pretty standard. We generate the buffer. We bind the buffer that we retrieved from our buffer variable using the numerator just to make it nicer. Then we bind to the jrray buffer target. We upload the position. We detach the buffer. Then we do the same for the element. And then we check the error. And we come out. So here, the buffer, we can basically generate them in just one line. We scope them. We, since we scope, we can just use the numerator to retrieve the corresponding buffer. We bound it. And then we pass lambda. What we call, for example, just data position data. Everything is already known. We know the buffer. We know the target. No need to redecler them. Same for the element and so on. At the end, the buffer will be detached. Check error. We need vertex array. We do the same. Generate the vertex array. Bind. We need to bind the buffer. We need to call a jr-vertex-set-to-boot point where we give all the stuff to specification for our vertex layout. Then we detach the bind buffer. And the vertex array requires to left-bond the element array. This is what we do. We enable. We detach. We check the error. What we can do, we can call jr-gen-vertex array. We give the reference to our inline function. This is also something really cool in Kotlin. We bound. We scope the buffers. We call the numerator bound on array. GLN offers some pretty fine layout. Just post to call sprit set. We automatically call all the lines that you see above. We bind the element. We enable. We check the error and we come back. Then here in the render, we basically have a window size vector position. Where we calculate our projection, matrix, view, and mvp matrix. Then GLN offers you some overloading function like this. GLN you port a window size. Set the clear color. Then we see the corresponding buffer. And we go to the next stuff. We use the program. We retrieve the memory stack in order to allocate our matrix on the net memory on the thread stack. And we bind the vertex array, draw element, and bind. Unuse the program. This can be done in the following code. Program used. We enter. Just GLN, uniform, mvp, and we give the matrix. Everything will be done in the background. Vertex array bound as before. Draw element, just pass element. Triangle is the default type primitive. All the rest will be retrieved from the int buffer. So we can retrieve the number of elements that remains. The type. So it's an int. So I'm saying int. And then the pointer at the end is defaulted to zero. That's true. At the end, we can just call the corresponding delete on the stuff. So with DSA, we can basically what was before, like GL buffer parameter get translated to GL get named buffer parameter. With GLN, it's simply buffer immutable storage on the line classes. Pretty natural and standard. So Vulkan. It's not only a cost plus one rendering, but also computing API. It's supposed to also take over OpenCL. Really low horoled. You have more than 1,000 lines for a single hello triangle. Boot upon Mantle, donated by MD. It was released on 2016, and the last release was at the beginning of this year. We have basically also in line classes and in line functions. It's object oriented. All the VK object has a lot of function on there. Function on Kagami and convenience overloading, low function. So basically we call the very end function of the LBGGL binding just before passing, going to the native, and then also play nice with GLN. Let's go just through a very short stuff. So just like creating sense, we want to have validation. What do we need to do first? Usually you want to retrieve the stack at the beginning of the function and then use in the body. We need to call, we need to allocate VK application info. But in order to do this, we need the first two for our application and giant name create, allocate some native space, and then allocate this string on the native memory via stack UTF-8. Then we call VK application info. We set this type, all the string, app version one, we go next. We retrieve the required extension. It's a pointer buffer. If it's null, then we are in a native state. Then we create a VK instance creating info also with the Korean type and then we pass our application info we just created. And if this required instance extension is not empty and we require, we want, the user want to have validation, then we need to allocate, we need to take the pointer buffer and then make space for another slot and then copy back all the stuff and finally allocate the new extension. Like we are doing here. So we copy all the extension for the, from the required extension to the instance extension variable. We allocate the VK debug details, then we actually put it and then we set the variable. Otherwise, we set immediately the variable of before because we didn't have to have a new extension. Then again, if we need validation, then we need the VK layer of the validation, which has all the current validation functionality. We want to check if these are available. So basically we retrieve all the instance layer properties in this way. You create pointer to an inter to retrieve all the layer properties count. And then with this, you can actually allocate all the buffer for the layer properties and then we finally all the layer properties. Then we check if this layer is present. If this is present, then we simply allocate a pointer buffer. We give this validation layer name in this pointer buffer and then we assign to the corresponding variable. If not, we find another. At the end, we create a pointer buffer where we'll be saved the instance pointer. So we call create create instance and we pass at the end our pointer buffer. We will return, we will get an inter at the end. Then we will create our VK instance. We pop the stack and we return the result. Create instance. So with VK2, we can just do this. Create instance. We return directly and inline classes. It's everything on Java. We don't want to deal. We already take the heat of the performance since we are in JVM. I don't want to take the heat about writing, let's say, I would not say hardly but pass me that bit with me on this. So I don't want to write all the boiler page tools. So application info. Hello triangle of my engine once. No need to deal with pre-string and so on. I don't have to specify the type. So then I get the required instance session. It's one unique release of string. I want to avoid the new ability. So just if it's empty, I'm in the failure state. Then I create the instance creating info. If it's not empty, if I want validation, I just add the string into the array list and then I simply pass the array list to the corresponding variable. If it's validation, VK layer validation, we just want line. We retrieve all our layer properties. All the boiler code is again hidden by the library. We check if it's present layer, if it's present, we simply have that. Otherwise we find the error. And then we create the instance. Again, no pointers. So we don't have to create a pointer buffer and then retrieve from the pointer buffer after calling the function. It's a direct instance session and there is no allocation function because I never saw anything about passing something for the allocation. So this is always null. What is the expected VK result? Well, since everything is in line, we can just call the function that it's a dummy constructor and then also accept a lambda at the end. It's in line so we can write a return and in the lambda we'll be given the result. At the first one, we return the instance. What happened to the stack? Well, you remember we had to create the stack once and then use inside the code. Here what we do, basically we use the stack just in two places where we retrieve the layer properties and when we get the instance. This will be all automatically done. I mean, if you don't pass it in this way, the stack will be retrieved. You will get the heat of the stack get twice. If you don't want to get this heat, then what you do, you basically call create instance using the memory stack as a receiver. So everything is nice, very few modifications and it's really efficient because in the hot loop you don't want to pay an additional heat so you can usually pass the stack that you get all through down the stack function. What is needed? All the libraries are available at etap.com and the Kotlin classes organization. Sorry, I don't have time for a question and answer and I hope you will find some interest there over there. Yeah. Thank you.
 So please welcome on stage Giuseppe.  He's going to talk about how Kotlin can change developer experience with modern graphics  APIs.  Please.  Hi.  Thank you.  I, as I said, I'm Giuseppe Berberi.  I am a graphic developer by Reno who is working on a software called M-Check, which is a cut-like  software for analyzing the visibility field of different types of vehicles.  And basically, I followed in law with Kotlin some years ago, and then I started writing  some utility leaves to help the developer with graphics.  So let's get started.  We started with OpGl.  I will assume that, yeah, we are all Kotlinians.  And some of you, I already know OpGl and maybe Vulkan.  How many knows OpGl?  Okay.  Vulkan?  Okay.  So for the others, let's say, this is much more about code, so you can still understand  most of the stuff.  So let's get started with OpGl.  So it's a really whole library, say, started in 1991 with STI.  Then they left the development in 2006 and basically handover to Chronos, which released  a very big version, 3.0, in 2008.  They also used the application mechanism and context.  The 4.1 is the less available MacOS.  This is a little shame.  And the last release available for all the other platforms is 4.6, which was released  on 2017, two years ago.  Vulkan came a little earlier than that.  So welcome, GLN.  What is about, basically about makes some, I would say, some massive use of inline classes  where basically you already know it's an integer.  Most of the time it's an integer, but works like classes and also Enums, although they  are not really available in Kotlin, but there's a little trick.  Then also we have inline functions.  So basically you write the nice code and then everything, all the, let's say, I will not  say, I agree, but all the boiler code will be then replaced by the compiler.  It's also object oriented.  So as I say, on the inline classes we have all the methods.  DSL, where you can easily wrap some scope, some, let's say, OpenGL object, and then inside  the scope do something nice, functional programming.  So you can pass around lambdas whenever needed.  And there are also some convenience of loading function that basically take maybe some parameter,  some, let's say, parameters which are quite obvious out of the question.  So we can have some more concise code.  And it plays quite well, quite nicely with another library, GLM.  It's basically a part of the original CGLM.  To the best way is just to start showing code and let's go through a very, very simple  Hello World program.  So in this case, for example, we have, we start our main, we define some variable where  we have, for example, the program variable, then an numerator to identify the two buffer  that we're going to use, one for the vertex and one for the element, then the actual variable,  which is under the hood, it's direct in buffer, it's native memory.  Then we have one integer for the vertex array and two for the uniform, so-called MVP for  the model view projection matrix and one for the diffuse color.  Then let's dig into our first method, any program.  Okay, here you can see in our function, we start just, I will show you first the plain  way to do it in Kotlin.  So we first create our program, then we want to create our vertex shader.  We have another function for that called any vertex shader.  We go inside our any vertex shader.  We can define here the source, this is a pretty standard shader where we have, for example,  matrix to then incoming attribute, vertex attributes and here Kotlin makes very nice  because first we have the default vote.  So compared to Java, this is already a very nice point, very nice advantages.  And if we want, we can also inject, as you see in the comment, we can inject some explicit  vertex layout, like for example position.  Then we have also one for the color, we have an outside for the color that will be linearly  interpreted by the segment shader and then in the main, we simply multiply the incoming  position by the matrix.  We assign to the GLSL position and then we also pass the color.  Then we create our vertex shader.  We pass the, we need to pass, of course, the type of vertex shader, the type of the shader  that we want to create, in this case, vertex shader.  Then we can have a generic in each shader where we give the object we just created and  the source.  In the in-node shaders, we receive, as I say, the shaders and the source.  So first we want to set the source to the shaders.  We want them to compile the shaders.  It's a lot of redundancy here.  Then we want to check if, of course, everything went fine or we want to know if there was  some problem.  So we retrieve the compile status.  GL gets shader i means that, of course, we will get an int.  Then we need to, for example, to check this int against one OpenGL concept like glFalse.  If the compile failed, then we want to see what went wrong.  So we want, of course, to retrieve the info log, but we have to retrieve the info log.  We need first to retrieve the info log length.  And this is what we are doing here.  We pass the shader set and then the concept info log length.  We return an int.  Then with this, we can call glGetShaderInfo, which will return automatically a string.  And then finally we can, through our nice exception, with the reason why the compilation  failed.  Then we can come back and we can return our vertex, which is an int.  So how can we make this nicer?  First we will return from the int.  We have the shader, glShader.  This is an inline classes.  The source is the same.  Let's comment out for space problems.  Then our original glCreateShader will be converted to a static function on the inline class.  So we want a glShader and we call create.  Passing, in this case, vertex shader.  You can think about it like an inline.  Then what we do here is basically we scope the glShader.  And then we can simply type much shorter code because we scoped it.  So we know what this is going about and we don't want any more redundancy.  So we call simply source.  Maybe this is unfortunately naming.  Then we compile our shaders.  Compile status.  This is also nice.  We are inside these, let's say inside these scopes.  So compile status is just, let's say, custom get variable, which we return.  Of course, the compile status.  We already know that the compile status should be a Boolean.  So immediately we can return directly a Boolean.  And then also the infolog.  I don't want to write all the boiler code.  So I want to hide in the library.  I just want to type glShader infolog and then I'll retrieve all the log that is telling  me what went wrong.  So we saw here glShader.create.vertexshader.  Question is, what is this vertex shader?  It's an inline class or a numerator?  Well, it's actually both because although Kotlin doesn't have yet inline numerator, there  is an issue on U-Track, which I personally hope to implement also inline numerator.  It's going to take some time.  Hopefully one day we will get them.  But in the meantime, there was a user.  I don't remember the name, but on the Kotlin forum, we wrote these nitrics where we can  basically use inline classes as an numerator.  There's just one disadvantage.  Let's say basically the end user can create some additional numerator, but of course we  want to play nice.  So it's a competitive environment.  The user will not hurt itself and create an additional maybe wrong numerator.  Then in our init, we come back to the init program.  We just came back from create a vertex shader.  Fragment is basically the same.  I will not go inside because it's a matter of time.  Then we have to attach the vertex and the fragment to our program.  In this case, for example, we bind the attribute location like position and color to some parameterized  variable.  Then we link our program.  Let's for a moment pause here and see what this can become.  So program can be also an inline classes where we call basically glprogram create.  And then we call apply.  Here glprogram will be scoped again.  We call our corresponding create vertex and fragment shader, which in this case, they  will return inline classes instead of int.  Then we can use, for example, the nice overload operator from Kotlin to attach the vertex to  the program.  We can then instead all of this stuff, glbind attribute location blah blah, we can simply  type the string.  We are inside the scope.  So we offer an extension function on the string that when we will be set, it will be automatically  called glbin attribute location behind the curtains.  So it's more like, I would say, natural.  Then we link, just one call, and then we continue.  We continue.  Here instead of link status, we have as before just one variable because we are inside this  block.  Also, infoloc is just one line.  Then we detach the shaders.  It's not mandatory, but if you want to do the things clear.  We detach them from the program.  And then we simply delete the shaders.  Since they are inline classes, we have a method available on the inline class itself.  Honestly, you can do all of this with just one line.  Using glprogram init from path, you give the path of the shaders.  And then the library will look through in this path for you give up to the name of the  shaders, then the shaders need to be, you have all the same name, and then through some  standard shader extension like that, frag, jam, test, and so on.  We look if they are available.  If they are available, we load them, and then it will compile into the program.  Also, it will look in the same directory if you have any import on any additional shaders.  Remember when we had to bind the attribute location?  This, if you remember, need to be done before linking the program.  So how can we do?  We just pass them as lambda at the end of our init program.  And this lambda will be, of course, served to you with the program base.  It's an object.  It basically offers you all this nice stuff like attribute with an extension variable on  the stream.  And this will be called before the link program.  Then the link program, blah, blah, blah, return the GL program to you.  Everything nice and fast.  Okay, now init buffer.  We go in the init buffer.  This is pretty standard.  We generate the buffer.  We bind the buffer that we retrieved from our buffer variable using the numerator just  to make it nicer.  Then we bind to the jrray buffer target.  We upload the position.  We detach the buffer.  Then we do the same for the element.  And then we check the error.  And we come out.  So here, the buffer, we can basically generate them in just one line.  We scope them.  We, since we scope, we can just use the numerator to retrieve the corresponding buffer.  We bound it.  And then we pass lambda.  What we call, for example, just data position data.  Everything is already known.  We know the buffer.  We know the target.  No need to redecler them.  Same for the element and so on.  At the end, the buffer will be detached.  Check error.  We need vertex array.  We do the same.  Generate the vertex array.  Bind.  We need to bind the buffer.  We need to call a jr-vertex-set-to-boot point where we give all the stuff to specification  for our vertex layout.  Then we detach the bind buffer.  And the vertex array requires to left-bond the element array.  This is what we do.  We enable.  We detach.  We check the error.  What we can do, we can call jr-gen-vertex array.  We give the reference to our inline function.  This is also something really cool in Kotlin.  We bound.  We scope the buffers.  We call the numerator bound on array.  GLN offers some pretty fine layout.  Just post to call sprit set.  We automatically call all the lines that you see above.  We bind the element.  We enable.  We check the error and we come back.  Then here in the render, we basically have a window size vector position.  Where we calculate our projection, matrix, view, and mvp matrix.  Then GLN offers you some overloading function like this.  GLN you port a window size.  Set the clear color.  Then we see the corresponding buffer.  And we go to the next stuff.  We use the program.  We retrieve the memory stack in order to allocate our matrix on the net memory on the  thread stack.  And we bind the vertex array, draw element, and bind.  Unuse the program.  This can be done in the following code.  Program used.  We enter.  Just GLN, uniform, mvp, and we give the matrix.  Everything will be done in the background.  Vertex array bound as before.  Draw element, just pass element.  Triangle is the default type primitive.  All the rest will be retrieved from the int buffer.  So we can retrieve the number of elements that remains.  The type.  So it's an int.  So I'm saying int.  And then the pointer at the end is defaulted to zero.  That's true.  At the end, we can just call the corresponding delete on the stuff.  So with DSA, we can basically what was before, like GL buffer parameter get translated to  GL get named buffer parameter.  With GLN, it's simply buffer immutable storage on the line classes.  Pretty natural and standard.  So Vulkan.  It's not only a cost plus one rendering, but also computing API.  It's supposed to also take over OpenCL.  Really low horoled.  You have more than 1,000 lines for a single hello triangle.  Boot upon Mantle, donated by MD.  It was released on 2016, and the last release was at the beginning of this year.  We have basically also in line classes and in line functions.  It's object oriented.  All the VK object has a lot of function on there.  Function on Kagami and convenience overloading, low function.  So basically we call the very end function of the LBGGL binding just before passing,  going to the native, and then also play nice with GLN.  Let's go just through a very short stuff.  So just like creating sense, we want to have validation.  What do we need to do first?  Usually you want to retrieve the stack at the beginning of the function and then use  in the body.  We need to call, we need to allocate VK application info.  But in order to do this, we need the first two for our application and giant name create,  allocate some native space, and then allocate this string on the native memory via stack  UTF-8.  Then we call VK application info.  We set this type, all the string, app version one, we go next.  We retrieve the required extension.  It's a pointer buffer.  If it's null, then we are in a native state.  Then we create a VK instance creating info also with the Korean type and then we pass  our application info we just created.  And if this required instance extension is not empty and we require, we want, the user  want to have validation, then we need to allocate, we need to take the pointer buffer  and then make space for another slot and then copy back all the stuff and finally allocate  the new extension.  Like we are doing here.  So we copy all the extension for the, from the required extension to the instance extension  variable.  We allocate the VK debug details, then we actually put it and then we set the variable.  Otherwise, we set immediately the variable of before because we didn't have to have a  new extension.  Then again, if we need validation, then we need the VK layer of the validation, which  has all the current validation functionality.  We want to check if these are available.  So basically we retrieve all the instance layer properties in this way.  You create pointer to an inter to retrieve all the layer properties count.  And then with this, you can actually allocate all the buffer for the layer properties and  then we finally all the layer properties.  Then we check if this layer is present.  If this is present, then we simply allocate a pointer buffer.  We give this validation layer name in this pointer buffer and then we assign to the corresponding  variable.  If not, we find another.  At the end, we create a pointer buffer where we'll be saved the instance pointer.  So we call create create instance and we pass at the end our pointer buffer.  We will return, we will get an inter at the end.  Then we will create our VK instance.  We pop the stack and we return the result.  Create instance.  So with VK2, we can just do this.  Create instance.  We return directly and inline classes.  It's everything on Java.  We don't want to deal.  We already take the heat of the performance since we are in JVM.  I don't want to take the heat about writing, let's say, I would not say hardly but pass  me that bit with me on this.  So I don't want to write all the boiler page tools.  So application info.  Hello triangle of my engine once.  No need to deal with pre-string and so on.  I don't have to specify the type.  So then I get the required instance session.  It's one unique release of string.  I want to avoid the new ability.  So just if it's empty, I'm in the failure state.  Then I create the instance creating info.  If it's not empty, if I want validation, I just add the string into the array list and  then I simply pass the array list to the corresponding variable.  If it's validation, VK layer validation, we just want line.  We retrieve all our layer properties.  All the boiler code is again hidden by the library.  We check if it's present layer, if it's present, we simply have that.  Otherwise we find the error.  And then we create the instance.  Again, no pointers.  So we don't have to create a pointer buffer and then retrieve from the pointer buffer  after calling the function.  It's a direct instance session and there is no allocation function because I never saw  anything about passing something for the allocation.  So this is always null.  What is the expected VK result?  Well, since everything is in line, we can just call the function that it's a dummy constructor  and then also accept a lambda at the end.  It's in line so we can write a return and in the lambda we'll be given the result.  At the first one, we return the instance.  What happened to the stack?  Well, you remember we had to create the stack once and then use inside the code.  Here what we do, basically we use the stack just in two places where we retrieve the layer  properties and when we get the instance.  This will be all automatically done.  I mean, if you don't pass it in this way, the stack will be retrieved.  You will get the heat of the stack get twice.  If you don't want to get this heat, then what you do, you basically call create instance  using the memory stack as a receiver.  So everything is nice, very few modifications and it's really efficient because in the hot  loop you don't want to pay an additional heat so you can usually pass the stack that  you get all through down the stack function.  What is needed?  All the libraries are available at etap.com and the Kotlin classes organization.  Sorry, I don't have time for a question and answer and I hope you will find some interest  there over there.  Yeah.  Thank you.
kotlin_how_can_change_developer_exp_graphics_api_0_1487.png kotlin_how_can_change_developer_exp_graphics_api_1488_14231.png kotlin_how_can_change_developer_exp_graphics_api_14232_21743.png kotlin_how_can_change_developer_exp_graphics_api_21744_25607.png kotlin_how_can_change_developer_exp_graphics_api_25608_25751.png kotlin_how_can_change_developer_exp_graphics_api_25752_25931.png kotlin_how_can_change_developer_exp_graphics_api_25932_26003.png kotlin_how_can_change_developer_exp_graphics_api_26004_26183.png kotlin_how_can_change_developer_exp_graphics_api_26184_26447.png kotlin_how_can_change_developer_exp_graphics_api_26448_26567.png kotlin_how_can_change_developer_exp_graphics_api_26568_26639.png kotlin_how_can_change_developer_exp_graphics_api_26640_28523.png kotlin_how_can_change_developer_exp_graphics_api_28524_31187.png kotlin_how_can_change_developer_exp_graphics_api_31188_36191.png kotlin_how_can_change_developer_exp_graphics_api_36192_38404.png