top of page

Assignment 4

1. Show a screenshot of your game running.

The games follows:

  a. when Shift releases, the square appears; when Shift presses, the square disappears

  b. when Space releases, the rectangle disappears; when Space presses, the rectangle appears

The recording includes, in chronological order:
  a. Release both Shift and Space, showing only square 

  b. Hold Shift, release Space, showing nothing

  c. Hold both Shift and Space, showing only rectangle

  d. Hold Space, release Shift, showing both rectangle and square

2. Show the code from your MyGame project that submits the background color; show the code from your MyGame project that submits a mesh/effect pair to be drawn

My program submit the background color and the mesh/effect at the same time.

As cMyGame inherits iApplication, ​cMyGame implements the virtual function: SubmitDataToBeRendered, which is called in every update. ​

In SubmitDataToBeRendered, function SubmitRenderData is called. SubmitRenderData is implemented in Graphics.cpp, which cache the data in the application thread. 

The arguments are:

  a. A float array with size 3, representing the RGB value of the background

  b. The count of meshes to be rendered

  c. A pointer to a dynamic allocated array of cMesh* (pointers to meshes that needs to be rendered)

  d. A pointer to a dynamic allocated array of cEffect* (pointers to effects that needs to be rendered)

Requirements:

  a. For the mesh array and the effect array, the index of mesh must align with the index effect. In other words, effect[i] always binds mesh[i].

  b. The float array must be size 3. (It can be larger than 3, but only the first 3 values will be counted as the RGB values. It cannot be smaller.) The float must be in range of [0, 1] which follows the RGB values limit.

  c. The size of mesh pointer array and effect pointer array should be the count of meshes submitted. (Same as the size of float array, it can be larger but not smaller.)

3. Explain to us why we have to submit things to be drawn the way that we do. (In other words, why do we have to cache all of the data for a single frame rather than just rendering things immediately?)

Because there are two threads working simultaneously, application thread and render thread. Rendering needs time, meanwhile the application thread can process and calculate new data submitted. Therefore, we cache data in the application thread first, and then the render thread takes the data and starts render, leaving the application thread to deal with other calculation.

4. Tell us sizeof(cMesh) in both platforms. Is there any way to make it smaller?

For Direct3D, a single mesh takes up 56 bytes. For OpenGL, it takes up 32 bytes. I don't think it can be smaller.

Originally, I thought it can be smaller if keeping only one of m_triangleCount and m_vertexCountPerTriangle, since the other can be calculated with size of m_vertexData array. However, I was wrong because I cannot get the total vertex data array size, because m_vertexData only points to one sVertex_mesh. I can only get the size of m_vertexData[0].

Screenshot 2024-09-20 164454.png

For Direct3D (64bit), the size of cMesh consists of:

2 unsigned int(m_triangleCount, m_vertexCountPerTriangle): 2 * 4 = 8
1 pointer to m_vertexData array
(m_vertexData): 8

1 pointer to m_indices array(m_indices): 8

1 uint16_t with padding(macro reference count): 2 + (padding) 6 = 8

1 pointer to vertex format(m_vertexFormat): 8

2 pointers to D3D buffer(m_vertexBuffer, m_indexBuffer): 2 * 8 = 16

In total 8 + 8 + 8 + 8 + 8 + 16 = 56 bytes.

For OpenGL (32bit), the size of cMesh consists of:

2 unsigned int(m_triangleCount, m_vertexCountPerTriangle): 2 * 4 = 8
1 pointer to m_vertexData array
(m_vertexData): 4

1 pointer to m_indices array(m_indices): 4

1 uint16_t with padding(macro reference count): 2 + (padding) 2 = 4

3 GLuint(m_vertexBufferId, m_vertexArrayId, m_indexBufferId): 3 * 4 = 12

In total 8 + 4 + 4 + 4 + 12 = 32 bytes.

5. Tell us sizeof(cEffect) in both platforms. Is there any way to make it smaller?

