Dienstag, 7. Dezember 2021

CHIP-8 emulator with Kotlin multiplatform

My main spare time project got a bit boring after some years and I wanted to do something small, rewarding, refreshing to test drive some cool new things. For example I wanted to  see what the current state of Kotlin multiplatform develpment is, after it was alreday really enjoyable for JVM/JS development back in 2019 for me. I am also very interested in GraalVM, my mediocre experience from 2018/2019 needs to be overriden with something more happy. So I decided to implement a CHIP-8 emulator, like ... nearly everyone who's doing software development already did before I had the idea. So I did it when it wasn't cool anymore, is that okay?

CHIP-8

I won't waste your time explaining all the details - CHIP-8 is already so well known and implemented a dozen times for every platform you can think of, you can google that easily by yourself. I use my remaining words to say that I am very thankful for this blog, this post and this wikipedia page! Those three pages contain all the information you need to implement an emulator yourself. Additionally, there are some repositories where you can get ROMs, like a nice ROM to test your emulator, or some funny game ROMs.

Kotlin Unsigned Types

Kotlin the language is heavily influenced by the JVM, as it is its main target. There's some friction because of that when implementing something as low level as an emulator. For example it's very nice to just have language support for unsigned types, which makes a lot of sense for indices. The support however, ends where anything related to the JVM appears, which is unfortunately the case for array indexing: The API expects a signed int as an index. Since there is no implicit conversion in the language, a program counter that essentially could be an unsigned int, needs to be explicitly converted with statements like 

val firstByte = memory[programCounter.toInt()]
val secondByte = memory[(programCounter.toInt() + 1)]

which is not too nice. It's not super important, as CHIP-8 only uses 4k memory, so we don't need all the bits of the int, but nonetheless. Furthermore, there are no bitshift operators on bytes, neither signed nor unsigned, so conversion to integer is always necessary after fetching instruction bytes from the memory, like so:

val a = (firstByte.toUInt() shr 4) and 0b0000000000001111u

Kotlin when statements

When statements with subject allow for very nice matching code for the opcodes. Take a look at this, as I think it is really readable. Maybe in the future passing this into all OpCode constructors can be removed with contextual constructors. I had to smirk a bit, because my main source of info for the emulator recommended to just inline all the calls and don't do a lot of architecture, but yeah, I couldn't resist and think it was for the good.

Multiplatform

Spoiler alert: I wasn't able to complete the emulator for Kotlin native targets like Windows or Linux.

So I started implementing everything in the common source set that can be compiled to all supported platforms, I planned for JavaScript, Windows, Linux and JVM. The first minor thing that was missing was a Bitset. Was able to resolve that with expect/actual pairs that pointed to the JVM implementation and implement a simple one for native by myself. The next thing that was missing in common sources was input handlig. I wasn't able to just access the native APIs, I didn't even manage to get autocompletion working. I then tried to just add two multiplatform libraries for input handling and resigned after some weird linkage errors I wasn't able to resolve. I wasn't able to be successful after 4 hours of work and I don't have that much time, so I conclude that the state of kotlin multiplatform for native targets hasn't changed that much, compared to my last try in 2019.

GraalVM

Now this one was really interesting for me. Simply bundling an existing web application with a (normally big) bunch of dependencies wasn't easy or even possible in 2019, as the ecosystem lacked tooling for kotlin, reflection, graalvm and the native image tool. This time, I had this nice gradle plugin, which is how I would wish tooling to be. Sadly, this time I had to use Windows, and for Windows, one needs to do some additional hops, namely use either the Windows SDK or Visual Studio Build Tools, which both need to be installed manually by clicking thorugh a bunch of websites and wizards. Of course the described way didn't work for me ootb, as the 2021 version of Visual Studio somehow uses different folder structures, so I needed to override the windowsVsVarsPath property in order to get it to run. After that, the compilation process just worked, finished my application in under 2 minutes, including some downloads, which is just NICE, I have to say. Size of the executable (.exe file!) is around 7MB, which is nice, considering I included ROMs, Swing and all that stuff. You can download it from the 0.0.1 release here.

Rendering

Even though there's no specification about the refresh rate at which CHIP-8 runs, it's common to set sth like 500Hz. This would mean 500 updates per second, or an update every 2ms. A game step needs to be finished within that budget though. Since simulation step and rendering step are coupled by specification for CHIP-8, both steps together may not exceed the budget. While not a problem for the game logic on modern machines, for rendering (if not to a console) it's a different story. I have/had different implementations tested, for example based on this console rendering library (which admittedly isn't meant to be used for games) or a very dumb implementation with Swing, rendering pixel by pixel on a graphics instance. Didn't meet the requirements, but I will write down the Swing journey as a seperate post, I think :)

Dienstag, 10. August 2021

How to pass multiple vars to terraform command in Gradle Exec task

I can't believe I wasn't able to find a single example on the internet about how to use the terraform executable with Java ProcessBuilder, Runtime.exec, Gradle's Exec task or anything else. How hard can it be might be your question. The problem is that it's not to intuitive and easy how to pass args when not just directly typing everything by hand on the shell directly.

In my case, I needed to pass mutliple var options into a terraform plan command. On the command line, this may look like

terraform plan -var foo=bar -var bar=baz -var-file=variables.prod.tfvars

Or as described in the official documentation, it could be

terraform apply -var="image_id=ami-abc123"
or
terraform apply -var='image_id_list=["ami-abc123","ami-def456"]' -var="instance_type=t2.micro"


There is even more documentation in order to make this thing work across different operating systems.
What struck me was apparently the whitespace between -var and the key value pair itself. Took me round about an hour to figure out this is the correct way to feed a command into a Gradle Exec task (Kotlin DSL ahead):


Mind that every var requires you to pass in an arg of -var and an arg of the key value pair itself.

Freitag, 29. Januar 2021

My master's thesis: Dynamic Global Illumination Using Realtime Importance Sampling And Image Based Lighting

I realized that I have never published or uploaded my master's thesis about global illumination stuff in realtime rendering from 2015. Even though it's written in german, it may be helpful for anyone out there, so feel free to take a look at the PDF version and the code examples.

https://drive.google.com/file/d/0B0j-0MDrGMAlSmtDNi1xWG5yMk0/view?usp=sharing

Quick summary: I utilized hand-placed, box-projected environment maps rendered and filtered in-engine in realtime in order to get a coarse scene representation. This is afterwards traced against with ray tracing, ray marching and cone tracing. For environment map rendering I created a datastrucutre per probe that is pretty much like a cubemap g-buffer, so lighting updates can be performed very fast. The whole process is complemented by screen space reflections because fine details or less rough reflections are not captured very good with this technique. I did some crazy experiments with volume interpolation in order to hide seams and leaks, added alpha information so that cone tracing through multiple volumes can be done and evaluated some optimizations. The results can be satisfying for diffuse indirect lighting and even for rough reflections, as long as the projection volume and the actual geometry don't differ that much.

