Xenko Game Engine 2.0 released(xenko.com) |
Xenko Game Engine 2.0 released(xenko.com) |
The growing adoption of C# among game engines, brings me back memories of when game engines finally started to allow C++ on their source code.
Switching from C/C++ to a GC language is nothing like switching from Assembler to C/C++. We did not write Assembler because we liked it. We wrote it because we targeted 8/16-bit archs, which did not fit C/C++ memory model quite well. Because of this Assembler had huge speed and size advantage. As soon as flat memory archs became viable almost everybody dropped Assembler without regret. We lost a bit of performance (which could have been easily regained by rewriting inner loops in Assembler) in exchange of reusable, portable code, type system and terse program texts. These allowed to write much more complex games by engaging bigger teams who could sensibly collaborate over a much bigger project in C/C++.
What is the transition to GC from C++? You sacrifice a lot of performance for freedom from managing memory. I don't know about other people but having shipped few AAA games my only concern was fitting shit into available memory (which GC does not help, to say the least). You allocate memory on load. If you load multiple levels you nuke the previous level's memory. If you stream you do the same but your "levels" are now "segments" in a pool. Of course, if you want to go full-GC and allocate your structures byte by byte, uint32_t by uint32_t - be my guest, not sure how you plan to compete but, hey, load times (same as frame rate) are not that important as they say on the internet :) Nevertheless, as soon as 32-bit targets become completely obsolete people will find out that you can pre-allocate everything off-line in 64-bit so all you will have to do at run-time is map/unmap pages (which GC won't help either). In conclusion: one dropped performance on the floor (due to cache issues, SIMD issues, off-line vs JIT quality issues etc) and picked up the solution to the problem one should not have had in the first place.
Same goes for memory: textures and other assets are managed through the engine; C# only contains game logic data and handles to the assets.
At the time I had many issues with the GC, Large Object Heap and fragmentation (although this had still been in a much older .NET version).
For a game project, both for speed and memory, you want as much as possible to be pre-allocated (and all at once). During run-time you want as few objects as possible being instantiated, that way you save cycles on both the objects, and eventually on the GC. Of course it's not always that easy.
After that it depends on your targets, you'll never fit a Unity C# game as tightly into any target as a native app, but it's a trade-off that's worth making in many cases.
Switching from Assembly into C, Pascal, Modula-2, QuickBasic was mostly an amateur thing until SDKs started to be based on C.
Same with C++, we were the outliers until console vendors started pushing C++ into devs. See Mike Acton's talks about about how he enjoyed having been forced to move from C into C++.
The thing with GC is not the freedom to manage memory, you still need to take care about how memory is managed. What one gets is type safety and an uniform way to manage memory across libraries.
You know exactly who is responsible for releasing it, there are no double deallocations, releasing invalid addresses, or having to deal with library specific smart pointers (CPtr, QSmartPtr, unique_ptr, my_in-house_ptr, ...).
> due to cache issues, SIMD issues, off-line vs JIT quality issues etc
Having a GC doesn't preclude lack of support for cache handling or SIMD.
Many GC based languages have such support and actually C# 7 with Microsoft's toolchain (not Unity's one) does offer such features, even if they can still be improved.
As for JIT quality, it is no different from any other compiler, otherwise as I referred, why not discuss C performance using MS-DOS compiler's benchmarks.
By the same metrics, we should evaluate performance of C and C++ code by using benchmarks with MS-DOS C and C++ compilers, which should be about the same age.
Don't mix languages with implementation when talking about performance.
1. Jai is not even released.
2. Jai is a programming language, not a game engine.
Unity is slow because they are using an outdated C# implementation (some old Mono).
Is there a way of running C# with reference counting?
So many of the problems you run into making a game on Unity, Unreal, etc come down to the out-of-the-ordinary requirements of your game and the inevitable peculiarities of the engine itself. Part of becoming an "expert" in building games on a third party engine is knowing where the pain points lie, where you should absolutely not fight The Way It's Done, and what bugs remain unfixed for years on end (Unity asset bundle system, looking at you).
Edit: My point being that unless you know the needs of your particular game and have familiarity with a candidate engine, it will be very difficult to determine if your choice is "best" or not.
Unity is the most known and jobs and markets have sprung up around it as well as a massive asset store now exists, it also has many integrations such as apis and tools that take years to acquire.
Unreal and Epic have Tencent money and are on the way.
The OSS side of this engine is pretty interesting. Will be fun to have another competitor in this area. Xenko looks like a direct Unity competitor even down the the pricing and tiers. The big challenge is the community, asset stores and launched titles under the engine. Branding is important as well, to me Shiva and Xenko are forgettable brands, Unity and Unreal are set in minds.
are they stopping with development?
Edit: Oh, nevermind - on the home page they explicitly say that they're open source.
The old version (which is on github) is GPLv3 apparently.
Unreal may not be open source, but having source access at all license levels continues to be incredibly attractive.
> Next-Level C# Game Engine
> Xenko is an open-source C# game engine designed for the future of gaming. It comes with a full toolchain and is especially well suited to create realistic games but allows you much more!
The Economist is a good example here. In every article, every time a new name or topic is introduced, it will provide a few words describing the person/thing. An example taken from the first sentence of the first article I opened: "Much of the language used by Mike Pence, America’s vice-president, [...]"
Writers for "progress announcements" blogs like this one, don't tend to write in this style, because these writers know that the only interest anyone would have in a such a blog is if they already knew what the subject was and then wanted to subscribe for updates.
Which is to say, deep-linking to a progress-announcement blog from another website is basically almost always entirely useless, and the webmasters of such blogs would actually do well to disable it entirely (e.g. with a robots.txt policy + a server-side hotlink-detection redirection rule) and just suggest that people interested in sharing the announcement, should instead write a few lines of "actual journalism" on their own blog about the release, and then share that.
People who like linking directly to primary sources would hate this, but sometimes primary sources are not in the easily-consumed essay or encyclopedia-article styles that much of the modern web has become. Sometimes a primary source is just a commit log, or a diary, where you need to "go back" to get any context. The primary source gets to do what it likes; it's not beholden to the Internet. If someone wants a good summary to share, they're beholden to write one.
> Also, it would mean I didn't have to use OOP to write games.
There are many instances where other programming paradigms are more usable - but in my experience, gameplay logic, specifically, maps very well onto classic OOP concepts.
Since C# is a multiparadigm language with strong functional as well as OO fundamentals, I suspect it will make it possible for libraries and frameworks to be built which enable allocation free code in C# gameloops. It's not just game engines which have these requirements - the same functionality is also critical for high performance servers, and machine learning applications, so this is a language feature with a lot of demand.
Basically they generate C++ from MSIL as a means to generate native code, instead of building their own compiler backend.
They plan however, to eventually update their Mono runtime.
https://forum.unity3d.com/threads/future-plans-for-the-mono-...
Regardless of their GC implementation, in games you don't want opaque runtime behaviour, which a GC always introduces. This leads to weird workarounds in your code that nobody understands instead of having clear and explicit memory management.
Naive implementations are slower than tracing GC, while high performance ones are as complex as tracing GC ones, while having the burden of forcing the developers to explicitly deal with cycles.
I bet there are plenty of game developers who would be only too glad to arrange their references as a DAG, if they could have guaranteed low latency.
If you want the goodies on Windows you need C++, if you want the goodies on iOS and OS X you needed Objective-C and now Swift as well, the goodies on Android require Java, the goodies on consoles moved from C to C++.
Same here, if tomorrow one of those companies decides their SDK should be Language X, anyone that wants a piece of the pie will learn Language X.
As for smart pointers in C++: they are only useful in a code architecture that essentially emulates C# or Java (all objects as single entities on the heap) using C or C++ in such a "memory-managed style" really doesn't make much sense since it will be slower then a GC. The point about manual memory management is to reduce dynamic allocations as much as possible and have all your data either on the stack or in long-lived, big memory chunks. If you need to allocate and deallocate all the time, or track the ownership and lifetime for every little memory chunk, you're not using C/C++ to its advantage.
PS: C# for tools is great though (not so much because of the language, but because of the standard framework, which is much nicer than the C++ stdlib).
[edit: typos]
And most implementations actually suck at multi-threaded code, to the point there are companies selling better implementations of them.
> The point about manual memory management is to reduce dynamic allocations as much as possible and have all your data either on the stack or in long-lived, big memory chunks.
Also possible in GC enabled languages, grated not available in all of them.
As former C++ dev, I can guarantee you that unless you write 100% of the code yourself, there will be leaks, double frees, delete calls instead of delete[] ones, releasing unallocated memory and totally lack of control of third party leaks.
Integrating third party dependencies into C++ is its real achilles heel, I agree. I only accept dependencies that come with source and either don't allocate dynamic memory at all, or allow full control over allocation by providing custom hooks. I also learned over time that typical C code is usually much easier to integrate than typical C++ code (which very often is an over-engineered template mess).
The way to deal effectively with memory management bugs is to allocate as little as possible. There are good analyzer and runtime tools (for instance the new runtime memory debuggers in Xcode and Visual Studio, the static analyzers, the clang address sanitizer in Xcode etc), these provide a much better view on what's going on under the hood than most managed-language-tools. And those tools make it quite trivial to catch most memory-related bugs. If you're doing hundreds-of-thousands of allocations it becomes much harder though, because than the problems will be lost in all the noise.
It is a valid argument though to use higher-level languages in high-level gameplay code, but this should only do scripting-style stuff, glueing subsystems and game objects together. Up in this area I don't want to care about ownership and lifetimes. It's important to find the balance though where the high-level code should better be moved into a low-level, central system.
The first (major) console C++ SDK library is GNM/GNMX for PS4. Are you saying C++ games has been outliers till 201x? I guess this depends on how you define outliers then. Other than the guy casting his game writing on youtube (Code Hero?) I don't know of any significant titles in C past 2000. I have not seen all the games but I shipped a few myself and have friends working on many more and nobody that I know had been writing pure C. Think of all vtbl-> you'd have to write if you are targeting Windows/Xbox just for the pleasure to name your source file .c instead of .cpp!
>What one gets is type safety
Thanks, we've got this in C++ already.
>You know exactly who is responsible for releasing it, there are no double deallocations, releasing invalid addresses, or having to deal with library specific smart pointers (CPtr, QSmartPtr, unique_ptr, my_in-house_ptr, ...).
Never had been a problem for me. The only game I touched that had smart pointers had them because it used NetImmerse and it got cancelled anyways.
>Having a GC doesn't preclude lack of support for cache handling or SIMD.
I don't know what is cache handling, to be honest, but what I meant is that, since GC moves stuff around memory, it's likely to create cache hazards. And since it probably uses a single pool, you cannot change cache policies on per-entity basis.
>As for JIT quality, it is no different from any other compiler, otherwise as I referred, why not discuss C performance using MS-DOS compiler's benchmarks.
Really? You believe JIT will be on-par with a profile assisted, bruteforcing compiler, which can spend a week optimizing a single function?
C++ became a de-facto standard for games, because console SDKs moved from C to C++, pushed by the companies selling them.
The same companies that are now adopting Unity and have already toyed with the idea of having a C# SDK.
If for the sake of example, PS5 SDK would be C# based, devs that wanted any money from PS5 games would adopt it, regardless of their feelings regarding C++ vs C#.
The major C++ SDK was the DirectX SDK for the Sega Saturn.
> Are you saying C++ games has been outliers till 201x?
Yes, the code was basically C compiled with C++ compiler.
> >What one gets is type safety
> Thanks, we've got this in C++ already.
Not when what most write is actually C compiled with C++ compiler.
> I don't know what is cache handling, to be honest, but what I meant is that, since GC moves stuff around memory
Is the ability to write cache friendly code.
If you don't want the GC to move memory around then don't allocate it via the GC.
Many GC enabled languages also allow for global statics and stack allocation. Even C# has some support here, even if it isn't comparable to what Modula-3 or D allow for.
Also there is also the possibility to just allocate it off GC heap.
> Really? You believe JIT will be on-par with a profile assisted, bruteforcing compiler, which can spend a week optimizing a single function?
No, but JITs can also make use of PGO just like AOT compilers. IBM J9 JIT and .NET RyuJIT have such support.
Also many GC enabled languages, including C# do have AOT compilers to native code code as well, it is not as JIT is the only viable approach.
a) there was no DirectX SDK for Sega Saturn. b) DirectX SDK (including one for Sega Dreamcast) is not C++. It has C++ bindings but is usable from C.
>Yes, the code was basically C compiled with C++ compiler.
You mean if I have taken that code and compiled with C compiler it worked? You realize even the DirectX C++ wrapper is not already C, right? You know classes, overloads, namespaces are not C?
>Not when what most write is actually C compiled with C++ compiler.
Could you explain exactly how this works? The C++ compiler uses ML to recognize that the code is not exactly following Alexandrescu's book and turns off typechecks? I seriously just don't understand what you mean here. I usually take "C compiled with C++ compiler", "C with classes" etc as "not enough GoF patterns for my taste" but you are making some other claim here it seems.
>If you don't want the GC to move memory around then don't allocate it via the GC.
So, why do you want GC in the first place? For types, which somehow disappeared from C++?
>No, but JITs can also make use of PGO just like AOT compilers.
How exactly does it work? The code stops executing for a week, the profiler gets run to under user credentials and then JIT finally decides?
Is this moving the goal posts a little bit? C++ now doesn't necessarily look anything like C++ written 20 years ago. Way back, people were writing C+, or C-with-classes, but that's what C++ was, in that era.
I was in game development looong ago (C++ / assembler, lots of 3D software rendering). What kind of compiler is that ? Could you give some pointers ?
I can assure you that at enterprise level, every time I have to integrate C++ code with our Java or .NET stacks, it looks exactly like C++ written 20 years ago, even if it was actually written last week.
Just because C++ has been vastly improved, doesn't mean everyone using it are adopting the new features, some people rather stay in Python 2 forever.
Last time I optimized code the hard way was using VTune to channel the right operation in the right pipeline.
Broken memories, I didn't bother to search for it (Saturn vs Dreamcast).
> You mean if I have taken that code and compiled with C compiler it worked?
Of course it would, that was one of the design goals of C++.
C90 is mostly a C++98 subset, except for stronger type conversion rules (no implicit void* conversions), precedence order for operator ?: and typedef/struct namespaces.
> You realize even the DirectX C++ wrapper is not already C, right? You know classes, overloads, namespaces are not C?
Yes, but COM is also callable from C by design. Also I have seen many codebases that have restricted C++ code to calling DX APIs, with everything else being compilable by a C compiler as well.
> Could you explain exactly how this works? ...
1 - Rename .c translation units to .cpp, .cxx, .C
2 - Invoke C++ compiler on them
3 - Fix compiler errors related to semantic differences in C subset of C++
4 - Forbid use of any C++ specific feature beyond those required to use the OS SDK.
> So, why do you want GC in the first place? For types, which somehow disappeared from C++?
Productivity.
> How exactly does it work? The code stops executing for a week, the profiler gets run to under user credentials and then JIT finally decides?
PGO data generated by the JIT compiler gets updated after each application execution and is used as input for optimization selection just like in an AOT compiler by a multi-stage compiler.
Feel free to read Android 7 ART source code to learn how about a possible implementation.
I think either I don't understand something you are trying to say or you are confused. C being a subset of C++ (one of design goals) does not imply C++ is a subset of C. C++ code in general cannot be compiled with C compiler without rewriting.
>Yes, but COM is also callable from C by design. Also I have seen many codebases that have restricted C++ code to calling DX APIs, with everything else being compilable by a C compiler as well.
You have blah->Foo(bar); in C++. In C it won't compile by any design. That code has to be rewritten as blah->vtbl->Foo(blah,bar). It is not C code as you claimed. It won't compile with C compiler. It's C++.
>> Could you explain exactly how this works? ... >1 - Rename .c translation units to .cpp, .cxx, .C
I asked how type checking disappears in this process, not how you compile C with C++....
>PGO data generated by the JIT compiler gets updated after each application execution and is used as input for optimization selection just like in an AOT compiler by a multi-stage compiler.
How can a JIT compiler obtain the PGO data in the first place? Is it running under profiler all the time? You realize that you've just refuted your claim about performance not being affected, right?
Should I enumerate all of them to make you happy?
> You have blah->Foo(bar); in C++. In C it won't compile by any design. That code has to be rewritten as blah->vtbl->Foo(blah,bar). It is not C code as you claimed. It won't compile with C compiler. It's C++.
Nothing prevents you to write COM calls in C++ code just like in C, blah->vtbl->Foo(blah,bar). The code won't stop compiling.
> I asked how type checking disappears in this process, not how you compile C with C++....
The whole point was about writing C like code with a C++ compiler.
> How can a JIT compiler obtain the PGO data in the first place? Is it running under profiler all the time? You realize that you've just refuted your claim about performance not being affected, right?
By using a multi-stage JIT compiler with different levels of optimization and making use of multi-cores.
99% of the applications are never able to saturate all cores to the point it matters to the overall performance.
I have always been on the Pascal and C++ side against C since the early 90's on BBS and USENET.
So this type of disbelief against better tooling is not strange to me.
Cry Engine, Unreal (C++ with GC), Unity, MonoGame, with their separation between lower level C++ and higher level languages, and the way those engines are being adopted by Sony, Nintendo, Microsoft, Amazon, Google speak for themselves.
Just like C and Pascal overtook Assembly, C++ overtook C, something else will overtake C++.
Sony and Nintendo do not use these engines, MS might be making the new Gears with UE though, rest of their first party don't. Amazon and Google have one successful game between themselves (and that's a mobile game). All these engines bring to the industry are indies and mobile games. UE actually lost quite a lot of AAA they had in UE3 times. Epic's and Crytec's own games don't do quite well (Crytec is not even making payroll). So yeah, looks like C++ games do not have much to worry about.
Use the platform C++ compiler, but write code only the language subset common to C, that could even be compiled by a plain C90 compiler.
The only exception being, wrapping C++ SDK APIs into C like wrappers.
A pattern I have seen too often.
Dismissing indies is the wrong attitude, they were the first ones to adopt C and Pascal, C++, Objective-C and nowadays C#, Swift, Java.
Sony does use C# a lot on their internal tools.
Nintendo uses Unity for prototyping.
Microsoft and Google are using Unity and Unreal a lot for their VR work.
All of them invited MonoGame developers and supported them porting MonoGame into their platforms (PS4, Switch, UWP Xbox).
C++ might not go away, people still write games in C and Assembly, but it will become that very thin bottom layer at the engine architecture diagram.
Just give it time, eventually even all major C compilers became written in C++.
And I have not seen ever. I have seen some C games (like Quake) but never worked on one. And I've been working in games since 90s.
>Sony does use C# a lot on their internal tools.
And now we are in the theretory of "console games are written on PC!!!1! So there!". Sony also uses Perl and Python on their servers and their movie studios use a lazy evaluated shader language. Does it mean games are switching to any of these soon to you?
>Nintendo uses Unity for prototyping.
And probably play Pokemon Go, also written in Unity! I see the pattern now... it's all clear.
>Microsoft and Google are using Unity and Unreal a lot for their VR work.
Listen. Unity has it's uses. If anything it keeps indies off the streets and provides artists with a way to earn a quick buck. I am not against Unity. It's just silly to imagine it has any chance competing with the traditional game industry tools. Saying so and so uses unity for something, which is not a game does not make the point I imagined you arguing here. Which is C# displacing C++ in games. Elon Musk likely uses Unity so there. Can't beat the old Musk.
But it still does not matter anything at all for the people who had been writing games in C++.