Handmade Hero»Episode Guide
Debugging the PNG Reader
?
?

Keyboard Navigation

Global Keys

[, < / ], > Jump to previous / next episode
W, K, P / S, J, N Jump to previous / next marker
t / T Toggle theatre / SUPERtheatre mode
V Revert filter to original state Y Select link (requires manual Ctrl-c)

Menu toggling

q Quotes r References f Filter y Link c Credits

In-Menu Movement

a
w
s
d
h j k l


Quotes and References Menus

Enter Jump to timecode

Quotes, References and Credits Menus

o Open URL (in new tab)

Filter Menu

x, Space Toggle category and focus next
X, ShiftSpace Toggle category and focus previous
v Invert topics / media as per focus

Filter and Link Menus

z Toggle filter / linking mode

Credits Menu

Enter Open URL (in new tab)
0:01Recap and set the stage for the day debugging our PNG reader
🗩
0:01Recap and set the stage for the day debugging our PNG reader
🗩
0:01Recap and set the stage for the day debugging our PNG reader
🗩
1:01On starting by making our decompressor produce the correct number of bytes from our input stream
🗩
1:01On starting by making our decompressor produce the correct number of bytes from our input stream
🗩
1:01On starting by making our decompressor produce the correct number of bytes from our input stream
🗩
4:14Approaching problems either by working from a spec, or comparing our implementation with a working version
🗩
4:14Approaching problems either by working from a spec, or comparing our implementation with a working version
🗩
4:14Approaching problems either by working from a spec, or comparing our implementation with a working version
🗩
6:00Run the program on gimp_test.png until a crash caused by the Dest pointer's attempt to write into memory
🏃
6:00Run the program on gimp_test.png until a crash caused by the Dest pointer's attempt to write into memory
🏃
6:00Run the program on gimp_test.png until a crash caused by the Dest pointer's attempt to write into memory
🏃
13:25Let ParsePNG() proceed to the next iteration of the loop, to see another length code 258
🏃
13:25Let ParsePNG() proceed to the next iteration of the loop, to see another length code 258
🏃
13:25Let ParsePNG() proceed to the next iteration of the loop, to see another length code 258
🏃
15:38Compare our PNGLengthExtra and PNGDistExtra tables with the DEFLATE spec1 to ensure they look right
📖
15:38Compare our PNGLengthExtra and PNGDistExtra tables with the DEFLATE spec1 to ensure they look right
📖
15:38Compare our PNGLengthExtra and PNGDistExtra tables with the DEFLATE spec1 to ensure they look right
📖
21:103.2.5 Compressed blocks (length and distance codes)2
📖
21:103.2.5 Compressed blocks (length and distance codes)2
📖
21:103.2.5 Compressed blocks (length and distance codes)2
📖
23:10Scrutinise the length table building code in ParsePNG()
📖
23:10Scrutinise the length table building code in ParsePNG()
📖
23:10Scrutinise the length table building code in ParsePNG()
📖
25:14Assert in ParsePNG() that the LenCount <= number of items in the LitLenDistTable
25:14Assert in ParsePNG() that the LenCount <= number of items in the LitLenDistTable
25:14Assert in ParsePNG() that the LenCount <= number of items in the LitLenDistTable
25:33Continue to scrutinise the Huffman decoding code in ParsePNG()
📖
25:33Continue to scrutinise the Huffman decoding code in ParsePNG()
📖
25:33Continue to scrutinise the Huffman decoding code in ParsePNG()
📖
28:24Assert in ParsePNG() that the DecompressedPixelsEnd does not get exceeded
28:24Assert in ParsePNG() that the DecompressedPixelsEnd does not get exceeded
28:24Assert in ParsePNG() that the DecompressedPixelsEnd does not get exceeded
29:21Run it and hit our Source + Len assertion
🏃
29:21Run it and hit our Source + Len assertion
🏃
29:21Run it and hit our Source + Len assertion
🏃
30:13Consider investigating the Huffman table calculation, before determining to nail down the literal length stuff
🗩
30:13Consider investigating the Huffman table calculation, before determining to nail down the literal length stuff
🗩
30:13Consider investigating the Huffman table calculation, before determining to nail down the literal length stuff
🗩
31:24Produce a smaller image that exhibits the bug
🎨
31:24Produce a smaller image that exhibits the bug
🎨
31:24Produce a smaller image that exhibits the bug
🎨
39:27Note that our bug exhibiting image contains multiple IDAT chunks
🏃
39:27Note that our bug exhibiting image contains multiple IDAT chunks
🏃
39:27Note that our bug exhibiting image contains multiple IDAT chunks
🏃
42:00Produce a 64×64 pixel image that probably can't be PNG compressed
🎨
42:00Produce a 64×64 pixel image that probably can't be PNG compressed
🎨
42:00Produce a 64×64 pixel image that probably can't be PNG compressed
🎨
44:52Run it on gimp_64x64.png to see that the image contains two IDAT chunks and exhibits the crash
🏃
44:52Run it on gimp_64x64.png to see that the image contains two IDAT chunks and exhibits the crash
🏃
44:52Run it on gimp_64x64.png to see that the image contains two IDAT chunks and exhibits the crash
🏃
45:205.3 "Chunk layout" and 11.2.4 "IDAT Image data"3
📖
45:205.3 "Chunk layout" and 11.2.4 "IDAT Image data"3
📖
45:205.3 "Chunk layout" and 11.2.4 "IDAT Image data"3
📖
48:5510.2 Compression of the sequence of filtered scanlines4
📖
48:5510.2 Compression of the sequence of filtered scanlines4
📖
48:5510.2 Compression of the sequence of filtered scanlines4
📖
50:17Run it and hit an assertion in HuffmanDecode() due to an invalid symbol
🏃
50:17Run it and hit an assertion in HuffmanDecode() due to an invalid symbol
🏃
50:17Run it and hit an assertion in HuffmanDecode() due to an invalid symbol
🏃
53:28Step through ConsumeSize() to realise that PeekBits() doesn't correctly operate across multiple IDAT chunks
🏃
53:28Step through ConsumeSize() to realise that PeekBits() doesn't correctly operate across multiple IDAT chunks
🏃
53:28Step through ConsumeSize() to realise that PeekBits() doesn't correctly operate across multiple IDAT chunks
🏃
54:09Fix PeekBits() and ConsumeSize() to correctly operate across multiple IDAT chunks
54:09Fix PeekBits() and ConsumeSize() to correctly operate across multiple IDAT chunks
54:09Fix PeekBits() and ConsumeSize() to correctly operate across multiple IDAT chunks
57:30Run it and again crash in HuffmanDecode() on an invalid symbol, although we did process more bits
🏃
57:30Run it and again crash in HuffmanDecode() on an invalid symbol, although we did process more bits
🏃
57:30Run it and again crash in HuffmanDecode() on an invalid symbol, although we did process more bits
🏃
59:05Crash ScriptedSandbox64.exe
🗹
59:05Crash ScriptedSandbox64.exe
🗹
59:05Crash ScriptedSandbox64.exe
🗹
59:52Continue to investigate our bug exhibited by gimp_64x64.png
🏃
59:52Continue to investigate our bug exhibited by gimp_64x64.png
🏃
59:52Continue to investigate our bug exhibited by gimp_64x64.png
🏃
1:02:51Assert at the end of ParsePNG() that the Dest == DecompressedPixels
1:02:51Assert at the end of ParsePNG() that the Dest == DecompressedPixels
1:02:51Assert at the end of ParsePNG() that the Dest == DecompressedPixels
1:03:16Run it and do not hit that assertion
🏃
1:03:16Run it and do not hit that assertion
🏃
1:03:16Run it and do not hit that assertion
🏃
1:03:34Determine that gimp_64x64.png crashes 9 bytes from the end, and investigate why
🏃
1:03:34Determine that gimp_64x64.png crashes 9 bytes from the end, and investigate why
🏃
1:03:34Determine that gimp_64x64.png crashes 9 bytes from the end, and investigate why
🏃
1:05:30Make PeekBits() print out BitBufferBeforeAdvance if it needs to advance the buffer
1:05:30Make PeekBits() print out BitBufferBeforeAdvance if it needs to advance the buffer
1:05:30Make PeekBits() print out BitBufferBeforeAdvance if it needs to advance the buffer
1:07:05Run it to see that there are 12 bits in the buffer but, more pressingly, that we do not handle fixed Huffman compressed chunks
🏃
1:07:05Run it to see that there are 12 bits in the buffer but, more pressingly, that we do not handle fixed Huffman compressed chunks
🏃
1:07:05Run it to see that there are 12 bits in the buffer but, more pressingly, that we do not handle fixed Huffman compressed chunks
🏃
1:08:06Enable ParsePNG() to handle fixed Huffman compressed chunks5
1:08:06Enable ParsePNG() to handle fixed Huffman compressed chunks5
1:08:06Enable ParsePNG() to handle fixed Huffman compressed chunks5
1:17:51Step into ParsePNG() and inspect the LitLenDistTable comparing it with the PNG spec6
🏃
1:17:51Step into ParsePNG() and inspect the LitLenDistTable comparing it with the PNG spec6
🏃
1:17:51Step into ParsePNG() and inspect the LitLenDistTable comparing it with the PNG spec6
🏃
1:19:17Determine to perform some difference tests
🗩
1:19:17Determine to perform some difference tests
🗩
1:19:17Determine to perform some difference tests
🗩
1:21:03Grab a screenshot of the stream7
📖
1:21:03Grab a screenshot of the stream7
📖
1:21:03Grab a screenshot of the stream7
📖
1:22:43Run okay on our captured screenshot
🏃
1:22:43Run okay on our captured screenshot
🏃
1:22:43Run okay on our captured screenshot
🏃
1:23:06Q&A
🗩
1:23:06Q&A
🗩
1:23:06Q&A
🗩
1:23:38mtsmox Q: Yeah, same bug
🗪
1:23:38mtsmox Q: Yeah, same bug
🗪
1:23:38mtsmox Q: Yeah, same bug
🗪
1:23:52vaualbus Q: You could use the ray casting code for save image files so we can see what happens. It should be a quick thing to do!
🗪
1:23:52vaualbus Q: You could use the ray casting code for save image files so we can see what happens. It should be a quick thing to do!
🗪
1:23:52vaualbus Q: You could use the ray casting code for save image files so we can see what happens. It should be a quick thing to do!
🗪
1:24:12Run the PNG reader successfully on our ray tracing image
🏃
1:24:12Run the PNG reader successfully on our ray tracing image
🏃
1:24:12Run the PNG reader successfully on our ray tracing image
🏃
1:25:49Credit rooctag for clarifying our understanding of the Paeth filter
🗩
1:25:49Credit rooctag for clarifying our understanding of the Paeth filter
🗩
1:25:49Credit rooctag for clarifying our understanding of the Paeth filter
🗩
1:26:33xxthebigfoxx Q: Did you purposely screenshot my message saying you are handsome?
🗪
1:26:33xxthebigfoxx Q: Did you purposely screenshot my message saying you are handsome?
🗪
1:26:33xxthebigfoxx Q: Did you purposely screenshot my message saying you are handsome?
🗪
1:26:42frostyninja Q: I think he meant save out the decoded PNGs out as a raw BMP so we can see the result?
🗪
1:26:42frostyninja Q: I think he meant save out the decoded PNGs out as a raw BMP so we can see the result?
🗪
1:26:42frostyninja Q: I think he meant save out the decoded PNGs out as a raw BMP so we can see the result?
🗪
1:27:24Pull WriteImage() in from ray.cpp and make ParsePNG() return an image_u32 for us to write out
1:27:24Pull WriteImage() in from ray.cpp and make ParsePNG() return an image_u32 for us to write out
1:27:24Pull WriteImage() in from ray.cpp and make ParsePNG() return an image_u32 for us to write out
1:32:27Inspect our written image to see that it is upside-down and incorrectly coloured
🎨
1:32:27Inspect our written image to see that it is upside-down and incorrectly coloured
🎨
1:32:27Inspect our written image to see that it is upside-down and incorrectly coloured
🎨
1:33:15Rename WriteImage() to WriteImageTopDownRGBA() and enable it to swap the rows, introducing SwapRAndB() to swap those colour channels
1:33:15Rename WriteImage() to WriteImageTopDownRGBA() and enable it to swap the rows, introducing SwapRAndB() to swap those colour channels
1:33:15Rename WriteImage() to WriteImageTopDownRGBA() and enable it to swap the rows, introducing SwapRAndB() to swap those colour channels
1:39:47Compare our written image with the original, to see that it is off-by-1 pixel vertically
🎨
1:39:47Compare our written image with the original, to see that it is off-by-1 pixel vertically
🎨
1:39:47Compare our written image with the original, to see that it is off-by-1 pixel vertically
🎨
1:43:05Fix typo in WriteImageTopDownRGBA()
1:43:05Fix typo in WriteImageTopDownRGBA()
1:43:05Fix typo in WriteImageTopDownRGBA()
1:43:20Compare our written image with the original to see that they match
🎨
1:43:20Compare our written image with the original to see that they match
🎨
1:43:20Compare our written image with the original to see that they match
🎨
1:44:09bobby1up Q: Isn't it true that the compiler's optimizations of your code and the way the CPU works can sometimes cause instructions to happen in a different order than you wrote them? If so, won't that screw up profiling measurements?
🗪
1:44:09bobby1up Q: Isn't it true that the compiler's optimizations of your code and the way the CPU works can sometimes cause instructions to happen in a different order than you wrote them? If so, won't that screw up profiling measurements?
🗪
1:44:09bobby1up Q: Isn't it true that the compiler's optimizations of your code and the way the CPU works can sometimes cause instructions to happen in a different order than you wrote them? If so, won't that screw up profiling measurements?
🗪
1:44:43tavqua Q: Can you quantify how fast you type?
🗪
🎲
1:44:43tavqua Q: Can you quantify how fast you type?
🗪
🎲
1:44:43tavqua Q: Can you quantify how fast you type?
🗪
🎲
1:44:59jacksonbanan Q: Would you say that 4coder is the ideal text editor?
🗪
1:44:59jacksonbanan Q: Would you say that 4coder is the ideal text editor?
🗪
1:44:59jacksonbanan Q: Would you say that 4coder is the ideal text editor?
🗪
1:45:32jacksonbanan Q: Also, how often do you work out? You're buff
🗪
🎲
1:45:32jacksonbanan Q: Also, how often do you work out? You're buff
🗪
🎲
1:45:32jacksonbanan Q: Also, how often do you work out? You're buff
🗪
🎲
1:45:40lkalinovcic Q: In the BMP write routine, I think you have a bug. You advance Row0 too soon
🗪
1:45:40lkalinovcic Q: In the BMP write routine, I think you have a bug. You advance Row0 too soon
🗪
1:45:40lkalinovcic Q: In the BMP write routine, I think you have a bug. You advance Row0 too soon
🗪
1:45:44enemymouse Q: Double-check the shifting is not a GIMP paster error
🗪
1:45:44enemymouse Q: Double-check the shifting is not a GIMP paster error
🗪
1:45:44enemymouse Q: Double-check the shifting is not a GIMP paster error
🗪
1:45:57jnog92 Q: Just joined a week ago and haven't had time to go through all the series. Can you say in overall what have you done on the project and what is left to do?
🗪
1:45:57jnog92 Q: Just joined a week ago and haven't had time to go through all the series. Can you say in overall what have you done on the project and what is left to do?
🗪
1:45:57jnog92 Q: Just joined a week ago and haven't had time to go through all the series. Can you say in overall what have you done on the project and what is left to do?
🗪
1:47:10bbbyan Q: Do you have any project recommendations for beginner-intermediate C programmers?
🗪
1:47:10bbbyan Q: Do you have any project recommendations for beginner-intermediate C programmers?
🗪
1:47:10bbbyan Q: Do you have any project recommendations for beginner-intermediate C programmers?
🗪
1:47:46ivereadthesequel Q: Seems a bit casual today, what's your favorite album?
🗪
🎲
1:47:46ivereadthesequel Q: Seems a bit casual today, what's your favorite album?
🗪
🎲
1:47:46ivereadthesequel Q: Seems a bit casual today, what's your favorite album?
🗪
🎲
1:49:54jessef Q: What is the craziest file format to parse, in your opinion?
🗪
1:49:54jessef Q: What is the craziest file format to parse, in your opinion?
🗪
1:49:54jessef Q: What is the craziest file format to parse, in your opinion?
🗪
1:50:54vaualbus Q: What is the most difficult file format to read? Have you ever try to read ttf files? And try doing a vector renderer for those in OpenGL?
🗪
1:50:54vaualbus Q: What is the most difficult file format to read? Have you ever try to read ttf files? And try doing a vector renderer for those in OpenGL?
🗪
1:50:54vaualbus Q: What is the most difficult file format to read? Have you ever try to read ttf files? And try doing a vector renderer for those in OpenGL?
🗪
1:51:08frostyninja Q: What's your favourite pasta dish?
🗪
🎲
1:51:08frostyninja Q: What's your favourite pasta dish?
🗪
🎲
1:51:08frostyninja Q: What's your favourite pasta dish?
🗪
🎲
1:51:41jacksonbanan Q: How come no one has made a solid debugger? Is it difficult?
🗪
1:51:41jacksonbanan Q: How come no one has made a solid debugger? Is it difficult?
🗪
1:51:41jacksonbanan Q: How come no one has made a solid debugger? Is it difficult?
🗪
1:52:34runamar Q: Will the game be only room based?
🗪
1:52:34runamar Q: Will the game be only room based?
🗪
1:52:34runamar Q: Will the game be only room based?
🗪
1:52:43quickshift_ Q: Bit off topic, but are you a musician? Didn't you write some music for Handmade Hero yourself?
🗪
🎲
1:52:43quickshift_ Q: Bit off topic, but are you a musician? Didn't you write some music for Handmade Hero yourself?
🗪
🎲
1:52:43quickshift_ Q: Bit off topic, but are you a musician? Didn't you write some music for Handmade Hero yourself?
🗪
🎲
1:52:54tavqua Q: This may be too in-depth of a question, but: how can I send data over the internet for a game that can be picked up in a code that I write
🗪
1:52:54tavqua Q: This may be too in-depth of a question, but: how can I send data over the internet for a game that can be picked up in a code that I write
🗪
1:52:54tavqua Q: This may be too in-depth of a question, but: how can I send data over the internet for a game that can be picked up in a code that I write
🗪
1:53:18thejimjames40 Q: Will we be parsing compiler debug output (DWARF?) for cool in-game debug stuff?
🗪
1:53:18thejimjames40 Q: Will we be parsing compiler debug output (DWARF?) for cool in-game debug stuff?
🗪
1:53:18thejimjames40 Q: Will we be parsing compiler debug output (DWARF?) for cool in-game debug stuff?
🗪
1:53:27enemymouse Q: 3ds is worse than psd?
🗪
1:53:27enemymouse Q: 3ds is worse than psd?
🗪
1:53:27enemymouse Q: 3ds is worse than psd?
🗪
1:53:47bbbyan Q: We've had a Handmade Ray bonus series, what about Handmade Asteroids?
🗪
1:53:47bbbyan Q: We've had a Handmade Ray bonus series, what about Handmade Asteroids?
🗪
1:53:47bbbyan Q: We've had a Handmade Ray bonus series, what about Handmade Asteroids?
🗪
1:53:52Call it a day
🗩
1:53:52Call it a day
🗩
1:53:52Call it a day
🗩