All the implementations were made in my custom game engine I wrote from scratch and used afterwards for all the other experiments I did and wrote about here, like voxel cone tracing, gpu occlusion culling etc. So likely everything can be found in the repository (https://github.com/hannomalie/hpengine) in some git state :) The title picture in the readme is from the last state of my thesis technique, it looked like this


I also found two screen recordings I never uploaded.

This one is a demo scene with a tight office or school floor. It's a tough scene for illumination because sun light can only enter the scene through small windows/doors on the side and the ceiling lights are thin area lights pointing downwards only. It would mean global illumination effects account for the largest amount of illumination in this scene, which is captured quite well by my technique. Changing floor materials has a visible impact on the mood of the scene because of that.




This one is a special test scene that has a spot light as the only direct light source.

Dienstag, 24. November 2020

Kotlin dependency injection and modularization without a framework

Recently I found myself in yet another discussion about dependency injection frameworks. The internet showed me that there is a weird tension and a lot of discussions about runtime vs compile time di, reflection usage, compile time safety, service locator vs di pattern and many more.

Here's what I think: The only acceptable ... actually good implementation of a di framework is Scala implicits. The reason why the JVM world is so obsessed with di frameworks is because Java is such a limited language, that implementing things with the language only is simply not feasible.

Pure di in Kotlin

It doesn't need many features, but those we need are key to make frameworkless di (I will call it pure di from now on) practical: Primary constructors, default arguments and smart constructors. Implicit parameter passing like in Scala would be an optional bonus on top - this feature is too controversial to just require it for pure di.

About the "testability" requirement

So first, the elephant in the room: You don't need interfaces to create testable implementations for something. Mocking frameworks like mockk can just mock any class you have and replace the implementations. Conclusion: Hiding things behind an interface is a good idea for a lot of reasons, but di doesn't care about them. You decide what you accept as a dependency in your class and that's it. No drawbacks for testability when you aren't able to use the default implementation for testing.

No annotations 

I know there's a standard on the JVM, but as I said in the introduction, we should question that. When a class is declared, just from a domain driven perspective, why on earth should we annotate our constructor with @Inject for example? It's a technical detail of a framework my caller may or not may not use. And even if he uses it, why is the declaration of the constructor not sufficient for anyone else to use it, be it automatically or not by hand? From my pov, using annotations on the dependency is a code smell that we got used to because of CDI. Even worse when configuration file keys are added into the annotation...

Module definitions

A module itself doesn't have to be interfaced. The components of a module can be. The module itself is just a plain old class that defines related components.


Note how Kotlin's primary constructor with default arguments completely replaced the need for any complex override framework sometimes needed for testing or bean definition overrides. Smart constructors (operator fun invoke on an interface companion here) don't exactly relate to dependency injection but can serve as a factory for default implementations.

Multiple module definitions

Using multiple modules with frameworks is often not too easy because of a single container or service locator, that flattens all definitions into a single pool which is used for service retrieval. Service locator will be talked about in the next paragraph, now lets take a brief look how simple multiple modules can and should look in your applications:


Note that it's not necessary to bundle all modules into a single super module - you can group whatever is meaningful for your domain, not what the framework requires you to do. When you really want to squash all definitions, all components of all of your modules into a flat facade, you can either use Kotlin's built-in delegation and interfaces, like so



Or you can use... Scala 3 that has a feature called exports - just kidding, we're doing Kotlin right - or something like what I implemented with this one https://github.com/hannespernpeintner/kotlin-companionvals .

Factories, lazy, optional

All those features di frameworks offer are already built-in in the Kotlin language. Singletons are given by just using val properties. Take a look at this example how factories, lazy things and optional things can be implemented

  

Those features automatically work with IDE features such as auto completion and refactoring, which is one of the most important things in projects and the reason Kotlin is so successful. Also you don't get runtime errors for example for optional dependencies, as Kotlin's built-in nullability gives you compile time errors. An additional bonus is that you can have nullable dependencies on the interface and override with non-nullable implementations in a module. Using those modules non virtual when it's okay to rely on the implementation (for example in testing) safes you from using the double bang operator all over the place.

Service locator

Finally, the probably most important aspect of di frameworks, the piece of code that is the surface your application and your components are allowed to rely on (are they? :) ). The implementation of the service locator is the source of problems in most frameworks, as it always generifies your module graph into something unnecessary generic that works more or less like a big map of types/names to instances/factories. This is also where compile time safety is lost.

Without any frameworks, you can just pass around the module (interface when given) instance you want to use somewhere. I found the best strategy to just use the smallest possible dependencies in your components, even though that may make your primary constructors big - it's just cleaner and more appropriate than passing context objects aka modules directly. For the caller's convenience - which is not an unimportant aspect! - you can provide a smart constructor that takes a complete module.

This is the point where manual declarations are more verbose than the magic wiring frameworks do for you. But hey, that's code. Plain old code. Everyone can go to declarations, refactor them, add more smart constructors, know how they work without having to know any framework. This approach has proven to be appropriate for even big module graphs in my applications.

Inner-module dependencies in components

What if a component that is part of a module needs a component from that very module? Most frameworks solve this problem by making everything lazy. In code, we would reorder statements - with constructors, we have to either pull out default arguments and wire and pass arguments explicitly or change the properties order like so

Not too worse, I think.

Bonus Round 1: Constructor vs field injection

You may have noticed that I did only write about constructor injection. The short reason is, that everything else should never be used as it introduces mutable and invalid state in your application. Whenever you have to deal with an environment that requires you to use such a lifecycle, Kotlin offers the lateinit keyword that can be used perfectly with pure di - but more important it depends on the foreign framework whether it's simple, robust and important to implement. When your environment requires you to use CDI, you should probably stick to it. Or not use those frameworks any more :)

Bonus Round 2: Quasi mixins

Kotlin doesn't allow for multiple inheritance of state, but interfaces and default implementations can become quite powerful and useful for a mix of data driven design and modularization. The idea is to place implementations into interfaces, writing dependencies as abstract state. Interfaces can leverage multiple inheritance and what's left is the implementation of state that can be done declaratively.

Let's consider you have a typical webapp Controller class that fetches some Products and needs some dependencies for that because it's not trivial.

