[video 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]