Tumgik
#Renderframes
jafarsydi · 1 year
Text
0 notes
arashtadjiki · 5 years
Text
Reworking the Graphics System
Tumblr media Tumblr media Tumblr media
Whereas last time we made our Graphics class platform-independent, this assignment dealt more with separation of concerns, and stripping out the elements of Graphics.cpp that should firstly belong somewhere else in the engine, and should also have better functionality. 
Instead of hardcoding what we want on screen within Graphics itself, that information is now kept inside the actual game project where it belongs. Data is now continuously submitted to the Graphics system, where it is processed. For starters, a game using the graphics system can set the background color by submitting RBGA values using the overloaded SubmitDataToBeRendered function. 
Tumblr media
Getting something onto the screen used to be really tedious. The user would have to specify an object geometry, as well as a shader effect, and would then have to call a trove of functions to initialize, render and dispose the objects, making it very unintuitive. In this rendition of the project, all the information regarding a 3D object on screen is now contained inside an instance of the RenderObject class, which I created to make the rendering process easier. 
Tumblr media Tumblr media
As shown above, the user first initializes a RenderObject by specifying the vertex data, index data, as well as the path to a shader. The RenderObject then creates the needed objects, such an instance of cEffect, and cObjectGeometry and returns a pointer. All the user has to do to render their object on screen is submit that pointer to the graphics system. To remove it temporarily, they can simply not submit it, or delete it entirely as well. RenderObject handles the cleanup of all the data beneath it, meaning the user doesn’t have to go around tying loose pointers. I had thought of submitting pairs of geometries and effects to the graphics system instead, but that seemed too complicated, and the abstraction of a container class turned out to be a lot easier to work with. 
In this engine, things aren’t rendered immediately. We can’t assume that if we were to render at any instance, the rest of the game engine is up to speed with that decision. What if the physics system is still working, or the game is still waiting for input? To maintain concurrency, we cache the data for the next frame and render it when it is time to render it. Inside the RenderFrame function in Graphics.cpp, the frame isn’t rendered until all data has been submitted to the application thread. This dictates the order of operations in the engine. The Game listens for input, then gathers the data to be submitted to be rendered, and sends it down the pipe to the Graphics system, which handles it when all data has been submitted. Concurrency is also vital to protecting data, as this is a multi-threaded system. 
Sizes:
Obviously in running a game, we want to be allocating as little memory as possible to process our data. There are some stark differences between platforms when it comes to the objects being passed through the Graphics system:
ObjectGeometry:
cObjectGeometry, which contains vertex and index data is 32 bytes and 56 bytes on x86 (OpenGL) and x64 (Direct3D) respectively. I suspect Direct3D’s geometry is larger because it’s carrying pointers for the vertex and index buffers, while OpenGL uses GLuints. This would account for the size difference as three 64 bit pointers would amount to 24 extra bytes. To reduce size I could try packing my object differently, but almost every variable is a pointer, so there is no way around the architecture-dependent size. 
Effects:
cEffect, which represents a shader effect is larger on OpenGL than Direct3D, 20 bytes vs 16 bytes respectively. As I mentioned in my last write-up, this is because of the extra pointer an OpenGL cEffect has for the ProgramID.  One thing I could do to reduce size is to no longer store the shader path in the variable. Since we’re never going to change it dynamically anyway, it only has to be there for initialization, reducing both structs by 4 and 8 bytes.
Frame Render Data
In total, the Graphics system uses 368 bytes to render a frame on Direct3D, and 344 bytes on OpenGL.  This can be broken down into three components - the constant buffer, the background color, and the array of render objects allowed in scene. On both OpenGL and Direct3D, 144 bytes are allocated for the constant buffer, and 16 bytes for the background color (uses floating point). Direct3D’s render object pool is 24 bytes long, and OpenGL’s is 12.  I could reduce the size of this by dynamically growing and shrinking the render object pool as things are submitted. As of now, the sDataRequiredToRenderAFrame struct that the Graphics system uses each frame render contains a render object pool that is already initialized to store the maximum amount of objects allowed (3 in my current system). If the user is only storing one render object, then there are two empty slots, a big waste of space!
Controls: 
Left arrow - Change effect of triangle
RIght Arrow - Hide Diamond
Download here: https://my.eng.utah.edu/~tadjiki/Assignment4.zip
0 notes