[video output=day477 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Changing to Single Dispatch Per Pass (Part 1)" vod_platform=youtube id=xEWV5zvCiho annotator=Miblo]
[0:00][Recap and set the stage for the day][:speech]
[1:05][Reacquaint ourselves with the separated renderer][:api :run]
[2:07][Review win32_renderer_test.cpp][:api :research]
[4:28][Determine to update the :API of our primitive pushing functions, and accelerate texture processing using texture arrays][:rendering :speech]
[8:50][Set up to support camera-matched quads][:camera :speech]
[10:26][Camera-matched quads][:blackboard :camera :rendering]
[11:20][Temporarily change PushSimpleScene() to push trees as non-upright sprites, and :run the Renderer Test to see the trees Z-fighting with the ground][:programming :rendering]
[12:20][Respecify and simplify PushSprite() as a non-upright sprite pushing function][:rendering]
[17:49][:Run the Renderer Test to see all our non-upright sprites][:rendering]
[17:52][Introduce PushUpright() as a dedicated function that handles upright sprites][:rendering]
[19:03][:Run it to see the grass as upright sprites][:rendering]
[19:16][Give PushUpright() default values for MinUV and MaxUV][:rendering]
[21:12][Camera-matched quads, placing 2D sprites in a 3D world][:blackboard :camera :rendering]
[26:39][Make PushUpright() interpolate the sprite axes between the world axes and camera-relative axes, running it to see the grass sprites rotating to follow the :camera][:programming :rendering :run]
[28:18][Attenuating the sprite's Y-axis for lay-down, while preserving the camera's X-axis][:blackboard :camera :rendering]
[30:34][Make PushUpright() use the camera's X-axis][:camera :rendering]
[31:16][:Run it to see the grass following the :camera][:rendering]
[31:26][Change PushSimpleScene() to call PushUpright() for the tree sprites][:rendering]
[31:49][:Run it to see the trees following the :camera, until we crash when panning][:rendering]
[33:02][Add Shift to the :camera struct so that the panning code can cold-set the Offset][:rendering]
[35:01][:Run it to try and see if the panning is working correctly][:camera :rendering]
[35:40][Change PushSimpleScene() to use the (rectangular) wall sprite instead of the tree, to help debug the sprite lay-down attenuation][:camera :rendering]
[36:08][:Run it to see that the wall sprites are not slanted][:camera :rendering]
[36:14][Make PushUpright() use 0.25 × the world axes for the sprite's Y-axis][:camera :rendering]
[36:28][:Run it to see our correctly tilting sprites, but their insufficient camera-facing rotation][:camera :rendering]
[37:05][Temporarily make PushSimpleScene() skew the wall sprites][:camera :rendering]
[38:40][:Run it to see our skewed walls sprites erroneously collapsing under rotation][:camera :rendering]
[40:00][Enable PushUpright() to correctly attenuate the Y-axis of skewed sprites][:camera :rendering]
[47:22][Subtracting the :camera Z-axis to push the Y-axis into the screen][:blackboard :rendering]
[48:14][Make PushUpright() normalise our hybrid Y-axis][:camera :rendering]
[48:33][:Run it to see the skewed sprites rotating to face the :camera without collapsing][:camera :rendering]
[49:03][Let PushSimpleScene() push the upright wall sprites using the default axes][:camera :rendering]
[49:23][:Run it to see the lay-down of the wall sprites not looking quite right][:camera :rendering]
[51:19][Change PushUpright() to attenuate the sprite Y-axis towards the world's Z-axis][:camera :rendering]
[52:10][:Run it to see the lay-down looking better, and consider making the attenuation tunable by the artist][:camera :rendering]
[54:05][Make PushSimpleScene() skew the wall sprites][:camera :rendering]
[54:24][:Run it to see that the wall sprites rotate without collapsing][:camera :rendering]
[55:03][Make PushSimpleScene() use our tree sprites again][:camera :rendering]
[55:17][:Run it to see our rotating tree sprites][:camera :rendering]
[55:30][Make PushUpright() attenuate the sprite's Y-axis 50/50 between the world and camera Y-axis][:camera :rendering]
[55:52][:Run it to see our 50/50 tree sprites][:camera :rendering]
[56:27][Make PushUpright() attenuate the sprite's ZBias with the lay-down][:camera :rendering]
[1:00:58][:Run it to see our upright sprites without any Z-fighting][:camera :rendering]
[1:02:18][Make PushUpright() take a tCameraUp and add a WorldUp to the render_group struct][:camera :rendering]
[1:05:12][:Run it to see it all working nicely][:camera :rendering]
[1:05:39][Introduce cube_uv_layout struct to permit custom layouts to be passed to PushCube()][:rendering]
[1:16:32][:Run it to see it all working fine][:rendering]
[1:17:12][Test custom cube texture layouts][:rendering]
[1:21:57][:Run it to see our custom cube textures for the start and end of walls][:rendering]
[1:22:43][Change WallUV to use the mid-wall texture][:rendering]
[1:23:23][:Run it to see our textured walls][:rendering]
[1:23:40][Prevent PushSimpleScene() from randomising the Z of wall elements][:rendering]
[1:24:47][:Run it to see our textured and aligned walls][:rendering]
[1:24:57][Prevent PushSimpleScene() from varying the wall colour][:rendering]
[1:25:32][:Run it to see our aligned, segmented wall][:rendering]
[1:29:15][Stress test the texture changing][:performance :rendering]
[1:29:45][:Run it to see our slowdown with the determination to figure out who is at fault][:performance :rendering]
[1:30:29][Set up an Nsight project][:admin]
[1:32:42][:Run our Renderer Test in Nsight and trigger it to capture a frame][:performance :rendering]
[1:37:06][Set up to fake sprite dispatch aggregation[ref
    site="OpenGL Hardware Database"
    url=https://opengl.gpuinfo.org/]][:hardware :research :rendering]
[1:41:52][Switch OpenGLEndFrame() from using glDrawArrays()[ref
    site=docs.GL
    page=glDrawArrays
    url=http://docs.gl/gl2/glDrawArrays] to sending down tri-strips using glDrawElements[ref
    site=docs.GL
    page=glDrawElements
    url=http://docs.gl/gl2/glDrawElements]][:hardware :rendering]
[1:44:42][Tri-strip][:blackboard :hardware :rendering]
[1:45:15][Finish switching OpenGLEndFrame() over to use tri-strips, guided by the OpenGL spec[ref
    site=OpenGL
    page="OpenGL 4.4 (Core Profile)"
    url=https://www.khronos.org/registry/OpenGL/specs/gl/glspec44.core.pdf]][:hardware :rendering]
[1:52:49][:Run it to see our triangles wound backwards][:hardware :rendering]
[1:53:10][Fix our triangle winding in OpenGLEndFrame()][:hardware :rendering]
[1:53:35][:Run it to see our correctly drawn scene][:hardware :rendering]
[1:54:04][Q&A][:speech]
[1:54:25][@mmozeiko][Q: Primitive restart index is in GL Core since version 3.1: glPrimitiveRestartIndex() function][:rendering]
[1:54:37][@lkalinovcic][Q: I thought you had to bind a GL_ELEMENT_ARRAY_BUFFER to do indexing, is this not true if no buffer is bound?][:rendering]
[1:55:38][@rale_2][Q: Using indices seems to take a lot more memory if the vertex data contains texture coordinates, normals, etc. How do you know when it's a good idea to render by indices?][:rendering]
[1:57:16][@ivereadthesequel][Q: I have one regarding @vaualbus' pre-stream question if that's alright: Why were the next steps of investigations into the MessageBox call not working to try doing it with the indirect call, then next to do it on another thread? What was the line of thinking?]
[1:58:10][@lkalinovcic][Q: What is your opinion on texture arrays vs texture atlases? Why did you choose to do texture arrays?][:hardware :rendering]
[2:00:22][@centhusiast][Q: Does the window size have anything to do with the tuning of the t value in the renderer, e.g. if we use the full screen window?][:rendering]
[2:00:58][@lkalinovcic][Q: Texture arrays require all textures to be the same size and have the same number of mipmaps, though. Isn't that a significant limitation? Atlases require manual handling in the shader, but I feel like they're more general][:hardware :rendering]
[2:01:51][@rooctag][Q: What are we going to mipmap in [~hero Handmade Hero]?][:hardware :rendering]
[2:02:00][@frostyninja][Q: Off-topic: How long is fall break going to be?]
[2:02:11][@areriff][Q: There's a rewrite of Dependencies Walker for Windows 10.[ref
    site=GitHub
    page="lucasg / Dependencies"
    url=https://github.com/lucasg/Dependencies] The old depends.exe is not up to date for Windows 10 dlls. You might find it useful for [~hero Handmade Hero]]
[2:04:35][@lkalinovcic][Q: Do you know if texture sampling is implemented in hardware? If it's not, then I don't think manually handling atlases would be slower][:hardware :rendering]
[2:06:57][@ivereadthesequel][Q: This is just about paradigms: What sets apart the functions you have made to construct structs certain ways (like GetStandardCamera) from the methodology around constructors in C++ that I presume you dislike? Or are they actually similar?][:language]
[2:07:46][Demo C++ constructors, with an example of a better constructor][:language :rant :speech]
[2:19:16][:API Granularity][:language :speech]
[2:21:43][@mmozeiko][Q: You were selecting .NET executables in dependency walker, for which it won't show anything]
[2:21:52][@vaualbus][Q: Back to the message box pre-stream answer, removing the filtering of message 0x738 make the window appear]
[2:22:13][@centhusiast][Q: Are you testing the renderer with the PNG asset? Do you think the renderer would have a better :performance with bitmap because the decoding of that is easier than the PNG one?][:rendering]
[2:22:42][@lkalinovcic][Q: I'm not sure, but doesn't camera Camera = {} in C++ call the constructor? (I know it zeroes if it's a normal structure, but I think if it's a thing with a constructor it calls it)][:language]
[2:23:18][@cubercaleb][Q: Also, placement new returns a new "object" (in terms of C / C++ object lifetimes), so you technically need to access it through the pointer returned, so it is disgusting][:language]
[2:23:35][@darkepopt][Q: Do you think you could submit a constructor like that to the C++ committee?][:language]
[2:24:19][][:language :speech][quote 628]
[2:24:58][Thoughts on proprietary software companies offloading QA to their users][:rant :speech]
[2:28:39][Time for lunch][:speech]
[/video]