For Direct3D, a single effect takes up 56 bytes. For OpenGL, it takes up 16 bytes. Codes below are data stored for cEffect and cRenderState. I don't think it can be smaller.

Originally, I stored te path of shaders, and initialized the shader in the initialization. Now I found that I can initialize the shaders in the constructor, and thus the paths don't need to be stored.

Screenshot 2024-09-20 173725.png
class cRenderState
{
}

For Direct3D (64bit), the size of cEffect consists of:

2 pointers to cShader(m_vertexShader, m_fragmentShader): 2 * 8 = 16
cRenderState
(m_renderState):
3 pointers
(m_BlendState, m_depthStencilState, m_rasterizerState) 

+ 1 uint8_t with padding(g_invalidRenderStateBits) = 3 * 8 + 1 * 1 + (padding) 7 = 32

1 uint16_t with padding(macro reference count): 2 + (padding) 6 = 8

In total 16 + 32 + 8 = 56 bytes.

For OpenGL (32bit), the size of cEffect consists of:

2 pointers to cShader(m_vertexShader, m_fragmentShader): 2 * 4 = 8
cRenderState
(m_renderState):
1 uint8_t with padding
(g_invalidRenderStateBits) = 1 * 1 + (padding) 1 = 2

1 uint16_t (macro reference count): 2 * 1 = 2

1 GLunit(m_programId): 4

In total 8 + 2 + 2 + 4 = 16 bytes.

6. Tell us the total memory that you have budgeted to your Graphics project for data to render frames.

For the Graphics project, there are following static variables, and I used sizeof to get their values:

  a. 1 pointer of cView(sView) -> 4 bytes for 32bit, 8 bytes for 64bit

  b. 1 constant buffer(s_ConstantBufferFrame) -> 12 bytes for 32bit, 24 bytes for 64bit

  c.2 sDataRequiredToRenderAFrame(s_dataBeingSubmittedByApplicationThread, 
s_dataBeingRenderedByRenderThread)

    -> in total 336 bytes for 32bit (168 bytes/each), 352 bytes for 64bit (176 bytes/each)

  d.2 cEvent(s_whenAllDataHasBeenSubmittedFromApplicationThread, 

s_whenDataForANewFrameCanBeSubmittedFromApplicationThread)

    -> in total 8 bytes for 32bit (4 bytes/each), 16 bytes for 64bit (8 bytes/each)

Screenshot 2024-09-20 194952.png

Taking a closer look at the sDataRequiredToRenderAFrame struct:

For Direct3D(32bit), the size of sDataRequiredToRenderAFrame consists of:

1 sFrame(constantData_frame): 144

  sFrame consists of:
  2 matrix_transform + 2 floats + a float array of size 2

 = 2 * 64 + 2 * 4 + 2 * 4 = 144 (same for both platforms)
1 float array of size 3(backgroundColor): 4 * 3 = 12

1 uint16_t with padding(meshCount): 2 * 1 + (padding) 2 = 4

2 pointers to the mesh pointer array and effect pointer array(meshArr, effectArr):

2 * 8 = 16

In total 144 + 12 + 4 + 16 = 176 bytes.

For OpenGL(32bit), the size of sDataRequiredToRenderAFrame consists of:

1 sFrame(constantData_frame): 144

  2 matrix_transform + 2 floats + a float array of size 2

 = 2 * 64 + 2 * 4 + 2 * 4 = 144 (same for both platforms)

1 float array of size 3(backgroundColor): 4 * 3 = 12

1 uint16_t with padding(meshCount): 2 * 1 + (padding) 2 = 4

2 pointers to the mesh pointer array and effect pointer array(meshArr, effectArr):

2 * 4 = 8

In total 144 + 12 + 4 + 8 = 168 bytes.

©2024 by Junxuan Hu, a gameplay programmer and technical designer.

Proudly created with Wix.com

bottom of page