CppCon 2016: Jason Jurecka “Game engine using STD C++ 11"

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Thanks for sharing!

👍︎︎ 2 👤︎︎ u/csp256 📅︎︎ Nov 14 2016 🗫︎ replies
Captions
so thank you all for coming just to go to get a quick sampling how many of you are actually at game studios now and working in game studios or at in games in some way okay I have a good number and the rest of you I assume are doing really awesome business software all right all right well believe it or not games use business software so thank you so first hello welcome this is disclaimer this project is not indicative of any particular project at Blizzard and I'm not representing blizzard blizzards code in any way this is a project I did on my own but just because it says Blizzard doesn't mean that it's something that we're doing internally yes okay so the first question of the day goes to gentleman over here who asked for whether or not this is indicative of some of the philosophies of Blizzard and whether or not we are using these techniques for the games I'm going to tell you that probably not but this what this is is kind of a case cut case study in that there's a lot of new features that came in with C++ 11 and some of you may groan like oh we got C++ 14 already well some of those things aren't necessarily in some of the compilers that we're using and we're using a lot of different machines and things like that so we have to use kind of the common date common set so C plus 11 is one of the things that is new in that a lot of the stuff was based upon C++ 98 so with that new feature set what are some things that we've had to do on the game side on our own that we can now kind of leverage some of those C++ 11 things so about me I've been 12 plus year veteran I actually ran into a guy that was younger than me and played one of my games that I made so I'm feel really old I have 10 or so titles that I've worked on and contributed to and I haven't really gotten the chance to really specialize in one particular thing a lot of people have specialized in either graphics or networking or AI or something like that I basically was a Swiss Army knife they threw it to code and said fix it so I've had to do a lot of different things I've done AI I've done rendering I've done physics and I've done resource systems and things like that so I kind of got a little bit of a little sampling of all things but not super deep on one so the project mentality or the idea this project is the idea of the presentation is we are going to go through these things which will highlight the idea of what is a game engine some of the C++ 11 things that can help us some of the standard things that are the present that we can leverage today as well as some things that would be nice to have and a couple of those are currently in this process of getting submitted to the standard but they're kind of neat things that as a game engine person we use a lot of then we'll have questions and if there's time we have some bonus material and a nifty bug that I fixed all right so number one what's the project mentality here I wanted to leverage mass concurrency based off of a lot of the talks that I've seen and kind of the feeling of everybody loves the cloud and cloud architectures are potentially infinitely scalable so leveraging that is a good win one of the leverage the standard over any of my own stuff so I did not try and pull anyone else's implementation of anything I didn't try and use any third-party libraries and I tried to stay away from making my own versions of things keep it simple stay away from the C style patterns that have kind of been leveraged in games don't really focus on graphics because there's always someone that's specialized and it's going to tell you that you did it slow and with the idea of here is that I'm going to be trying to do the magic 60 frames per second which is 16 milliseconds per frame of work and then this is a really good tool for me to learn the new standard features as well as get me involved in kind of where C+ is going so what is a game engine game engines interface with hardware ap is such as the graphics system sound network and input and various other things but essentially that's whose purpose we also have things like data creation and data loading will also do data interpretation and data presentation so that's the graphics fancy layer so this is why does the game engine not use the standard well typically a lot of the game engines were started went during the low period as explained in garnish talk of C++ 98 and there were some features that weren't as fleshed out or use memory as effectively as we wanted how many of you here saw Chandler's talk this morning okay not enough of you saw that everyone go get the YouTube video see it that is what game companies do with their kind of underlying architectures for how they use memory how they want to use arrays of things and stuff like that so it was really cool to see that and it's really neat to see that he does a really good job of presenting it so that is a really good talk to go watch the containers is one of the foe paws of games usually and if you go watch Chandler's talk you'll see some of the things that he's done within the compiler to show the power that you can get from not necessarily using some by using the containers in a different way see string is one of those things that has kind of been looked at as a horrible thing and it has its uses but comparing strings and things like that and games is kind of slow so we don't really use that at all so that there's been a lot of kind of built up I guess grief against the standard because of some of these things they're not necessarily fully founded but some of them are just based upon implementations that the standard did so right now there is actually a proposal for a flat container which is more like a game usage structure that is being done by Sean and Sean middle middle britain Middleditch and a few other people and as a way to get some of the more game friendly things as part of the standard there's also the thing of the templates generating a whole bunch of code size the video that's linked here that you know the slides will be available for everyone so look at it later but it goes into how to remove some of the extra bloat that the templates would create typically it's just specializing your classes for your particular use instead of being super generic we also have this assertion mentality that are our exceptions are not wanted so in our system a lot of the game companies just turn them off on their compiler completely we don't really try and handle them at all maybe we have a high level one at the very top of our game loop or at the very top of our main loop but we don't really do anything with them this limits us in that we can't really use third-party code typically because the third-party code uses exceptions some third-party libraries use exceptions as control flow which is worse so please don't do that and we also have immense teams of QA that we hire that is supposed to catch a lot of the common things we also nowadays we leverage a lot of the patching which is widely available for all kind of consoles withstanding the GBA which doesn't really have that but in general we take the mentality of look if the game crashes it's unfortunate for our fans and our in our people that paid us and we are going to try do everything we can to limit their pain but at the end of the day it's not a moon rover we can patch it and if it's like 1% of 1% of our users I'm sorry the cost of actually the exception unrolling and things like that was gone into really great with that website if you have a chance go take a look at it it's really helpful now there are two proposals or three proposals now going through the the standardization process that are about creating lightweight exceptions so then that would give us the ability to use these third-party libraries that do throw exceptions in a more lightweight manner which is very interesting so we're looking we're looking at that what else do we do well not all games are created equal there are different concerns for different games so there are guys here from a creative assembly and they do total war total war has several thousand units on the screen at once that's a different concern than a game like overwatch which my company makes where you're right up next to the character so you don't necessarily need a super detailed eyeball map on total war but since you're right up next to character on the for FPS you might so there are different concerns there are different trade-offs the same with open world versus level based game you can get a game like inside that's a very level based game and so you have a very curated view of everything and so detail can be added there in a curated way which allows for some graphical optimizations that an open-world game doesn't allow you because the game can be looked at from any angle anyway and probably someone's underneath the terrain looking at it too there also have platform restrictions so until recently xbox and ps3 kind of had their own world that they lived in with the 360 it became more of a windows type architecture but ps3 had its own craziness with its cell processor and they're there their processing units that were split off to the side the SPU's PC and Mac have had similar type things when Mac I remember when Mac had a different processor than it does now but now they kind of share a same processor the Intel x86 architecture which is great for us which means that we can now assume some things and leverage some of that technology the problem we also have is the PC has a lot of variants and hardware you know some people go out and buy new rigs for games they have very advanced graphics capability but other people still are playing on Windows XP and so we're supporting those people too which makes it very difficult for you to kind of force someone to have the greatest and latest feature in the game or graphics technique and then still support the people that are running XP mobile devices as well or more kind of a curated architecture where you have limited space that you can do things in as well as some of the language features so on is there are certain things that you have to do through Objective C or you have to create interfaces from Objective C to your code and for Android it's a it's the java version where you have to do java and then into your code and then we have the web so there's some guys here for more gaming or new y'all in here so they have a really cool embedded 3d hardware-accelerated thing in the web browser it's not flash and depending on when they updated it that might be leveraging other technology than html5 but there are concerns there that you would trade off you wouldn't do the same thing that you would do in other things alright so how does C++ 11 help us well if you remember the things that we had to deal with our data creation and loading part we can leverage this context per thing I know that this sounds kind of like a weird weird keyword and at first it was weird to me but after looking at a while as it then you know what we have a problem in games so some coder implements something for our resourcing system and he says oh it's reliant upon this particular version version one so then another coder comes in and he says oh actually we need this other data and he adds this data or maybe he just moved some of the data around and then he doesn't increment the version at that point he checks it in everything goes to the asset people and they're starting to do stuff and they're like hey my game doesn't work well at that point you have a version problem so typically when you track that down you have to tell everybody hey get this old build or you have to yell at the guy and tell them to fix it and then smack it tell them don't do that again so with context birth since a compile time you can actually perform some operations on your code and generate a unique resource ID for all of your resource data structures for serialization and deserialization you can also use static assert which is new in c++ 11 for compiled time checks which is great you can make sure things are of the size that you want you can make sure that things are of the types that you want it's it's great leveraged items so let's go through with versioning the structure the structure is a very simple structure it's essentially just a spawn point as position and a direction and we have a small structure that's our vector leveraging a new technique which is initialization at declaration within a class which is very useful so what are some of the things that we would do to hash this this is where you yell at me all the cool stuff alright so first what we'll do is we'll say hey the name of the structure has got to be unique because you can't have two classes saying the same thing you'll get like duplicate declarations and it'll get weird alright so we can do that and then oh well yeah the data member types those are unique potentially if someone changes it yeah they'll change but you want to know that that's a new version so then you go okay well the data member names because we have a position in a direction what happens if someone changes that direction to a quaternion instead of just a vector3 that's that's something that's good for that or if we add a new position we have data member order because what happens if someone swaps those they say hey the direction is actually above the position for whatever reason and we have one final thing which is data alignment so this one I don't go deep into but we can do things and we do things with data compacting to get our structures small as small as possible so when we're serializing them in and out it goes really fast off the disk they're off the RAM so we can get them into the game as fast as possible all right so here's the code wall what's doing so at the very top you see I have that using keyword which is kind of nice that's a new feature as well that one doesn't really impact a whole lot of things except it gives us some some things that we can reason about stuff I also have this structure there that I'm calling context per string and that is just something that I'm leveraging so then that I can pass in to my concept for functions and know what the size of the string is because it takes in a conch string all right then my first function there is a string hasher it basically goes through my contacts per string structure iterates through all of the the items that are in there and then calculates a hash well I have some things where I have a raise of these contacts per strings and that's the sex in second function which goes through and calls the concept bra array function and goes through for each one of the contacts for string structures and then hashes that and then told us it all together now this is pretty cool because it generates a unique hash based on any of the structure layouts that you have your data layout so I didn't do a super-advanced one but I have a co-worker that was excited by the possibilities of contacts bura and he implemented sha-1 as well as md5 hashing in context bura so that that is amazing to me it's got the sha-1 code token is a little bit bigger than what my hash value is I'm only using a 32 bit int he's using a much larger structure but for my purposes that's got me what I needed so what does that do well I have three or four structures that are essentially a replication of that spawn point but they're all different in some way and they all generate a different hash code based on the code that we just looked at so this is the magic is I'm using the macros magic which is starting to become fo passe but essentially what I have here is I'm declaring these structures with these macros and then in my compilation I make passes on every one of these objects multiple times one time I generate the hash another time I generate the actual structural definition either a class or structure and then one time I actually go through and generate a list an inorder list of all of the serialization or deserialize functions which is important when you serializing data in so you unci realize the data in the right order and I'm also using a trick in the in the concepts for trick in there where I am figuring out the offset of the class to each data member so instead of calling syria serializer deserialize on a particular member I'm just telling it like hey go to this offset in the memory and just splat down your information and that works really well and really fast but now I have a compile time changing data of data version check so then all our tooling that if we're doing tooling can then check and see like oh there's a data version change I just regenerate the data hey did the artist now pull the data to pull a version that they don't have you can throw up a warning or you can throw up a an error or you can just have them start exporting it on their machine and it kind of eases that pain of the oh my god we have to search and why didn't this guy change the version number so mastering currency it's not necessarily new to C++ 11 but it is coming in new in that so the standard is now enabling certain things so there is a standard standard thread now which is really usable for that and they have the standard mutex as well as the standard a condition variable and other thing and then there's a Stanek library or stat at standard atomic library which gives you those Atomics which we use to have to implement ourselves using you know things apparently but we had to do it ourselves per platform and we also had to do things if we were doing Xbox or ps4 or Playstation you had to do their specific implementations but now it's in the standard so then that everyone can kind of play nice so for this quick benefits I'm sure that everyone would see that is it exploits the multi processors of the machine the cloud-based processing can dynamically scale the task what can be small and simple which allows you to focus optimization on those particular tasks instead of having to kind of look at them everything as a whole you can optimize a single task and get wins they're serialized sequences can be distributed to multiple places it's highly modular so then that you can change different versions of tasks easily so if you have one version and then you change a different version you can then go back to the old version if you want to I'm not saying we do that at runtime but as you're iterating through the code you can make those changes and it's simple to kind of drop those in efficiency of doing multiple things at once can outweigh the serialization wins of cache coherency sometimes all right so what are the things that we have to worry about well one thing is our tasks need to be as a pendant independent as possible that makes it to where you really can't rely upon other tasks to do your own work and that takes a little bit of thinking about how you're interacting with with your data excuse me as well as data manipulation needs to be thread safe this is the deadlock or live lock situation you need to keep in mind the data set when your data synchronization synchronization happens some people like to synchronize their data every time they change it which then you're basically doing a serialized game and that's not good you need to take an account when you oh you need to take an account that things can happen non deterministic or der so if you're expecting six things to happen in one three four five six that may not happen because different threads may have grabbed it and one thread finishes early and the other one doesn't pick it up yet and is now starting on it so there are some things that you need to remember is that if you kick off a bunch of tasks you can't say like oh well it's going to execute in this specific order your task queue speed is really going to come in to come in to come into play here there's been some great talks about concurrency and task queues and how to do things with mutexes as well as the lock-free method which is so the mutex the mutex method is basically like a stoplight situation coming at a tea that coming out of intersection people stop then tasks go through then that that side stops and then more tasks can go through the other direction the lock-free method tries to eliminate as much of that as possible and so it's more like an on-ramp situation for highways and so then that kind of tasks are kind of just naturally moving in into into their their execution lanes and things like that and there is a concern of thread context switching if you are just executing stuff without kind of taking consideration your thread context you can invalidate your caches and have to go and have cash message all over the place and having to re pull that data from out of the cache into the cache may degra gate your performance game so with that said let's create a simple task system so I have a task system that I wrote for this example and I'm not using a class so typically a lot of the game companies I've been at and a lot of implementations I've seen have been more like a singleton class structure and this is not that the idea there is that what I want to do is I want to hide the implementation of my task queue because everyone else doesn't need to care about what my task queue looks like and if you're including things and you have this header and it includes a class and it references a class without forward deck relation and all that then you have to include what the task queue looks like to everyone else all the other compilation modules so instead of doing that I abstract that use a namespace and that then this is essentially all the interface that I need so this is how we add tasks I essentially have a name spaced static task queue and I push things on to it and for the track tasks I essentially create a wrapper around the tasks and then push that on there and you'll notice a couple things for C++ 11 in that I'm using unique pointer and I'm using future and I'm I'm doing those as a way to allow for the concurrency for the future case so I can get back information on when the task was completed and the unique pointer is allowing for proper shutdown if let's say the game immediately needs to if you if the user says hey I'm exiting the game the game state can immediately delete all the data that it needs to because the unique pointers goes out it goes out of scope and then it can return it back to the memory pool and then you can go back to your main menu something like that so this is to keep all my cleanup possible in case of a crash or things like that it'll kind of clean up the data for me I'm also using the Move semantics to move stuff around unique pointer kind of forces you to do that but this is to highlight that the move semantics are a very valid way of doing stuff and I'm sure that everyone is seeing the move semantics stuff if you haven't then there's more yes right so right now my so the question was about the push that I have there it was like where does that come from that's not a standard name for a function in any of the standard data structures that is true and the reason that is is I have an abstraction that I'm using that is wrapping the standard functions so this is just the simple this is a simple of that interface as I needed for this particular thing essentially we'll go into it more but push essentially pushes one on to my queue and then pop pulls one off the queue so again code-wall great now no one can read it but so I'm using a several things here so I have an atomic bool which tells me whether or not I should run tasks this function is what I give to all my threads I have a thread pool that's using uni that creates a unique pointer for a list of thread pools or a list of threads and then I allocate those by use by asking the computer at runtime hey what is your hardware concurrency level and it'll tell me and then I could basically create one for every core essentially so the work that we need to do is actually right there are tasks we pop one off into a unique pointer we check it to see whether or not we have one because the pop can return nothing which says that there's nothing in the queue then we run it if it completes then we just go through and everything cleans itself up the tasks can have overwritten delete operators that will dump its memory back into a memory pool for game optimizations or it'll just go out of scope and be deleted by default then if we didn't complete then it pushes it back onto the same queue and says hey you need to rerun me so this is essentially our flow and some of you will recognize this and one of you in here will remember it from earlier when he actually said what this is so to eliminate some contention I'm essentially pulling off the front trying to process it and then if I need to I put back onto the back end which is a ring and luckily we have some folks that are sponsoring a a standardization of a ring buffer q something to ring but essentially we can create this loop and we can eliminate some contention things so I'm waiting for that before I actually use it in my thing but this is what I got so far so this is my yes okay so the question is in summary is essentially task specialization on thread specialization this is currently focused on super generic but yes there there can be things set up in your queue to where it knows what type of task it is and it will properly assign it to the correct thread this is a more super simplistic generic setup where you just have a whole bunch of threads and throw at it and then it will do things for the things that deal with GPUs directly this does not go into that because the threads that we are using in the standard don't actually operate on the GPU there is some other work that's being done that's coming into the standard hopefully that is open openmp has a as a GPU kind of implementation as well as c++ amp and there's a couple other research papers based on this so having multi-threaded GPUs is going to be super awesome I can't wait until I can render to one texture over here rendered one texture over here and then do a merge all up raishin before I actually display to the screen that'll be super useful and super fast but at this point it's not in the standard so this was very focused on what's in the standard right now so this is my frame these are the the sub boxes are actually sub parts of my frame each stage of the game or each stage of the frame I have a beginning I have a pre simulation step I have a simulation step I have a pre visualization step and they have a visual Asian step and then I have an an end so where are my synchronization points any guesses so I have after simulation essentially in the pre pre visualization step anyone else yes okay so you're saying tor before the visualization step like at the end of the previous Oh at the end of the frame completely okay so these are my locations where I synchronize and I only synchronize the beginning and the end because I have my stuff set up to where I can run multiple frames at once so I can start one frame start it going and start another frame and it'll tail behind using the state that was kind of stored globally as a way to do two-way to continue and process more more things the previous pre simulation step is actually the main workhorse that's where most of the things get evaluated the pre-visualization step is not as much the the synchronization is that you would think because essentially all it's doing is coming up with the list of things to render and sorting those lists so it's a lot of sorting and things like that which can be compartmentalized and then parallelized so these are the things that allow us to do math parallelization the beginning and ending are very small they're not super big so there isn't really parallelization there the other things are bigger and can fan out to a lot more things if you're processing a lot of AI then you can simulate a lot more AI or you can simulate your physic state in there and things like that so why doesn't videos visualize use that and that's part of the part that I already ruined which is there isn't really any multi-threaded graphics rendering at the moment that's very safe it's very state state centric so you'll say begin render you start doing all your things setting up your render targets and things like that and then publish to that and then you end render and so there isn't really that multi-threaded support at the moment like I said C++ amp and OpenMP have like some GPU implementations that may help with that but right now that's not in a standard yes so the question is about the new API is the graphics API is about Vulcan and DirectX 12 so those are very new and that's the keyword they're new which means that the user base that you have millions of players playing aren't necessarily on the mall yet because we still have to support the guy that's using Windows XP so some of those things are coming and they're going to be available and I believe NVIDIA has some cool tech where they're actually doing the multi rendering thing that I was talking about you know multiple render targets at the same time but that's not in common hands like it you may have someone who has that card and they spend a lot of money on that video card but it's not necessarily in the breadth of people breadth of people's hands so some things like sim D are on their way there's some good papers on that to try and leverage some of the some single instruction with multiple data pieces which is great and visualize fancy features can can be pretty expensive so isolating all that in the pre-visualization step where you sort everything and get everything ready and load all the data and stuff like that can be super paralyzed but then the actual implementation of rendering and all that is very state centric and kind of serialized at the moment so some standard highlights some things that I found that we're in the standard that are pretty cool so move semantics are great I'm sure that everyone loves them the threading library is new it's pretty neat the algorithms library is underused in games we have a lot of those algorithms that we've implemented ourselves based off of the 98 standard which didn't have some of them but now use them you don't have to use the standard containers to actually run the algorithms they run on concurrent or a contiguous memory so you can give it just array and it will iterate through the array because it knows how to step into the next element of the array and so that means that there's a lot of stuff that's opened up right now that we can then use the other thing there the interesting little standard distance thing was something that I found by accident but that thing actually does the pointer math for you on a an array to figure out what index you are which is kind of a neat little feature that I found kind of buried somewhere yes so I haven't tried that so his comment was that you can use the standard distance on a list or a forward list I haven't tried that based on when I was using it in the contiguous array set up it got me what I needed and the things that I were you that I was using were contiguous arrays so I haven't tried it with that I'm sure that it does it's just using the iterator stuff to figure out the distance but I'm sure that the contiguous array is much faster than the running through the list of linked lists okay so basically summarize for the recording and for posterity it's essentially standard distance uses the iterator to figure out what your actual index would be so you can use it with the iterator classes like linked lists and other things like that so other things standard function is a great use of a delegate lambdas or potentially even better with new complex lam are more advanced lambdas and things like that then you can leverage that more static assert I found very useful it allowed me to verify things in my context per context was very useful as example earlier a tuple can be great for dynamic data grouping so if you're doing some AI calculations and you need certain attributes you can isolate those into a tuple and then send that off to a task to be processed by itself in isolation Atomics are great as it allows you to do things that ensure that your your data that you're setting is actually understood by all of the threads because all of the threads get the same data piece standard array is a nice little thing it wraps kind of a regular raw ray and it has all the iterators and things like that unordered map in ordered set are nice they're essentially hash tables they allow you to create your own hash functions which is great so you can hash your data off of specific things that you want instead of just giving it a data piece that it then has to do a comparison on so what can hold something better bigger than itself and ensure proper cleanup so I have a smart pointer over here and you are a smart man so smart pointers are very useful then so I'm using them and leveraging them for data management but not everywhere so my rule of thumb within my project was essentially unique pointers were a way to show how you're supposed to use things and smart pointers as well are uh shared pointers as well but the usages of them were more along the lines of I wanted to actually change ownership of something and I would use an a unique pointer if I wanted to actually really keep a ref count then I would use a shared pointer but I didn't use them everywhere I still have raw pointers everywhere to process data because some things didn't need to know that they were an owner or not an owner they just basically operated on something so there is something in the standard that's called weak pointer which allows you to check whether or not it's been deleted and it kind of creates us kind of a link back to a shared pointer I didn't really leverage that I found that using the weak pointer kind of seemed to me to add a little extra thinking that I didn't want to do because typically if you have a pointer that goes away then you actually want to crash there and so fail early and fail fail correctly by crashing the code in the place where it actually happened yes right so that was something else that was going to mention later but the observer pointer is something that is coming up which will allow you to mark something as not owning and operate on it right now we're just using the raw pointers and as beyond I said last year or somebody said let maybe it was herb gave a talk about that he wasn't trying to get you to replace all of your stuff with smart pointers and you can use the star pointer but you need to use your smart pointers effectively all right so another one I'm in front of you you cannot see me but you may see me later all right so we've got some smart people in here now we've got some future so future is it is a really neat concurrency item that I'm sure that you've had talks about here and better talks about in previous times or even here and so this is very quick I'm using it as a tool to get information from the tasks so I'm sending off a task and then it's filling a future for me and then based on that future result on doing stuff futures are relatively small they are essentially equivalent to two pointers but you do have to be aware that future bool is the same size as future int pointer so take that as you will ah so another code another code block so this is the the pre simulate part and this looks really difficult but essentially what I'm doing is right here I have created a task and I say hey task I care about your results so I'm going to have a future that's in my task that says hey I'm going to watch your results then down here I'm going to say hey every time I run have those results been given to me yet no okay well I'll just won't worry about that for now and then it goes off and does execute other things on that thread and then I have this function which leverages the valid thing that's built into the standard and then a Microsoft only implementation of is ready that may also be on Mac I don't but for right now the Microsoft implantation is not standard but I found that if I just check it for it's valid or not that doesn't mean that the data is ready to be grabbed and valid valid will return you whether or not it has state that's what it does so it doesn't necessarily give you whether or not the value has been set so this is ready it tells you hey a value has been set it is now time for you to get this result all right so what is infinite in size but you never seem to have enough of what was that no so time so this one hasn't gotten a whole lot of love but this this may be the greatest contribution to the standard to games for now this library for for timing is something that will enable people to get resolution on their their timing structures without having to go and jump through all the hoops or know these really fancy techniques so who's in here has implemented the query performance counter who uses time get time who knows all the differences between them there's two of you so you two I'm going to start a company with the rest of you go back to school so those two implementations are used for different things and yet they give you similar type information they give you what's supposed to be time so chrono wraps all that stuff into a simple interface it allows you to be it allows for type checking and it allows you to use different variants of times so they have three different three current timers the steady clock a system clock and then the high resolution clock yes right so the comment is that there's only two clocks and the high-resolution clock is whatever is implemented that is true for Windows right now Windows uses the steady clock as its high-performance clock but the idea is is that you have three options and if the implementer of the code says well actually I have this really this other fast way to do it for the high-resolution clock they can change it so that's why there's three so for here we have this conundrum we have an unsigned int that we're calling timestamp what is it is in milliseconds seconds nanoseconds and if it is an actual timestamp what do you POC is it is it the beginning of time is it UTC is it West Coast Pacific time is it Australian time so there's been a lot of bugs you don't know and then we have another one which is all right time in seconds that's better we know it's seconds but then we can do assignments like that I have a thousand a thousand of what is that that 1,000 milliseconds is a thousand seconds now the standard does have kind of they do allow PostScript things where you can do MS or ass on things to give it kind of a type but that doesn't help you if you don't have a typed typed variable that you're putting in it yes yeah you can have you can have little where you can say 1s and the compiler interprets it is one second so this is some some examples of that so we have here a high resolution clock is what I'm using the very top one is actually my time step for my simulation loop and what I'm doing there is essentially extracting the difference in time from the last time I grabbed it and then making sure that I only do a minimum of 15 milliseconds and that's great I have all these types there I can see what I'm doing and then I can do stuff like the next example which is I have one second and then I can convert those things it can be printed out as one second 100,000 milliseconds or even more even more nanoseconds then I do things like alright so I can add things but it's really cool in that the compiler tells you when you add wrong so the top one is adding 500 milliseconds to a second and it produces milliseconds and then you can see that it actually will display the information that you need then on the bottom one I have a compiler telling me my types don't match because you can't add milliseconds to seconds and have it result in a second so that's very useful that catches bugs that would normally get into the code so some of you may be thinking about the standard and say what about async why aren't you using async well async has a little bit more wild-west nature to it it can spin up its own thread it can run on the same thread and there's a lot less control so for this I wasn't as keen to use async as opposed to my own thread queue and using a thread pool and typically you would use it you would if you're on a xbox or you're on at ps4 you would use a thread pool anyway so I implemented it based on that so these are things that are on the way the file system library was experimental but is now coming in as part of C++ 17 the one caveat with that is that it uses exceptions so games are stuck at the moment until we get the lightweight exceptions in variant which is really really neat we had the we have the ability there to essentially use it as a state machine so you can go and say alright if I'm doing a network library you can say okay what state on my end am i connecting or whatever and you can iterate through this variant to do different implementations that do different different things on a similar on the same data piece which is great so I found out today which maybe I should pay attention more and stop looking down all the time but the atomic smart pointers are actually made it in for C++ 17 which is really cool I'm looking forward to that then we have C++ standard optional which is really cool for dealing with a lot of things that we use Sentinel values for so the brief code example there is we have a bull value that says whether or not something was triggered then we have a unique pointer to say hey this is the result so now that just becomes optional my result and then if it has data then it becomes yeah it was set or it was triggered and then there's other various of refinements there's refinements to the context person context where it allows for more complex functions as opposed to what it is now we also have things to lambda which allows for greater greater flexibility there and there's plenty of other things that would take up more and more time for a talk yes so the implementation I looked at it's not it doesn't take the data type and determine something about the data type what it does is it essentially has a sentinel value built into it so it essentially has a bit or a byte that tells it like yes or no whether or not it's set so it's not actually checking the unique pointer for whether or not it's no lore not well the the construction of that unique pointer initializes it to null already so then you you would once it gets constructed it would be no and then you assign it again and then you'd have data there sure so essentially what you're indicating is that because I used a pointer which was probably a bad example for this you could just check the pointer if it's null or not and that would be your sentinel value so that is true if you're using pointers if you're not using pointers and you're using a data structure or you're waiting on some result that's supposed to be filled into some piece of memory then you would use a sentinel value but this was a simple example with kind of a more common use is that that pointer value so some things that it would be nice to have so a pool structure would be great so you can pre allocate a bunch of things and be able to pull things off of it right now that's as far as I know the standard is kind of a little bit more like hey you know what that's something that you can implement on top of our data structures so they may not necessarily be looking at that a pure keyword I've written a lot of interfaces that are pure virtual and I keep writing virtual function definition equals zero and I get tired of typing virtual so saying pure would be a much quicker in typing there is a proposal out there now for essentially using the the attributes to identify things as pure I haven't read it completely 100% but it's essentially the the crux of the idea is they want a way to specify something as a pure virtual function without having the type virtual equals zero all the time there's a network Lib that's out there it did not get accepted for C++ seventeen hopefully it'll get C++ 20 the idea there is that that library would provide basic interfaces for TCP as well as UDP you wouldn't necessarily use that for some of the game implementations but you can use it for tooling and other types of things that would be helpful and with iteration it may become the de-facto starting point for games some other things so standard thread is neat but it doesn't allow for all the things that you would like so you really can't set the affinity of the thread and you can't set a name for it which is kind of as troubling for debugging the affinity you can set by extracting the heart the you can get out the actual handle to the OS specific object and then perform OS specific operations to set the affinity or set the name but that's still not as standard e as we would like the future is ready as I showed in my example the the valid was kind of not really showing me what I expected I expected it to tell me when the value was set and it was ready to be pulled but it didn't end up that way it basically just told me whether or not the future had some sort of state and so the Israeli thing has been some proposed by Microsoft as part of a as part of a try and get it in the standard thing I'm not exactly sure where that is in the process but it'd be kind of cool to have that so one of the things that I was hoping to leverage a lot of was this context birthing and I ran into a thing where it wasn't actually executing at the time when I thought it was so in the top example we have a Const int and we actually are calling a context for function with a context per string and it doesn't get executed a compiled time it gets executed at runtime at compile time the one the second one there gets run because it's the value that you're assigning to it is a context bruh and that was a little bit disappointing to me what I would have really liked or did too for it to have done is the compiler actually run the concepts put a hash generation and then just stick it in there as a constant value which is what the macro evaluation stuff can do so I was hoping for that it didn't do that but I don't know if that's necessarily in any anyone's papers or anything yes so the the comment is that it can actually work that's not the way that it worked in my tests so every time I would iterate through there and I would be debugging it would launch the concepts for function when I and call there and get er eight through there which I didn't want to do so you're commenting on my example yes so my example of a constant is yes if you have a context where in front of it then it can execute that but the way that I was trying to use it was that in an if statement I was trying to use it as a messaging item where I could use English messages or text messages and have it actually evaluate to a constant extra hash that then I could compare against a variable in my code and then I could say like whether or not they were equal and then execute some sort of code pad so it's not necessarily that I was using a constant and it wouldn't evaluate it was that the way that I was trying to anticipate that it would work it didn't work that way all right so the final thing for nice things to have is smart pointers that can handle default destruction so I ran into this and I was kind of surprised this didn't work but if you have a class that you implement in a header and CPP off to the side and then you have a interface class it has a unique pointer to your implementation class but that's not including your class named H then it will fail to compile unless you create a destructor in your containing class in its compiled object that you know at that point it can figure out what the class name dot H is because you've included in into the CPP as you're trying to use it things like that so I was kind of surprised that this didn't work it made it kind of weird because if you're using this unique pointers and shared pointers all over the place then typically you would think that you can get rid of the destructors because all of that is taken care of for you but unfortunately that didn't work out so I don't know if this is on anyone's radar at all yes so right now the only compiler that I used so this was a question about whether or not this was implementation specific the compiler that I used was the Microsoft compiler and for Visual Studio 2015 with all of the updates that I could get would to try and leverage as many features as I could so this may be a Microsoft only thing but for games it doesn't matter because we are we are held back by the system that doesn't support the thing that we want to use so if Xcode doesn't support this or does support this and Microsoft doesn't then we need to implement it for the way that the non compiling compiler does it otherwise we can't compile for Windows or we can't compile or for Xcode sure so I guess he's trying to get me to submit a bug and I I may do that actually because this is something that I would thought would work and it would be really cool if it'd work so I know you can't write all these down but these are some great talks by a lot of people that inspired me to do this thing and put myself out here so I'm they're grateful for all of them if you can see any of them and you like games then go look up at the one by Naughty Dog what they did was they ported their engine from ps3 to ps4 and they leveraged a lot of the techniques that I was using as well not necessarily C++ 11 but they were using a thing called fibers to do mass paralyzation for the Last of Us and so do we have any questions yes not rendering but processing one frame at once I mean you with because of the way that the graphics card is implemented and not having the paralyzed like GPUs you're not able to necessarily render at the same time unless you use a third-party thing that enables that behavior for you so the question is about the work for previous frames that are and so if my frame is operating and then I go to a new frame and then I'm operating there essentially what you get is you get a place where you're processing the data and if the state of the data is not fully updated because the new frame is moving then you'll catch it next time and because the frames are operating it at 16 milliseconds the user is really going to have to do something to their machine to slow it down to actually see that hitching the delay in it so I think the session is over if you have any questions please come up I love talking about this kind of stuff so and I believe it's the end of the day so come up and I'll have til I fall asleep
Info
Channel: CppCon
Views: 72,441
Rating: undefined out of 5
Keywords: Jason Jurecka, CppCon 2016, Computer Science (Field), + C (Programming Language), Bash Films, conference video recording services, conference recording services, nationwide conference recording services, conference videography services, conference video recording, conference filming services, conference services, conference recording, conference live streaming, event videographers, capture presentation slides, record presentation slides, event video recording, video services
Id: 8AjRD6mU96s
Channel Id: undefined
Length: 61min 1sec (3661 seconds)
Published: Wed Oct 05 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.