A High Performance Data-Driven, Entity-Component Framework for Game Engines with Focus on Data-Oriented Design
Total Page:16
File Type:pdf, Size:1020Kb
A High Performance Data-Driven, Entity-Component Framework For Game Engines With Focus on Data-Oriented Design Max Danielsson∗ Gustav Pihl Bohliny Blekinge Institute of Technology Abstract 2.1 Entity-Component This paper presents an implementation of a Data-Driven Entity- Nystrom[2014] has summarized the fundamentals of component- Component framework for computer game engines built using based design and how it differs from object-oriented design. In his Data-Oriented Design principles. In the framework a developer de- suggested solution the components contain both data and logic and fines systems and components to create games. We present a simple are tied together in game object classes. Each component contains test-case built in the framework with rendering and audio, measur- its locally relevant logic and can communicate with other compo- ing system performance and cache misses. The results are deemed nents either via direct access or messages. promising, with good cache utilization and the framework is con- The Unity game engine1 is a well known example where EC based cluded to be useful as a base for future development. programming is used to a great extent, providing a system for ex- tending entity behaviour through a scripting layer. Keywords: entity-component, data-oriented, data-driven, game West[2007] has a write-up over the basics of EC concepts, describ- engine, game architecture, engine framework ing a design which is flat rather than hierarchical. Martin[2007] has written about a slightly different solution adding 1 Introduction the concept of Systems which house the logic used for transform- ing the data of components, essentially turning components into In this paper, an implementation of a game object framework is pre- pure data. He also adds the concept of aspects, representing a sented. It combines two design patterns: EC (Entity-Component) component composition, similar to our solution, which we detail and DOD (Data-Oriented Design), with the aim to provide a foun- in section 3.2. He also goes to great lengths describing anecdo- dation for a game engine architecture that is both efficient in terms tal information regarding the widespread difference in what entity of rapid feature implementation and cache utilization. component systems are to developers. His writings have inspired the Artemis Entity System Framework[Arent 2012] which is an EC based systems [Nystrom 2014, c.14] have been on the rise in open-source framework for implementing EC based games and has popularity within the game industry since at least 2002 when Scott served as an inspiration to our own implementation. Bilas proposed a method where game objects are Data-Driven enti- Garcia et al.[2014] has previously described the gains in designing ties constructed from a composition of multiple components[Bilas accessible games by employing Data-Driven and EC based design 2002]. A flat EC game object design, as compared to a hierarchi- principles. The methods described show how a games stimulation cal game object design, lessens coupling between behaviour and or output to the user can be modified within the game without re- entity types, and individual entities become more malleable. Be- designing other aspects of the engine. This is achieved simply by haviour can be easily shared between vastly different entities, with- switching out components responsible for stimulation. By creat- out the need for complex inheritance structures. The core goal is to ing different profiles for people with different abilities the game is handle the immense complexity of large games and to allow faster allowed to have a greater accessibility and a bigger audience. turnaround times on feature changes. 2.2 Data-Oriented Design DOD is a design paradigm based on performance optimization prin- ciples. The primary goal of DOD is to engineer programs that consider cache hardware design, maximizing memory throughput The primary performance bottleneck of modern CPUs (Central Pro- and CPU utilization. We have observed that EC patterns lends it- cessing Unit) is memory access times[Hennessy et al. 2007]. The self well to DOD principles because of its potential decoupling of main way this has been alleviated has been through implementa- memory and procedures. This decoupling allows us to meticulously tion of so called caches; Faster but more expensive memory placed place component data in memory and order execution to minimize between the CPU and RAM (Random Access Memory) where re- cache-miss rates. cently accessed memory is stored for quicker reuse. The assump- tion is that memory which is recently used has a high likelihood of being accessed again—a concept called temporal locality. An- 2 Previous Work other assumption made with modern caches is that memory is often accessed close to previous accesses, or linearly. This concept is called spatial locality. The spatial locality assumption is reflected There has been a substantial amount of work done in the game de- in that cache often stores a larger chunk of sequential memory, a velopment field regarding DOD and EC. Yet, relatively little has cache-line, than is being accessed by the instruction.[Gerber and been published in peer-reviewed journals and most of the infor- Bik 2006, p.111][Hennessy et al. 2007] mation currently resides in books and developers personal online resources in the form of presentations and blogs. Albrecht[2009] from Sony has a presentation regarding DOD in which he presents the impact of cache efficient data layout. He also details the difference between different orders of execution ∗e-mail:[email protected] ye-mail:[email protected] 1http://unity3d.com/ and memory de-referencing and how strongly it can impact per- collide. The game uses six components to store the different types formance. of data. One component each for: position, velocity, rendering data (sprite), audio (audio file), collision (radius) and a component for Frykholm[2014] from Bitsquid details an EC implementation with activating the play sound on collision system. focus on DOD, although different from ours in many ways. His so- lution has a tighter coupling between systems and component types, Entities are defined in JSON files, as opposed to XML used by Gar- giving the systems the responsibility to handle allocation of its com- cia and Almeida Neris. Both formats serve similar purpose and ponent type. This results in a more tailored allocation scheme for the change is purely that of personal preference. The JSON files specific data, but gives the developer implementing the systems a contain the data definitions and component makeup of an entity. larger responsibility. The files are loaded by the program using Jansson3 and parsed to generate the needed entities for the test. After loading, the enti- 3 Method ties’ velocities and positions are randomly modified to make them behave somewhat differently. We define three types of objects: This paper uses Garcia’s and Almeida Neris’[2014] work as a start- audio-visual, visual and background objects. The audio-visual ob- ing point in defining how an EC framework can work in the abstract ject moves, collides, is rendered and plays a sound on collision. The and we present a practical implementation which is designed us- visual object has no audio component and the background object is ing DOD in the programming language C++11[Stroustrup 2013]. invisible, inaudible and runs only in the background. The varia- We then implement a simple real-time application and measure tion allows for better focus on our implementation and less on the its frame-time and cache-miss rates to determine its performance, performance and scaling of SDL’s features. which are later discussed. 4 Implementation 3.1 Outline Components can not have member functions or complex construc- Building upon the work of Garcia and Almeida Neris[2014] we first tors. They have to be trivially copyable, preferably so called POD detail some technical aspects in section 3.2, defining components (Plain Old Data) objects. The reason for this is to simplify copy and entities and adding concepts such as aspects and systems which and storage of these structures in memory. In our implementation will aid in describing the implementation in section4. After going we verify this during compile time using static compile-time asserts through our implementation we cover some results in section5 re- which simplify development and removes some common mistakes. garding the performance of the system. At the end of this paper in section6 we discuss the results and our implementation. Lastly sec- Entities consist of one unsigned integer. As a result it is easy to sort tion 6.2 covers future work and suggestions on how our framework entities and execute them in an ascending order. The assumption can be improved. is that entities which are placed in an ascending order has compo- nents which are placed in an ascending order. This is not guaran- 3.2 Concepts teed however and it is all up to the component allocation routines to try and optimize this creation to achieve an optimal memory Before we begin to detail our implementation we define the four structure. As entities are released and reclaimed, id reuse is in- primary concepts that are relevant. Note the there are no strict defi- evitable, this can cause mix-ups as a routine keeps a reference to a nitions of these terms and that ours may vary from other authors. reclaimed entity id which it does not actually have intended interest in. This can be solved using a second integer as a globally unique A component is a collection of data, it does not have any logic di- id which grows for each Entity allocation, resulting in collision free rectly tied to it, like a standard OO (Object-Oriented) class would. ids. Frykholm[2014] solves this issue by reserving part of the id’s An entity is a specific collection of Components given a common memory for a ”generational id” which is locally incremented for ID.