Using interface inheritance could be seen as an abuse of the language feature here, but let's try to stay pragmatic. Using it automatically brings local extensions into scope, enabling implicit parameter passing of contexts, hence dependency injection. This approach gives you the freedom of just not caring about modules at all and just think about fine grained dependencies. Pretty much what di frameworks give you, but without any runtime errors because the source code is your module graph that is already validated on the fly by the compiler :) This approach can also be combined with pure di - you can define generic implementations in interfaces and deliver some default implementations as final classes, just as you wish, I can't see any borders here.

Sonntag, 27. September 2020

Rendering massive amounts of animated grass

 I recently played Ghost of Tsushima and I was impressed by the amount of foilage that covers the world. Just as I was impressed when I played Horizon: Zero Dawn a few years back.

So my engine can already render a lot of instanced geometry, a lot of per-instance animations and so on, but for that much foilage that is needed for believable vegetation, this is too costly. The answer to the problem is pivot based animation and therefore some simple, stateless animation in the vertex shader.

In addition to that, the instances of for example grass, need to be clustered and culled efficiently. My two-phase occlusion and frustum culling pipeline is exhausted pretty fast, when we use it for 10000000 small instances without any hierarchical component. A cluster is best and easy a small local volume that covers enough instances to not mitigate the benefit of batching. For example it's not worth batching only 10 instances, only to be able to cull them better. 1000 instances seem to work well for me. I generate a cluster's instances randomly, so that I can just render the first n instances and scale n by distance between camera and cluster. This way, the cluster gets thinner and thinner, until completely culled. Hard culling results in pop-ins. For a smooth fadeout without alpha blending enabled - which would again kill the performance of foliage - screen door transparency can be used. This is again a simple few lines, now in the pixel shader, and culling is mostly hidden.

Three things that are for themselves very efficient team up for a nice solution for foliage: Pivot based animation, cluster culling and screen door transparency fading.



As stated under the first video, I don't have nicely authored pivot textures, so I created a veeeeery simple one that just goes from 0-1 from root to leaves of the grass.


Montag, 13. Juli 2020

Private routes with Kotlin JS and React Router

In order to implement login functionality in a Kotlin React app, I used React Context API to save an optional instance of Login. This context can be used to create a wrap-around component that checks whether a given route can be accessed or not. If not allowed, the request is redirected to the public /login route.

The context class has to provide a way to get the current login data and functionality to logout or login. The state resides in the main component and is accessed through the onChange callback. The component1 function can be used to destructure the useContext result when only read access is needed.

class LoginContextData(login: Login?, private val onChange: (Login?) -> Unit) {
    var login: Login? = login
        private set
    fun login(potentialLogin: Login) {
        login = potentialLogin
        onChange(login)
    }
    fun logout() {
        login = null
        onChange(login)
    }
    operator fun component1() = login
}
// can be global
val LoginContext = createContext(LoginContextData(null) { })

The context is used like


val loginState = useState(null as Login?)
val (login, setLogin) = loginState

LoginContext.Provider(LoginContextData(login) { newLogin ->
    setLogin(newLogin)
}) {
// render your tree here
}

Just like React Router provides the route function, we can write a function that does an if-else on the context and either calls the known route function or gives a redirect:


fun  RBuilder.privateRoute(
    path: String,
    exact: Boolean = false,
    strict: Boolean = false,
    children: RBuilder.(RouteResultProps<*>) -> ReactElement?
): ReactElement {
    val (login) = useContext(LoginContext)

    return route(path, exact, strict) { routerProps: RouteResultProps<*> ->
        if(login != null) {
            children(routerProps)
        } else {
            redirect(from = path, to = "/login")
        }
    }
}

The callsite can just use privateRoute instead or route and done. The login route remains public.

The context can be used to decide whether a navigation item should be rendered or not as well.

My journey with Kotlin JS and React

Honestly I have no idea what the purpose of this post could be, but I am really happy with Kotlin JS and react and I want to write down my thoughts after implementing a real world administration application in my spare time. Maybe some of the sources I link can help somebody, maybe my experience can help someone in a similar position.

This is the app I created:


It uses Kotlin JS, Kotlin react wrapper, react, react-dom, react-router-dom, uuid, styled components, Kotlin coroutines.... the react hooks api, the react context api and Bootstrap 4.

TLDR
: Even though Kotlin JS is still experimental, i created a complete administration application using it and encountered only a few minor bugs. There's so much gain in being able to use gradle tooling and Kotlin as a language for me, that I would happily accept some minor bugs here.

Motivation

I have to admit: I love Kotlin but I was very sceptical about its non-JVM targets, especially after reading a lot about Kotlin Native and its caveats. The thing is: I feel such a strong demand of frontend stuff, that it would be super super handy for a Kotlin team to be able to use the same language - and toolchain - for backend and frontend projects and even share libraries between the two targets. Maintaining builds and code on a high quality level is that much easier this way, polyglot really shows its costs there.

Chicken and egg

I would love to implement such a thing in the team at my company, but this is not an easy task: Kotlin JS is still experimental. The next Kotlin version (1.4) will break binary compatibility for example because the compiler backend is switched completely. Given there is already Typescript, it's very very hard to convince people that another experimental technology might do a good job for the frontend. This results in the chicken-egg-problem: No one tries it, no one knows whether it works out well, no one gains experience, no one helps moving the platform forward, no one makes any progress. Arguing for a new technology reminds me of the time my team switched to Kotlin from Java for the backend. And after we did it, everyone was much happier than before. Getting the time to proof that a techology is worth it and can be used in production is key.

Elephant in the room: JSX

The biggest downside of React with JavaScript is most probably JSX. It reminds me of the wild days when JSP was in. Not only does it require the build system to do very very complex stuff, but also I don't think it's a good idea to extend code with something that makes it code no more, mixing markup languages and programming languages, introducing many strange constructs that are mostly workarounds for naming clashes and identifiers that can't be mapped. Tooling has to be adjusted, knowledge has to be adjusted, code style has to be adjusted... This is a proper comment on that. Do you know what is a nice way to write the UI? kotlinx html. This is basically what everyone would be happy with. I am. There was only one missing piece in the workflow: When you get html based designs of the page you should program, you have to convert html to kotlin dsl. With JSX you can just paste the html into your component and modify it slightly for variable usage. For kotlin dsl, there is this, that lets you do the same, but additionally, you can just start refactor names, extracting methods and so on in the best IDE / one of the best IDEs out there.

Hooks 

The last time I used react was when hooks didn't exist. The usage of setState was so annoying for me, that I just didn't warm up with the framework at all, because state is the single most important aspect of the application code. Hooks are such a nice addition and make functional component usage so pleasant. Take a look at a simple example with kotlin. It's hard not to like that. Now the downside: Hooks have some constraints that are not too intuitive. And now a proper downside: Even though I never used any return statements in kotlin, placed every hook usage at the top of the component, I got the infamous rendered too few hooks error... I wasn't able to figure it out exactly but I suspect it came from nested component usage where I had a fairly complex list based component that nested a lot of stuff. I removed the complex component completely, but if I weren't able to do that because of design requirements, I would have had a hard time with it.

