{"id":12773,"date":"2010-09-23T07:00:00","date_gmt":"2010-09-23T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2010\/09\/23\/you-must-flush-gdi-operations-when-switching-between-direct-access-and-gdi-access-and-direct-access-includes-other-parts-of-gdi\/"},"modified":"2010-09-23T07:00:00","modified_gmt":"2010-09-23T07:00:00","slug":"you-must-flush-gdi-operations-when-switching-between-direct-access-and-gdi-access-and-direct-access-includes-other-parts-of-gdi","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20100923-00\/?p=12773","title":{"rendered":"You must flush GDI operations when switching between direct access and GDI access, and direct access includes other parts of GDI"},"content":{"rendered":"<p>\nA customer was running into problems when accessing the pixels of\na DIB section.\nThey used the <code>HANDLE<\/code> parameter to\n<code>Create&shy;DIB&shy;Section<\/code> and created two bitmaps from the same\nunderlying memory.\nThose two bitmaps were then selected into corresponding DCs,\nand the customer found that changes to the pixels performed\nby writing via one DC\nwere not visible when read from the other DC.\n<\/p>\n<p>\nThe customer pointed out this clause in MSDN:\n<\/p>\n<blockquote CLASS=\"q\"><p>\nYou need to guarantee that the GDI subsystem has completed\nany drawing to a bitmap created by <code>Create&shy;DIB&shy;Section<\/code>\nbefore you draw to the bitmap yourself.\nAccess to the bitmap must be synchronized.\nDo this by calling the <code>Gdi&shy;Flush<\/code> function.\nThis applies to any use of the pointer to the bitmap bit values,\nincluding passing the pointer in calls\nto functions such as <code>Set&shy;DIBits<\/code>.\n<\/p><\/blockquote>\n<p>\nThe customer said,\n&#8220;The description says that it applies to cases\nwhere you modify the bits yourself through the direct memory pointer.\nBut all of our access is performed through HDCs;\nI would think GDI is smart enough to handle that,\nbut we&#8217;ve found that we still need to call <code>Gdi&shy;Flush<\/code>\nto get the two DCs back in sync.&#8221;\n<\/p>\n<p>\nWhat you ask GDI to do you have done yourself.\nThat&#8217;s why the documentation say <i>any use of the pointer<\/i>.\nSort of like in law, where in many causes you can be punished for\n&#8220;doing X or causing X to be done.&#8221;\nIf you induce somebody else to do X,\nyou&#8217;re in violation as much as if you had done X yourself.\n<\/p>\n<p>\nI doubt that every call to GDI ends\nwith a big loop that checks whether the bits\nit just modified also belong to some other GDI bitmap in the system.\n<\/p>\n<pre>\nGDIFinishAPI(HDC hdc)\n{\n if (IsDIBSection(GetCurrentObject(hdc, OBJ_BITMAP), &amp;ds)) {\n  EnumGdiObjects(FlushIfOverlap, &amp;ds));\n }\n}\nFlushIfOverlap(HGDIOBJ h, DIBSECTION *pds)\n{\n if (IsDIBSection(h, &amp;ds) &amp;&amp;\n     DIBSectionsReferToSameUnderlyingBits(pds, &amp;ds)) {\n  GdiFlush();\n }\n}\n<\/pre>\n<p>\nThat would seriously slow down all DIB section operations\nto cover a rare scenario that most people don&#8217;t realize is\neven possible to create.\nNot the best engineering tradeoff.\n<\/p>\n<p>\nThe point of the documentation is\nis that if you ask GDI to mess with the bits in the bitmap\nvia the <code>HDC<\/code>,\nyou must call <code>Gdi&shy;Flush<\/code>\nbefore anybody else tries to access those bits,\neven if that &#8220;somebody else&#8221; is another part of GDI.\nThe example of <code>Set&shy;DIBits<\/code> is an attempt to capture the\nsense of this requirement.\n<\/p>\n<p>\nTranslating into this specific scenario:\nYou must flush the pending changes whenever you switch between\n&#8220;GDI accesses bits through the DIB section created by this handle&#8221;\nand &#8220;the bits are accessed by anybody else.&#8221;\nAnd &#8220;anybody else&#8221; could be\n&#8220;GDI accesses bits through the DIB section created by a different handle.&#8221;\n<\/p>\n<p>\n<b>Bonus chatter<\/b>:\nWhat&#8217;s the deal with <code>Gdi&shy;Flush<\/code> anyway?\n<\/p>\n<p>\nAs a performance optimization, GDI performs &#8220;batching&#8221;\nof operations.\nWhen you ask GDI to perform an operation, it doesn&#8217;t always do it\nright away.\nInstead, it may choose to store the action in a buffer,\nand when the buffer gets full,\nit &#8220;flushes the batch&#8221; and sends the commands that it had been\nsaving up into kernel mode for execution.\n(This idea of buffering up operations and submitting them as a batch\nis hardly new to GDI.\nThe C stdio library does it, and\nin networking, a variation of it goes by the name\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/larryosterman\/archive\/2004\/08\/05\/209160.aspx\">\nNagle&#8217;s Algorithm<\/a>.)\n<\/p>\n<p>\nGDI also flushes the batch when necessary in order to preserve semantics;\nfor example, if you call <code>Gradient&shy;Fill<\/code> and follow it\nwith a call to <code>Get&shy;Pixel<\/code>,\nGDI needs to flush out the <code>Gradient&shy;Fill<\/code> before\nissuing the <code>Get&shy;Pixel<\/code> so that the pixels that get\nread match the pixels that were written.\n(A much more common case of just-in-time flushing is\nwhere you <code>Bit&shy;Blt<\/code> the results out of the bitmap\ninto another device context.)\n<\/p>\n<p>\nThis behind-the-scenes optimization works great with one exception:\nDIB sections.\nSince the memory for DIB sections is directly visible,\nGDI doesn&#8217;t get a chance to sneak a call to <code>Gdi&shy;Flush<\/code>\nbefore you issue your &#8220;mov eax, [esi]&#8221; instruction.\nHence the clause in MSDN explaining that when you switch between\nGDI access and direct access,\nyou need to call <code>Gdi&shy;Flush<\/code> to get all pending operations\nout of the buffer so that the bits in memory match the operations\nyou performed.\n<\/p>\n<p>\nMany years ago,\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2003\/09\/15\/54925.aspx\">\nwe saw another case where we had to compensate for GDI batching<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A customer was running into problems when accessing the pixels of a DIB section. They used the HANDLE parameter to Create&shy;DIB&shy;Section and created two bitmaps from the same underlying memory. Those two bitmaps were then selected into corresponding DCs, and the customer found that changes to the pixels performed by writing via one DC were [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-12773","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>A customer was running into problems when accessing the pixels of a DIB section. They used the HANDLE parameter to Create&shy;DIB&shy;Section and created two bitmaps from the same underlying memory. Those two bitmaps were then selected into corresponding DCs, and the customer found that changes to the pixels performed by writing via one DC were [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/12773","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=12773"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/12773\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=12773"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=12773"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=12773"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}