[video output=day546 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="GPU MIP Mapping" vod_platform=youtube id=mpRKQCi3tjw annotator=Miblo]
[0:02][Recap and set the stage for the day][:speech]
[0:40][Demo our new ground cover, with the need to light our sprites][:"entity system" :lighting :rendering :run]
[1:49][MIP mapping our sprites][:"entity system" :memory :rendering :run]
[8:14][Distributing our grass more naturally][:"entity system" :prng :run :statistics]
[9:55][Plan to work on our :rendering quality][:run]
[11:08][MIP (Multum In Parvo) maps][:blackboard :optimisation :rendering]
[14:00][Texture sampling][:blackboard :rendering]
[18:05][MIP map pre-filtering][:blackboard :optimisation :rendering]
[23:15][Anisotropic filtering][:blackboard :optimisation :rendering]
[30:31][MIP map :memory bandwidth savings and efficiency][:blackboard :optimisation :rendering]
[32:55][Understanding glTexSubImage3D()[ref
    site=docs.GL
    page="glCompressedTexSubImage3D"
    url=http://docs.gl/gl3/glCompressedTexSubImage3D]][:hardware :rendering :research]
[35:09][Understanding the "level" parameter of glCompressedTexSubImage3D()[ref
    site=docs.GL
    page="glCompressedTexSubImage3D"
    url=http://docs.gl/gl3/glCompressedTexSubImage3D]][:blackboard :hardware :rendering]
[36:38][Set up OpenGLManageTextures() to specify the texture subimage of multiple MIP map levels][:hardware :rendering]
[37:38][Understanding glGenerateMipmap()[ref
    site=docs.GL
    page=glGenerateMipmap
    url=http://docs.gl/gl3/glGenerateMipmap]][:hardware :rendering :research]
[39:00][Experimentally revert OpenGLManageTextures() and instead call glGenerateMipmap()[ref
    site=docs.GL
    page=glGenerateMipmap
    url=http://docs.gl/gl3/glGenerateMipmap] to do all the MIP mapping][:hardware :rendering]
[41:03][Better understanding glGenerateMipmap()[ref
    site=docs.GL
    page=glGenerateMipmap
    url=http://docs.gl/gl3/glGenerateMipmap]][:hardware :rendering :research]
[43:59][Abandon glGenerateMipmap() and make LoadAssetWork() to generate the MIP maps ourselves][:hardware :optimisation :rendering]
[55:49][Make OpenGLManageTextures() specify the texture subimage of multiple MIP map levels][:hardware :rendering]
[58:08][Introduce Downsample2x() for LoadAssetWork() and our original Downsample() to call][:rendering]
[1:03:03][Create handmade_image.cpp and .h][:rendering]
[1:09:17][Introduce GenerateSequentialMIPs() for LoadAssetWork() to call, IterateMIPs() and the mip_iterator versions of IsValid() and Advance()][:rendering]
[1:15:23][Consider how best to indicate special textures to BeginTextureOp()][:rendering :research]
[1:19:47][Change BeginTextureOp() to take a SizeRequested for LoadBitmap() to pass, introducing GetTotalSizeForMIPs()][:rendering]
[1:24:35][Implement GetTotalSizeForMIPs(), IterateMIPs() and the mip_iterator versions of IsValid() and Advance()][:rendering]
[1:31:09][Step through BeginTextureOp() to debug our new MIP mapping work][:rendering :run]
[1:33:14][Fix GetTotalSizeForMIPs() to correctly accumulate the size, and the mip_iterator version of Advance() to operate the opposite way round][:rendering]
[1:33:49][Step through GetTotalSizeForMIPs() and out to LoadBitmap()][:rendering :run]
[1:36:33][Hit a GL_INVALID_VALUE OpenGL error in OpenGLDebugCallback()][:rendering :run]
[1:39:15][Fix LoadBitmap() to set the TextureOp->GenMipMaps][:rendering]
[1:39:50][Step through GenerateSequentialMIPs() to see that we're not dealing with powers of 2 sizes][:rendering :run]
[1:42:02][Enable the mip_iterator version of Advance and Downsample2x() to handle non-powers of 2 sizes][:rendering]
[1:48:40][Step through GenerateSequentialMIPs() successfully][:rendering :run]
[1:49:32][Investigate the GL_INVALID_VALUE OpenGL error in OpenGLDebugCallback()[ref
    site=docs.GL
    page="glTexSubImage3D"
    url=http://docs.gl/gl3/glTexSubImage3D]][:hardware :rendering :research]
[1:51:19][Make OpenGLInit() announce all of our MIP levels][:hardware :rendering]
[1:53:03][Find that OpenGL is accepting our textures, but we have glitches][:hardware :rendering :run]
[1:55:05][Understanding the GL_TEXTURE_MIN_FILTER value for glTexParameteri()[ref
    site=docs.GL
    page="glTexParameter"
    url=http://docs.gl/gl3/glTexParameter]][:hardware :rendering :research]
[1:56:25][Temporarily prevent LoadAssetWork() from calling GenerateSequentialMIPs()][:rendering]
[1:56:44][See that our :rendering glitches are gone, and consider our possible bugs][:run]
[1:57:15][Scour Downsample2x() and GenerateSequentialMIPs() for bugs][:rendering :research]
[1:58:45][Slightly simplify GenerateSequentialMIPs()][:rendering]
[1:59:50][Step through GenerateSequentialMIPs()][:rendering :run]
[2:03:42][~remedygb bug: Clicking values of entered variables][:admin]
[2:04:40][@x13pixels][Just fixed that about 20 minutes ago]
[2:05:01][Step through Downsample2x()][:rendering :run]
[2:07:08][Add a space-checking assertion in GenerateSequentialMIPs()][:rendering]
[2:08:57][Fail to hit that assertion in GenerateSequentialMIPs()][:rendering :run]
[2:09:18][Investigate our :rendering glitches, scouring LoadBitmap()][:research]
[2:10:00][Slightly simplify LoadBitmap()][:rendering]
[2:11:21][Continue to investigate our :rendering glitches][:research]
[2:13:56][Slightly simplify OpenGLManageTextures()][:rendering]
[2:14:09][Continue to investigate our :rendering glitches][:research]
[2:15:02][See our :rendering glitches][:run]
[2:15:22][Temporarily prevent Downsample2x() from writing the pixels][:rendering]
[2:15:41][See that our glitches are gone][:rendering :run]
[2:15:44][Let Downsample2x() write the pixels][:rendering]
[2:16:17][Assert in GenerateSequentialMIPs() that the end of one bitmap is the start of the next][:rendering]
[2:17:38][Fail to hit that assertion but still see the glitches][:rendering :run]
[2:18:23][Change GenerateSequentialMIPs() to fill the MIP map with a different colour per level, introducing FillImage()][:rendering]
[2:21:52][See no :rendering glitches][:run]
[2:22:05][Scour Downsample2x() for bugs][:rendering :research]
[2:22:35][Fix Downsample2x() to output the correct sized image][:rendering]
[2:23:30][See that our glitches are gone, and we are not using our MIP maps][:rendering :run]
[2:23:48][Enable MIP maps in OpenGLInit()][:hardware :rendering]
[2:25:32][Admire our smoother, MIP mapped textures][:rendering :run]
[2:27:34][Q&A][:speech]
[2:28:04][@s0imn][Q: Would you want to add shaders to the :"asset system"?]
[2:29:01][@pragmascrypt][Q: Which textures are considered "special textures", and why do they not want MIP mapping?]
[2:30:37][@nonsensation][Q: (Off-topic) Can you explain these light blue kind of selection bars in ~4coder?]
[2:30:59][@bulmanator][Q: Request to change the name of mip_iterator to mipterator]
[2:31:06][@mattiamanzati][Q: Through stream is difficult to notice. Can we please see an image sent through chat difference between before and after MIP maps?][:rendering]
[2:31:50][Enable OpenGLChangeToSettings() to toggle MIP maps and nearest texel filtering][:hardware :rendering]
[2:41:46][Try toggling nearest texel filtering and MIP maps][:hardware :rendering :run]
[2:43:07][@kniffel5][Q: Is there an easy way to view the MIP maps sent to the GPU and, if so, why didn't you use that feature for debugging purposes before?][:hardware :rendering]
[2:44:32][@nonsensation][Q: Some file formats like DDS have MIP maps already baked in. Is generating them better nowadays or does it actually matter any longer?]
[2:46:17][@abarishu][Q: If we add some packing, would MIP maps interfere with that?][:rendering]
[2:47:39][@variandra][I don't watch you much but I was wondering: Are those settings you toggle, can / do you have a GUI so users can interact, or is that different?][:ui]
[2:49:22][Close up shop][:speech]
[/video]