Build

Everyone who knows me knows: Builds are really my métier. I am doing this excessively for many many years with different build systems and I always ensure projects have clean, stable, maintainable builds that enable proper development and testing workflows. Builds are one of those areas where having only one kind of them in the team is very beneficial, as all of the existing tooling can be reused. Being able to use gradle is a big plus for me (note, gradle with kotlin, not gradle with groovy brrrr). Convince yourself of how easy and simple the gradle build of a kotlin js project can be here and here. I can confirm that it works like that for a complete application development cycle. The good thing is, that the whole webpack stuff is hidden from you so that you don't have to bother with the whole mess. However, if necessary, you can configure things. And this is one of the two issues I faced during development: Hot reloading with the webpack development server. I had to apply this workaround as everyone seems to have to. Annoying to find out, not a problem anymore after the small fix.

Final thoughts

What can I say? I am very happy about what can already be done with Kotlin JS. Finally, I can get back to frontend development with pleasure again, keeping all my gradle and kotlin love :)

Montag, 17. Februar 2020

BVH accelerated point light shading in deferred rendering

My engine uses a lot of modern techniques like programmable vertex pulling, persistent mapped buffer based multi threaded rendering with a ring buffer and at the core of these techniques, there is this concept of a simple structured buffer. Experiments with compute based ray tracing on kd- and octrees led me to stackless tree traversal on the gpu, which is very very interesting and can be easily found on the internet. And occasionally, I found this article about an alternative to all those clustered, forward plus deferred tile based or whatever approaches for a massive amount of lights. I highly recommend reading it and all the other nice posts over there. He got my interest. I heard about light bvhs only for offline renderers. And structured buffers? I have them. Compute shaders, I have them. My point lights? Yea, maybe I have many of them, but they mostly don't move. And than again, I need rendering and light evaluation not only for my deferred rendering pass, but also for my transparency pass, a regular grid of environment probes or my voxel cone tracing grid...

Long story short, implementing a basic version was very easy, because the concept is so simple.





Assuming a static tree, my implementation needs ~10ms for 100 point lights instead of ~34ms in the most trivial compute shader in the quite dense configuration above on my crappy notebook with integrated intel card. In a less dense configuration, the time goes down to ~4ms and less. It really depends on the amount of overlapping volumes and how efficient the tree is. 500 pointlights scattered over the Sponza atrium takes below 30ms.



BVH update: The most tricky and also the most costly part of the whole thing is probably the creation and update of the BVH which I haven't implemented efficiently yet. My creation happens on any light movement and clusters lights or inner nodes recursively into buckets of 4. 4 gave me better performance than 8 as in the blog post, probably because my light struct layout is not very efficient.

Sphere union: The implementation to find an enclosing sphere for n spheres is from here. I'm not too sure that a really optimal sphere is found, but since I'm feeding every sphere's aabb corner points into the library, some efficiency is already wasted on my side or the program.





Donnerstag, 26. Dezember 2019

Smart property delegation with Kotlin

Every now and then I have a use case where I have a data holder object that is wrapped by some other object. With Kotlin's interface delegation, it's very easy to implement an interface by delegating to the implementing property. However, sometimes you don't have interfaces, so I realized that there's one thing missing from the Kotlin standard lib: Have a property delegating to another property. Or at least I wasn't able to find it and it's kind of difficult to google that. So here's the solution:



I'm using a property reference (you need the reflection dependency for that) for generic property (get and set) usage. This is kind of a lense, known from functional programming I guess.

Nice things can done with that, for example typesafe ui components can be generated like that:

Sonntag, 1. Dezember 2019

Programmable vertex pulling

So i finally managed to invest some time to implement programmable vertex pulling in my engine. I can really recommend to implement an abstraction over persistent mapped buffers that lets you implement structured buffers of generic structs and then use it on the cpu and the gpu side as a simple array of things.

Nothing comes for free: I find it quite difficult to handle any other layout than std430 because that matches what your c, c++ code is doing, as long as you restrict yourself to always use 16 byte alignment members, I think. My struct framework doesn't do any alignment, so I just added dummy members where appropriate in order to match the layout requirements. Afterwards, struct definitions in glsl have to match your struct on the cpu side and the only things left for your vertices is


struct VertexPacked {
    vec4 position;
    vec4 texCoord;
    vec4 normal;
};
layout(std430, binding=7) buffer _vertices {
    VertexPacked vertices[];
};

...


int vertexIndex = gl_VertexID;
VertexPacked vertex = vertices[vertexIndex];


Combined with persistent mapping, you can get rid of any layout fuddling, synchronization, buffering, mapping...and it just works.

Regarding performance: I am using an array of structs approach because it is the simplest to use. The performance in my test scenes (for example sponza) is completely identical to the traditional approach. No performance differences on a Intel UHD Graphics 620.

Having free indexed access to vertices in your shaders can be beneficial in other situations as well. For example you can implement a kd-tree accelerated ray tracer with compute that uses indices into your regular vertex array.

Donnerstag, 14. November 2019

Pixel perfect picking with deferred rendering

There are several ways to accomplish pixel perfect picking in one's engine. Some tutorials mention an object hierarchy as a scene representation in order to trace rays for picking. This is often done on the CPU, where information about the object is already available when the ray hit callback is invoked when tracing. On the GPU, this could be done with a compute shader or a vertex shader that writes to an output buffer... this output buffer can be read back on the CPU.

With deferred rendering however, I have a simpler approach that doesn't involve any tracing at all. Since I need object IDs for later passes to fetch instance data out of a big buffer, I write them to one output texture in my deferred rendering buffer. The output texture can be of type int or uint, depending on the amount of objects you have to handle. One can pack the index into bits of a regular 8bit rgba texture, into a floating point texture, or whatever texture has some bits space left in your gbuffer. After the gbuffer pass of deferred rendering was done, one can use glReadPixels (with read buffer set) or glGetTexImage and the current mouse position to get the index of the clicked object back to the cpu side of things. Besides the format handling and the bit mangling, this is rather trivial, so I won't post code here, but here's a nice video of the usage in my new ribbon based editor :)

Sonntag, 8. September 2019

Sparse voxelization on the CPU

The various adventures with Voxel Cone Tracing showed me, that asynchronous and partly done voxelization on the gpu can become really really tricky, because the data structures involved are very hard to implement.

