[video output=day475 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Abstracting the Renderer Interface" vod_platform=youtube id=EguT5zni4J4 annotator=Miblo] [0:02][Recap and set the stage for the day][:speech] [0:49][Walk through our test RenderLoop() with a view to streamlining the :camera and fog code, and cleaning up the drawing calls in PushSimpleScene()][:api :rendering :research] [3:34][Our framerate problems incurred by the :lighting][:performance :rendering :research] [6:12][Crank up the grass sprite count in PushSimpleScene()][:rendering] [7:53][:Run the game and step in the RenderLoop() to see that we are using 184 bytes of our 64 megabyte-capacity PushBuffer][:memory :performance :rendering] [9:15][Reduce the PushBuffer size to 1 megabyte][:memory :rendering] [10:09][Consider simplifying the PushBuffer out of the renderer :API][:memory :rendering] [16:26][Change open_gl to no longer be initialised as a global variable, but locally by Win32InitOpenGL()][:api] [28:49][Introduce platform_renderer to generalise our renderer and decouple it from the OpenGL :API] [35:04][Introduce GetWhiteBitmap(), and continue the :API decoupling, renaming DefaultRenderCommands() to BeginFrame() and OpenGLRenderCommands() to EndFrame()] [41:38][Set up implement platform_renderer dispatching][:api :speech] [42:49][Change LoadBMP() to call AddOp() and take a renderer_texture_queue and renderer_texture rather than call QueueTextureOp() and take a platform_renderer][:api] [46:50][Introduce AllocateTextureQueue() and ProcessTextureQueue() for RenderLoop() to call][:api :memory] [50:17][Implement AllocateTextureQueue(), setting it up to use the platform :memory allocation call][:api :"platform layer"] [52:23][Remove AllocateTextureQueue() in favour of making RenderLoop() call InitTextureQueue(), allocating :memory in that call using Win32AllocateMemory()][:api :"platform layer"] [55:19][Respecify InitTextureQueue() to take MemorySize, and itself compute the possible TextureOpCount to fit in that :memory][:api] [58:09][Rename MaxVertexCount to MaxQuadCountPerFrame in RenderLoop(), leaving the possibility open for the platform to specially allocate the :memory][:api] [1:00:15][Reorder RenderLoop() slightly][:api] [1:01:11][Make Win32InitOpenGL() allocate our open_gl, adding PushBufferMemory and textured_vertex and renderer_texture arrays to this struct][:api :memory] [1:08:09][Demo C++ inheritance to abstract the renderer][:api :language] [1:11:38][Abstract out the renderer dispatch with an enum in platform_renderer, for newly introduced Win32AllocateRenderer(), ProcessTextureQueue(), BeginFrame() and EndFrame() to switch on][:api] [1:27:33][Introduce OpenGLBeginFrame(), adding WindowWidth and WindowHeight to game_render_commands, and stubbing out the various API-specific functions][:api] [1:38:54][:Run the Renderer Test and check out our :memory usage, to see that we have reserved 1.5 gigabytes][:performance] [1:41:20][Step through RenderLoop() to determine that EndFrame() allocates this :memory][:performance :run] [1:44:19][Step through OpenGLEndFrame() into OpenGLChangeToSetting() to see that the first CreateFramebuffer() call reserves 300 megabytes][:memory :performance :run] [1:46:33][Step in to CreateFramebuffer() to see that the glFramebufferTexture2D() call reserves 200 megabytes, and investigate whether this is reasonable][:memory :performance :run] [1:51:17][:Run the game and consider our high :memory usage][:performance] [1:53:29][Temporarily disable multisampling in OpenGLInit()][:rendering] [1:53:49][:Run the game to see that it now only reserves 312 megabytes][:memory :performance] [1:54:09][Re-enable multisampling in OpenGLInit() and reduce the grass sprite count in PushSimpleScene()][:rendering] [1:54:51][:Run the game, and compare the edge :rendering with and without multisampling] [1:58:03][Disable pixelisation in OpenGLInit()][:rendering] [1:58:32][:Run the game and consider that enabled pixelisation to be a bug][:rendering] [1:58:53][Switch [~hero Handmade Hero] over to our abstracted renderer interface[ref site=MSDN page="wglGetCurrentDC function" url=https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-wglgetcurrentdc]][:api :memory :rendering] [2:12:51][:Run both the Renderer Test and game successfully][:api] [2:13:28][Refresh our memories as to how the mouse position is handled][:"input handling" :research] [2:15:24][Prevent DEBUGEnd() from calling ClipSpaceFromPixelSpace() to map the mouse coordinates][:"debug system" :"input handling"] [2:16:01][:Run the game to find that the clicking doesn't work][:"debug system" :"input handling"] [2:16:20][Introduce ClampBinormalMapToRange() for WinMainCRTStartup() to clamp the mouse coordinates to -1 to 1 space][:"debug system" :"input handling"] [2:19:03][:Run the game to find that the mouse works again, but that the rotation and scaling controls are broken][:camera :"debug system" :"input handling"] [2:19:31][Tweak the :camera rotation and zooming multipliers in UpdateAndRenderWorld()][:"input handling" :programming :run] [2:21:22][Change the Mouse coordinates in game_input to be one v3 called ClipSpaceMouseP][:"input handling"] [2:23:21][:Run the game to see that all is working, except for the positions of the :"debug system" menus] [2:24:34][Reflect on our renderer :API][:research] [2:25:47][Make OpenGLChangeToSettings() responsible for setting VSync using a newly introduced PlatformOpenGLSetVSync()][:api :rendering] [2:29:58][:Run the game and the Renderer Test to gauge the VSync][:rendering] [2:31:34][:Run the Renderer Test in -Od to see that we do request that VSync is disabled][:rendering] [2:32:20][Q&A][:speech] [2:32:47][Reflect again on our cleaner renderer :API][:research] [2:33:45][@ivereadthesequel][Q: Don't know if you've answered this before, but why do you make all of your functions internal? Some in chat were saying that doesn't seem to make sense in a unity build, but I'm just wondering for your general case][:language] [2:36:51][@vateferfout][Q: Not important, but I think that in your LoadBMP() function you're still declaring a renderer_texture result] [2:37:29][@rationalcoder][Q: Is there something about your render passes that prohibits hybrid AA techniques, like MSAA 4X plus conservative FXAA? MSAA 16X is way overkill][:rendering] [2:40:33][Reduce MaxMultiSampleCount in OpenGLInit()][:rendering] [2:41:00][:Run the game to gauge our multisampling quality][:rendering] [2:43:50][@uplinkcoder][Q: Could you take a look at 'Typo in win32_render_test.cpp'[ref site=HandmadeHero/cpp/Issues page="Typo in win32_render_test.cpp" url=https://github.com/HandmadeHero/cpp/issues/76]] [2:44:06][Fix typo in PushSimpleScene()][:"procedural generation"] [2:45:16][@Rounin][Q: The plants look worse with 8-bit][:rendering] [2:46:03][@centhusiast][Q: Have we used the malloc from CRT or have we always used Windows alloc? Is it okay to use the malloc in the game?][:memory] [2:47:39][@ivereadthesequel][Q: On "internal": sorry, I was just wondering on a more fundamental level. I only knew it makes that function only accessible from that translation unit (I may have this wrong), and I wanted to know what it did for you in general, not just in response to the unity build part. Or is that really all it does?][:language] [2:51:34][We're all good[ref site="Handmade Hero" url=https://handmadehero.org/][ref site="Molly Rocket's Site Nexus" url=https://mollyrocket.com/nexus]][:speech] [/video]