So after ditching clipmaps because they won't allow for enough caching of static sthings, I gave sparse voxelization another try. Like - I think - CryEngine, I wanted to implement voxelization on the cpu, in order to be able to perform it async and partly on demand. The voxelization itself didn't took too much time - I decided to go for the "brick" approach, which allocates either none or all eight children of a given node, whether some of them are empty or not. The advantage here would be that working with offsets is much easier, as first childs always are located at the brick pointer start and the next 7 children are contiguous in memory and one can just increment the pointer to get the next child. Using a pointer based apporach enables required asynchronicity and streaming, because the memory layout doesn't have to fulfill everything we need on the GPU later on for tracing. Super nice Kotlin coroutines enable usage of 100% of the cpu very easily with a fork join approach and just launching thousands of coroutines. Depth of the tree is 11, size is 1000³. I think in order to have this resolution, one would need a 3d texture with resolution of 512³ or 1024³ which usually is too costly for voxel cone tracing approaches.



I didn't squeeze out the last bit of performance here. So yes, maybe this can be implemented much faster. And no excuses, but the video itself eats up a lot of the fps I had - it had about 30 fps, pretty much limited by my laptop cpu.

And this video could be the last thing I can show about voxelization, because the tracing part didn't just work out as expected. In order to work with empty leave nodes, one has to get creative. Because if you intersect a ray with a box, but the hit would actually be with a box that is an empty leaf, you would have to backtrack the tree (hence you need parent node pointers in all nodes, but that's okay) until you get somewhere where some sibling nodes are left to be traced...

My implementation is too bad to be anywhere near realtime and debugging or reason about what's going on is very very tedious... after having my computer completely frozen half a dozen times because I made another stupid mistake on the GPU, I decided that this approach is just not doable in the amount of time I can afford :)

Freitag, 16. August 2019

Companion vals

I totally forgot to make a braindump about another feature I stumbled upon lately: companion vals.

There's this really interesting feature proposal for the Kotlin language.

In essence, the proposed feature allows to write the following code:


and the following code:

From my point of view the feature has two aspects.

The first one is making members of companion members part of the surrounding instance. That means we can have properties and their members are automatically exposed, hence you don't need to access them with dot notation.

The second aspect is that other scopes are treated as well: If something is marked as companion, it is automatically available as a receiver in the corresponding scope. The proposal only talks about class properties, which are available in the class body automatically. This enables having Kotlin's scoped extension functions available without the need to use with(AdressPrinter) }{} everywhere.

I extended the Kotlin compiler with these two features and widened the application of the second aspect to all (?) possible scopes. This means if the companion val is top level, it's automatically available in the whole file. If a function parameter is marked as companion, the argument is going to be available as a receiver in the function body and so on. The implementation can be found here and examples can be found in the working tests.

Since the compiler has no simple and no stable API, I also implemented an annotation processor, that fulfils the first aspect. Repository can be found here. This would make the above code compile (with the right imports). Works by generating extension functions for all members, just as you would do in Kotlin by hand anyway if you would want to have this functionality.

Sonntag, 24. Februar 2019

Multivolume voxel cone tracing

Another feature experiment I nearly forgot to show you is voxel cone tracing with multiple voxel volumes. There are different approaches to support large scenes with voxel cone tracing:

* Use a single volume texture and scale it to the scene's bounds. This increases a single voxel's world extents, which leads to coarser lighting and even more light leaking.
* Use sparse octree voxelization with a buffer instead of a volume texture. This is a way more complicated implementation. Additionally, the performance hit for lighting evaluation is quite big, compared to hardware-filtered volume texel fetching.
* Use cascaded voxel cone tracing, a similar approach to cascaded shadow maps. Revoxelization of the whole scene (or what's visible for the player) is quite demanding - implementations that only revoxelize objects on the border of the cascades are way more complex than the traditional, non-cascaded approach. Not using such an approach and revoxelizing everything every frame leads to flickering in the voxelization step, which can't be eliminated complettely due to the "binary" nature" of voxels (or at least I didn't manage to achieve it).

My implementation goes a different way, that doesn't suffer from the above problems, by introducing world space voxel volumes. Instead of a single big one, there are many smaller ones. There are many advantages now:

* Not all voxel volumes have to be updated every frame - one can update the nearest n volumes per frame, depending on the given hardware specs.
* There can be higher resolutions where needed and less resolution where coarse illumination is sufficient.
* Since everything is in world space, no flickering on revoxelization - at least when materials change. For dynamic objects, one still has to do some tricks or use temporal filtering with multiple bounces or sth.
* Theoretically, the voxel data could be precalculated and streamed in.


I put a sized list of VoxelGrid entries into a generic buffer that my avaluation compute shaders can read. My VoxelGrid data structure is as simple as the following.
struct VoxelGrid {  
   int albedoGrid;  
   int normalGrid;  
   int grid;  
   int grid2;  
   int resolution;  
   int resolutionHalf;  
   int dummy2;  
   int dummy3;  
   mat4 projectionMatrix;  
   vec3 position;  
   float scale;  
   uvec2 albedoGridHandle;  
   uvec2 normalGridHandle;  
   uvec2 gridHandle;  
   uvec2 grid2Handle;  
 };  

As mentioned in an earlier post, my volumes use a kind of deferred rendering to cache geometry properties and onyl recaclulate lighting information when necessary, hence the need for 4 texture attachments - one for albedo, one for normals, and two for multiple bounces of gi.

The resolution (and the helper resolutionHalf) determine the resolution of the volume texture. This is needed, because the size of a volume can be arbitrary, while the resolution is fixed at some time, leading to arbitrary world space sizes for a single voxel.

Besides a little bit of padding, I also save the projection matrix that is used to voxelize objects into this volume. This isn't needed during evaluation, but I wanted to use a single data structure for both steps of the pipeline.

Since the texture ids don't give you much when using multiple volumes any more (you don't want to bind anything anymore...), those can be erased by now. What I use is bindless handles for everything, hence the long texture handles for the said four textures, passed in as uvec2 data types.

Tracing

Now the interesting part. When only a few volumes are used, let's say 5-10 or something, the tracing can easily be implemented as brute force iteration over an array. I don't think more volumes are practical, as each volume needs a lot of memory, and there comes the point where classic sparse voxel octrees are simply more efficient.

When implementing the tracing, I realized, that I want to favour higher resolution volumes when volumes overlap. Besides that, the tracing is quite simple: Take the gbuffer's world space position and trace diffuse or/and specular lighting in as many directions as you like. The sampling diameter increases with distance and determines the mipmap level to sample from.


    vec4 accum = vec4(0.0);
    float alpha = 0;
    float dist = 0;
    vec3 samplePos = origin;// + dir;

    while (dist <= maxDist && alpha < 1.0)
    {
        float minScale = 100000.0;
        int canditateIndex = -1;
        VoxelGrid voxelGrid;
        for(int voxelGridIndex = 0; voxelGridIndex < voxelGridArray.size; voxelGridIndex++) {
            VoxelGrid candidate = voxelGridArray.voxelGrids[voxelGridIndex];
            if(isInsideVoxelGrid(samplePos, candidate) && candidate.scale < minScale) {
                canditateIndex = voxelGridIndex;
                minScale = candidate.scale;
                voxelGrid = candidate;
            }
        }

        float minVoxelDiameter = 0.25f*voxelGrid.scale;
        float minVoxelDiameterInv = 1.0/minVoxelDiameter;
        vec4 ambientLightColor = vec4(0.);
        float diameter = max(minVoxelDiameter, 2 * coneRatio * (1+dist));
        float increment = diameter;

        if(canditateIndex != -1) {
            sampler3D grid;
            // sample grid here
        }

        dist += increment;
        samplePos = origin + dir * dist;
        increment *= 1.25f;
    }
 return vec4(accum.rgb, alpha);

The results are quite nice, with mixed resolutions and sizes of volumes. Here's an example of a transition between a fine and a coarse volume:

coarse and fine voxel volume side by side
Unfortunately, the performance of my tracing is not that good. It's remarkably slower than the single volume tracing, and I'm not too certain why this is the case. My test scene contained 4 volumes and decreased performance below 30 fps on my GTX 1060, to it's not capable of being realtime anymore. And I'm talking about avaluation only - no voxelization done here.

This again leads me to the conclusion, that voxel cone tracing is just too heavy on resources to be practical. I got the idea of using binary voxelization and only use voxels for occlusion and soft shadows, but evaluate global illumination from precomputed volumes. Much cheaper, no synchronization between voxelization threads and in general just a lot cheaper.

Samstag, 23. Februar 2019

Multibounce voxel cone tracing

It has been quite a while since I implemented a derivative of the classic voxel cone tracing with volume textures in my graphics engine that kind of applies deferred rendering with voxels in order to achieve multi bounce global illumination. The idea is to voxelize the whole scene to a voxel texture and save all parameters that are needed for lighting. Similar to the regular gbuffer in deferred rendering, positions (implicitly given by world space voxels..) normals and albedo can be sufficient. Additionally, my renderer writes a flag if the object is dynamic or static, in order to be able to cache voxel data for static objects, which massively speeds up voxelization proccess and just brings the whole thing closer to realtime capable.
Decoupling lighting from voxelization also frees enough frame time to implement multiple light bounces. Therefore, for n bounces, I added n light accumulation voxel texture targets. During voxel lighting, these are traced against. Although a second bounce can significantly enhance the scene's overall lighting. I struggled getting this to work with ping-ponging textures. I also struggled with parameters like samples on the hemisphere or tracing distance, cone aperture, etc. because in the voxel world, my default parameters for gbuffer tracing didn't lead to great results. Nonetheless, I wanted to share my results with you strangers, although I tend to discard this feature, because it  doesn't make voxel cone tracing's light leaking problem less appearent....

two bounces (first), one bounce (second)

Montag, 17. September 2018

Kind-of-structs on the JVM using Kotlin's delegated properties

Project Valhalla is on everyone's lips nowadays, but the problem is: It is for years now and there's no concrete schedule when we can expect value types to be part of the JVM.

In games, there is a desperate need for value types or at least control about the object layout. Why? Because one has to share memory with the native side. For example OpenGL lets you use a persistent mapped buffer - combined with multibuffering and your own synchronization gives you a blazing fast multithreading approach for your engine. But OpenGL doesn't want to read your Java object's headers, that's why you can't use regular serialzation mechanisms and instead you have to put your objects into a ByteBuffer float by float or int by int.

Using standard Java/JVM heap objects, one has to update all the objects and afterwards extract them to a ByteBuffer. This means two iterations. Better would be to have objects that use a ByteBuffer directly, in order to be able to skip the buffer extraction completely.

Now there's Kotlin with its delegated properties. All the basic examples show how to use a hash map instance as a backing storage for arbitrary properties of an object (https://kotlinlang.org/docs/reference/delegated-properties.html). This led me to the idea to use delegated properties to access a ByteBuffer object as a backing storage for objects and structures of objects - just like structs in C do it.

interface Struct { byteOffset: Int buffer: ByteBuffer } // some missing magic here for property registration and local offset calculation class FloatProperty(val localOffset) { inline operator fun getValue(thisRef: Struct, KProperty<*,*>): Float { thisRef.buffer.getFloat(thisRef.byteOffset+localOffset) } } class MyStruct: Struct { // .. missing magic here val myFloat by FloatProperty() val mySecondFloat by FloatProperty() } This will result a flat Layout for a MyStruct instance. This can be used directly by native APIs. So what I'm interested in is, how well does this perform compared to Vanilla Java approach? How much overhead is there for all those methods and delegate instances? I tested several different implementations that differ in convenience for the user and overall performance. One surprise for me was, that none of my implementations (neither ByteBuffer nor Unsafe backed) is as fast as vanilla Java. There are some benchmarks on the internet that tell a different story, for example this one. I can't really tell you how it was achieved. Just that I wasn't able to achieve similar results.



Benchmark                                                       
Mode  Cnt      Score     Error  Units
iterAndMutBufferDirect                                         
thrpt   12  90626,796 ± 303,407  ops/s
iterAndMutKotlinDelegatedPropertySlidingWindowBuffer           
thrpt   12  23695,594 ±  82,291  ops/s
iterAndMutKotlinDelegatedPropertyUnsafeSimpleSlidingWindowBuffer
thrpt   12  27906,315 ±  52,382  ops/s
iterAndMutKotlinDelegatedPropertyUnsafeSlidingWindowBuffer     
thrpt   12  25736,322 ± 904,017  ops/s
iterAndMutKotlinSimpleSlidingWindowBuffer                       
thrpt   12  27416,212 ± 959,016  ops/s
iterAndMutResizableStruct                                       
thrpt   12  10204,870 ± 189,237  ops/s
iterAndMutSimpleSlidingWindowBuffer                             
thrpt   12  27627,217 ± 122,119  ops/s
iterAndMutStructArray                                           
thrpt   12  12714,642 ±  51,275  ops/s
iterAndMutStructArrayIndexed                                   
thrpt   12  11110,882 ±  26,910  ops/s
iterAndMutVanilla                                               
thrpt   12  27111,335 ± 661,822  ops/s
iterStruct                                                     
thrpt   12  13240,723 ±  40,612  ops/s
iterVanilla                                                     
thrpt   12  21452,188 ±  46,380  ops/s


All benchmarks iterate over a collection of 5000 Vector3f instances. iterAndMutVanilla is just a regular ArrayList iteration with forEach, setting the three components of each vector. iterAndMutStruct is my current implementation of a tight StructArray of Vector3fs with a sliding window iteration.

Vanilla Java iteration with mutation yields the baseline results with 27k operations. It's very intersting, that a non-abstracted simple version with a direct bytebuffer is three times as fast as the baseline, reaching 90k operations. Simple non-abstracted implementations with Kotlin's delegates brings us down to the baseline performance again. My struct abstraction in the current implementation with a struct array class implementation can only reach 50% of the baseline - quite a difference between the simple delegate approach and only a rough sixth of the simple direct bytebuffer approache's performance.

I have to figure out why my abstractions degrade performance by such amounts - the generated bytecode looks pretty similar for all the versions. At the time of writing, Kotlin's inline classes are not stable enough for delegate usage, so delegates cause some class overhead here.

But even though there are some performance differences in this very micro benchmark, it doesn't necessarily mean that other use cases show such dramatic differences as well. Additionally, the largest benefit my struct-alike implementation offers is, that now large and complex datastructures can be memcopied like this:


class MyStruct: Struct { // .. missing magic here val myFloat by FloatProperty() val mySecondFloat by FloatProperty() } val source = MyStruct().apply { myFloat = 5 } val target = MyStruct() source.copyTo(target) // Simple extension method that copies a bytebuffer println(target.myFloat) // prints 5

This means no iteration over nested arrays, complex copy constructors and even more complex nested invocation of them. Super handy for renderstate constructs in game engines - your whole renderstate instance can be mapped to a OpenGL struct and mapped as a shader storage buffer :)

Dienstag, 27. März 2018

Programmatically compile Kotlin code

Here's a small braindump again, because I don't want to forget how I managed to compile Kotlin files programmatically. There are some very small discussions online, for example this one, but I find existing usages too complex and there are too many things that didn't work for me at the first few tries.

So there's a very convenient artifact that seem to contain everything one needs in order to call a Kotlin compiler from within code and that's published for every Kotlin release. Use it with


    compile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler-embeddable', version: "$kotlin_version"

The following snippet instantiates a compiler, passes a file and some other properties to it and executes compilation. The resulting class file can be found in the given output directory.


val output = File("/home/myuser/out")

K2JVMCompiler().run {
    val args = K2JVMCompilerArguments().apply {
        freeArgs = listOf(File("/home/myuser/KotlinFile.kt").absolutePath)
        loadBuiltInsFromDependencies = true
        destination = output.absolutePath
        classpath = System.getProperty("java.class.path")
                .split(System.getProperty("path.separator"))
                .filter {
                    File(it).exists() &amp;&amp; File(it).canRead()
                }.joinToString(":")
        noStdlib = true
        noReflect = true
        skipRuntimeVersionCheck = true
        reportPerf = true
    }
//        output.deleteOnExit()
    execImpl(
            PrintingMessageCollector(
                    System.out,
                    MessageRenderer.WITHOUT_PATHS, true),
            Services.EMPTY,
            args)
}

The usage depends on the project where it is used, for example it coult be necessary to add a different classpath or add the classpath and a stdlib or something else.

EDIT: I'm sure I found this snippet, or a similar one in the internet, but I can't find it anymore. If you found it, let me know and I will link it as source.

Dienstag, 13. Februar 2018

Koin vs Vanilla Kotlin

Here we go again: I'm searching for a performant, convenient solution for dependency injection in Kotlin. Koin got my attention, because it seems to be simple and straightforward. Since it uses a lot of small inline functions and seems to have only a few hotspots where performance suckers could lurk, it seemed very promising. But I wouldn't want to use it in my game engine project until I can be sure that the performance impact would be negligible. So I did a ... probably totally flawed microbenchmark, that doesn't show anything, but I want to dump it here nonetheless.

So we have a simple service class and another service class that depends on the first service. The main module depends on the seconds service, so the chain has to be fulfilled.


class MainModuleKoin : Module() {
    override fun context(): Context = applicationContext {
        provide { ServiceA() }
        provide { ServiceB(get()) }
    }
}
class MainModuleVanilla(val serviceA: ServiceA, val serviceB: ServiceB)

class MainComponentKoin : KoinComponent {
    val bla by inject<ServiceB>()
}
class MainComponentVanilla(val bla: ServiceB)

class ServiceA
class ServiceB(val serviceA: ServiceA) {
}  

Using Koin, one can simply write a few lines and everything is wired together automatically. Note that the Koin context has to be started and stopped, which has to be excluded from the benchmark later.


@JvmStatic fun benchmarkKoin(): ServiceB {
    return MainComponentKoin().bla
}

@JvmStatic fun stopKoin() {
    closeKoin()
}

@JvmStatic fun startKoin() {
    startKoin(listOf(MainModuleKoin()))
}

@JvmStatic fun benchmarkVanilla(): ServiceB {
    return MainComponentVanilla(ServiceB(ServiceA())).bla
}

The benchmark is executed as follows, to ensure all object creation happens and context creation is done outside of the benchmarked code:

@State(Scope.Thread)
public static class MyState {

    @Setup(Level.Trial)
    public void doSetup() {
        KoinBenchmarkRunner.startKoin();
    }

    @TearDown(Level.Trial)
    public void doTearDown() {
        KoinBenchmarkRunner.stopKoin();
    }

}
@Benchmark
public void benchmarkKoin(Blackhole hole, MyState state) {
    hole.consume(KoinBenchmarkRunner.benchmarkKoin());
    hole.consume(state);
}
@Benchmark
public void benchmarkVanilla(Blackhole hole, MyState state) {
    hole.consume(KoinBenchmarkRunner.benchmarkVanilla());
    hole.consume(state);
}

 The result is somehow sobering

Benchmark                          Mode  Cnt          Score         Error  Units
BenchmarkRunner.benchmarkKoin     thrpt  200    1425585.082 ±   31179.345  ops/s
BenchmarkRunner.benchmarkVanilla  thrpt  200  106484919.110 ± 1121927.712  ops/s   

Even though I'm aware that this is an artificial benchmark that may be flawed, it's pretty much clear that using Koin will have a huge impact on performance, that could make program infrastrucutre slower by a factor of 100. Of course, we're talking about dependency injection at object creation time, which should be a rare case in a game engine. Nonetheless, not too good from my sight.

Mittwoch, 7. Februar 2018

Kotlin's scoped extensions micro-benchmarked

My last post was about an approach to use Kotlin's scoped extension methods to implement an application with data oriented design paradigm. Yes, I'm still coding that game engine, that's why I had to do a simple benchmark, just to get a feeling how performance could get better or worse. See it as a brain dump. Very unprofessional benchmark with the println statement, but I wanted to get the relation between the simple baseline implementation and the extension method version, like this:


import org.openjdk.jmh.annotations.Benchmark

interface Extension<ELEMENT>{
    fun ELEMENT.prettyPrint() { println("Default pretty " + this) }
}

object StringListExtension : Extension<String>

fun <T> someFrameWorkFunction(parameter : T, extensionProvider: Extension<T>) {
    with(extensionProvider) {
        parameter.prettyPrint()
    }
}

@Benchmark
fun extension() {
    someFrameWorkFunction("asd", StringListExtension)
}

fun String.prettyPrint() { println("Default pretty " + this) }

@Benchmark
fun baseline() {
    "asd".prettyPrint()
}

Surprising results again:


Benchmark                            Mode  Cnt       Score       Error  Units
BenchmarkRunner.benchmarkBaseline   thrpt  200  269087.160 ± 17915.393  ops/s
BenchmarkRunner.benchmarkExtension  thrpt  200  329648.131 ± 19646.005  ops/s

Once again, the opposite of my expectations.

Two-phase occlusion culling (part 2) - instance aware culling

I described the basics about the two-phase occlusion culling technique in the first part post, but there is one thing, that doesn't work well with this simple setup: Instancing or sometimes viewed as batching.


The problem is very simple, the solution however is not. Only a few engines managed to implement the technique, but it is unavoidable if one needs to render large batches or large amounts of instances. Quick recap, under the assumption that we compromise flexibility in favor of speed and use OpenGL 4.5 level graphics APIs:

Avoid buffer changes one, two different vertex layouts (for example for static and animated meshed)

Avoid program changes well defined firstpass program (deferred rendering) or subroutines in a global attribute buffer

Minimize drawcalls Usage of instanced and indirect rendering


The usage of draw commands and indirect rendering is nice enough. The amount of drawcommands is reduced by using instanced rendering for entities that have different uniform attributes but the same vertices and indices. This results in the command and entitiy buffers of the following form:


Entities
uint entityId 678
mat4 transform 000...
uint materialIndex 18
uint entityId 1566
mat4 transform 000...
uint materialIndex 2

Commands
vertexOffset 0
indexOffset 0
indexCount 99
instanceCount 2
vertexOffset 1200
indexOffset 99
indexCount 33
instanceCount 3

Firing indirect rendering call is now done with a count of two, because we have two commands. 5 objects will be drawn. The shaders are invoked several times and the entity data can be accessed with an index and fetched from the entities buffer. The resulting indices in the shader will look like

Shader Invocations
DrawId InstanceId Entity buffer index
0 0 0
0 1 1
1 0 ???
1 1 ???
1 2 ???

As mentioned in the previous blog post, there's no chance for us to know the entity index when the second command is executed, because the current offset is based on the amount of instances the previous commands draw. The solution is to use an additional offset buffer with size of the draw command buffer. For every command, we set the offset to the appropriate value when creating the commands on the cpu side. With instance based culling, this problem intensifies, because the cpu doesn't know the offset anymore. The calculation has to be done on the GPU now. My solution is still based on vertex shader kernels, but I will tell you later why this is probably problematic. First how it is done, because conceptionally, it will be the same for compute shaders. The layout now looks like this:

Shader Invocations
DrawId InstanceId Entity buffer index (command offset + InstanceId) Offset of the command
0 0 0 0
0 1 1 0
1 0 2 2
1 1 3 2
1 2 4 2


The first step is to determine the visibility for every single instance. Vertex shader kernels have an advantage here, because they can be arbitrarily large (compute shader groups are limited to 1024 or so). A single draw call can determine visibility for dozens of thousands of instances or entities. Combined with instancing, we can use DrawId and InstanceId to index into the command buffer and offset buffer (DrawId) and into the entity buffer (offset + InstanceId). Since the same kernel sizes are applied to every command, invocations are wasted if few commands have many more instances as others. So you might want to launch draw calls without instancing, one per command, which could be faster here.
The visibility is again stored into the visibility buffer, which has to be as large as the entity buffer now. With non-instanced culling, size of the command buffer was sufficient. One important thing has to be done now: Every visible entity thread has to increase a counter that is associated with the corresponding command - since this is done per invocation, atomic operations are needed. So we need another int buffer (just like the offset buffer), that holds the visible instances count per command.

The reason why this is so important is, that this is the bit of information that is used in a second step to append entity data and draw commands in parallel. This is done by an algorithm similar/equal to parallel prefix sum - you can google it. Tldr: Each command has to know how many visible instances all previous commands produce in total, so that it can append its own instances there.

I call the seconds step appending step, while the first one is the visibility computation step, that actually calculates the visibility of an instance. For a massive amount of instanced commands, one would probably want to launch a two-dimensional kernel of the size n*m where n is the amount of commands and m is max(maxInstanceCount, someArbitraryValue) or something. Again, with vastly different instanceCounts per command, multiple shader calls could give a benefit.

So now we need a target buffer that holds the entity data, a target buffer for the commands and a target buffer for the entity data offsets. Additionally, we need an atomic counter for the target command index and then an atomic counter per command, that is the current index of the entities per command. Each shader invocation has its own command index in the DrawID built-in and the instance index in the InstanceID  built-in. So we can calculate all information that is needed on the fly:

struct oldCommand = read from the bound command buffer with DrawID
uint  oldCommandEntityOffset = read from the oldOffsetBuffer with DrawID
uint oldEntityIndex = oldCommandEntityOffset + InstanceID
uint visibilityBufferIndex = oldEntityIndex
uint targetCommandIndex = atomicAdd(commandConuter, 1)
uint targetInstanceIndex = atomicAdd(commandCounters[targetCommandIndex], 1)
uint targetEntityIndex =  sumOfVisibleInstancesOfAllCommandsBeforeCurrentCommand

The current entity data can then be written to the targetEntityDataBuffer, as well as the offset for the instance/command. The command can be written by the first active thread (InstanceID == 0). The resulting buffers contain only the visible instances, offsets of the visible instances and drawcommands that can be used to only draw exactly those instances.

 Here's a video demonstrating occlusion and frustum culling with this technique:



Bonus: For the visibility computation step, it's nice to launch a vertex shader kernel, since the kernel can be arbitrarily large in two dimensions at max. Since there's no shared memory involved, this will probably perform better than the compute shader equivalent, maybe at the same speed, but it shouldn't be slower. The appending step needs an atomic operation per invocation, because every invocation increments the counter if the corresponding instance is visible (which the other invocations couldn't know). Instead of "global" shared memory, one could use shared memory of a compute shader group. Shared memory in a group is much faster than atomic operations between a gazillion vertex shader invocations, so I will implement this at some time and may be able to show a performance comparison.