<?xml version="1.0"?>
<rss version="2.0">
	<channel>
		<title>_al_stretch_blit questionable behaviour</title>
		<link>http://www.allegro.cc/forums/view/607099</link>
		<description>Allegro.cc Forum Thread</description>
		<webMaster>matthew@allegro.cc (Matthew Leverton)</webMaster>
		<lastBuildDate>Sun, 22 May 2011 11:16:55 +0000</lastBuildDate>
	</channel>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Due to an error with how I called stretch_blit, I wound up debugging and I discovered that on most platforms in all cases stretch_blit calls _al_stretch_blit, so naturally I was looking it over to see if anything was wrong with it. I came to the lines where it actually stretches the bitmap and I discovered this line (allegro/src/c/cstretch.c line 404) :
</p><div class="source-code snippet"><div class="inner"><pre>      <span class="k2">(</span><span class="k3">*</span>stretch_line<span class="k2">)</span><span class="k2">(</span><a href="http://www.allegro.cc/manual/bmp_write_line"><span class="a">bmp_write_line</span></a><span class="k2">(</span>dst, y<span class="k2">)</span> <span class="k3">+</span> dxofs, src-&gt;line<span class="k2">[</span>sy<span class="k2">]</span> <span class="k3">+</span> sxofs<span class="k2">)</span><span class="k2">;</span>
</pre></div></div><p>

<s>Now the destination bitmap is guaranteed to be a memory bitmap by these lines</s> (src/c/cstretch.c lines 259-263) - actually if do_stretch_blit is NULL in the source bitmap&#39;s vtable then the destination could be any kind of bitmap.
</p><div class="source-code snippet"><div class="inner"><pre>   <span class="c">/* vtable hook; not called if dest is a memory surface */</span>   
   <span class="k1">if</span> <span class="k2">(</span>src-&gt;vtable-&gt;do_stretch_blit <span class="k3">&amp;</span><span class="k3">&amp;</span> <span class="k3">!</span><a href="http://www.allegro.cc/manual/is_memory_bitmap"><span class="a">is_memory_bitmap</span></a><span class="k2">(</span>dst<span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span>
      src-&gt;vtable-&gt;do_stretch_blit<span class="k2">(</span>src, dst, sx, sy, sw, sh, dx, dy, dw, dh, masked<span class="k2">)</span><span class="k2">;</span>
      <span class="k1">return</span><span class="k2">;</span>
   <span class="k2">}</span>
</pre></div></div><p>

The problem is that the type of the source bitmap is not checked for at all, and it is accessed using the line pointer, which the manual says it is not safe to do for non memory bitmaps :
</p><div class="quote_container"><div class="title">The manual said:</div><div class="quote"><p>
The <u>simplest approach will only work with memory bitmaps</u> (obtained from create_bitmap(), grabber datafiles, and image files) and sub-bitmaps of memory bitmaps. <u>This uses a table of char pointers, called `line&#39;</u>, which is a part of the bitmap structure and contains pointers to the start of each line of the image.
</p></div></div><p>

The manual goes on to elaborate a little bit :
</p><div class="quote_container"><div class="title">The manual said:</div><div class="quote"><p>
If you want to write to the screen as well as to memory bitmaps, you need to use some helper macros, because the video memory may not be part of your normal address space. <u>This simple routine will work for any linear screen, eg. a VESA linear framebuffers: </u>
</p><div class="source-code snippet"><div class="inner"><pre>   <span class="k1">void</span> linear_screen_putpixel<span class="k2">(</span><a href="http://www.allegro.cc/manual/BITMAP"><span class="a">BITMAP</span></a> <span class="k3">*</span>bmp, <span class="k1">int</span> x, <span class="k1">int</span> y, <span class="k1">int</span> color<span class="k2">)</span>
   <span class="k2">{</span>
      bmp_select<span class="k2">(</span>bmp<span class="k2">)</span><span class="k2">;</span>
      bmp_write8<span class="k2">(</span><span class="k2">(</span><span class="k1">unsigned</span> <span class="k1">long</span><span class="k2">)</span>bmp-&gt;line<span class="k2">[</span>y<span class="k2">]</span><span class="k3">+</span>x, color<span class="k2">)</span><span class="k2">;</span>
   <span class="k2">}</span>
</pre></div></div><p>
</p></div></div><p>
So in this case, they use the line pointer to write to the screen, but the manual goes on and says when this will not work :
</p><div class="quote_container"><div class="title">The manual said:</div><div class="quote"><p>
This still won&#39;t work in banked SVGA modes, however, <u>or on platforms like Windows that do special processing inside the bank switching functions</u>. For more flexible access to bitmap memory, you need to call the following routines <b><i>(They&#39;re referring to bmp_write_line, bmp_read_line, bmp_unwrite_line)</i></b>. They are implemented as inline assembler routines, so they are not as inefficient as they might seem. If the bitmap doesn&#39;t require bank switching (ie. it is a memory bitmap, mode 13h screen, etc), these functions just return bmp-&gt;line[line].
</p></div></div><p>

However, I tested stretch_blit on Vista using a video bitmap as the source and a memory bitmap as the destination, and nothing bad happened at all, so I&#39;m confused. </p><p>The manual says it&#39;s wrong to use line pointers on non memory bitmaps, but _al_stretch_blit does exactly that.</p><p>So is it safe to use line pointers on any bitmap, or isn&#39;t it? <img src="http://www.allegro.cc/forums/smileys/huh.gif" alt="???" /></p><p><b>Append</b><br />Well, I looked at stretch_blit in the manual, and it says :
</p><div class="quote_container"><div class="title">The manual said:</div><div class="quote"><p>
Moreover, the source must be a memory bitmap.
</p></div></div><p>
However, if that is true, then why are there entries in gfx_capabilities for the following flags :
</p><div class="quote_container"><div class="title">The manual said:</div><div class="quote"><p>
GFX_HW_VRAM_STRETCH_BLIT:<br />Indicates that stretched blitting of video bitmaps onto the screen is implemented using hardware acceleration. </p><p>GFX_HW_SYS_STRETCH_BLIT:<br />Indicates that stretched blitting of system bitmaps onto the screen is implemented using hardware acceleration. </p><p>GFX_HW_VRAM_STRETCH_BLIT_MASKED:<br />Indicates that masked stretched blitting (including stretch_sprite) of video bitmaps onto the screen is implemented using hardware acceleration. NOTE: some display drivers may show artifacts when this function is used. If the image does not look correct try updating your video drivers. </p><p>GFX_HW_SYS_STRETCH_BLIT_MASKED:<br />Indicates that masked stretched blitting (including stretch_sprite) of system bitmaps onto the screen is implemented using hardware acceleration. NOTE: some display drivers may show artefact&#39;s when this function is used. If the image does not look correct try updating your video drivers. 
</p></div></div><p>

This indicates that the source may be a system or video bitmap when drawing onto another video bitmap. I wish the manual would stop contradicting itself.</p><p>Is it correct to assume that given all the information so far, that when the destination bitmap is a memory bitmap, then the source bitmap can (should) only be a memory bitmap? That would fit _al_stretch_blit&#39;s assumption about using a line pointer on the source bitmap, however, the source code of _al_stretch_blit should reflect that if it is true.</p><p><b>Append 2</b><br />Bueller?</p><p><b>Append 3</b><br />So, to review :<br />1) The manual says it&#39;s wrong to use line pointers on non memory bitmaps, but _al_stretch_blit does exactly that.<br />2) The manual says that for stretch_blit that the source must be a memory bitmap, but there are flags in gfx_capabilities that indicate the possibility of hardware accelerated stretching from system and video bitmaps to video bitmaps.</p><p>Apparent options :<br />1) Change the manual entry for stretch_blit to say that the source bitmap must be a memory bitmap except when gfx_capabilities has the following flags set (as appropriate) : <br />GFX_HW_VRAM_STRETCH_BLIT<br />GFX_HW_SYS_STRETCH_BLIT<br />GFX_HW_VRAM_STRETCH_BLIT_MASKED<br />GFX_HW_SYS_STRETCH_BLIT_MASKED</p><p>2) Modify _al_stretch_blit to work for any combination of bitmap types. This would require using bmp_read_line on the source to read a line into a temporary array and then stretching the line normally.</p><p>3) Modify _al_stretch_blit to ASSERT that the source is a memory bitmap.</p><p>So, any opinions on this?</p><p><b>Append 4</b><br />Since I haven&#39;t gotten any replies to this, I guess I will take it to the [AD] mailing list and see if I get any replies there.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Edgar Reynaldo)</author>
		<pubDate>Mon, 16 May 2011 09:24:49 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I vaguely recall fixing stretch_blit a few years back when there was an unrelated bug in it. From what I remember, on some platforms, my game would crash when using a non memory source bitmap. I can&#39;t remember if it was DOS or Linux console or anything, just a vague recollection of bad things happening.</p><p>My suggestion would be to document those display flags and say that they mean the hardware is capable of it but Allegro is not, for a quick fix. Now if you could come up with a real fix, that allowed any type of bitmap to be used, that would be a better fix, <u>providing</u> that there is no significant speed decrease. This function is highly optimized right now and I&#39;m going to guess that on a low end machine (which I think is now the main target for Allegro 4) it would make a significant difference to all variations if you made it more generic. But as I say, if you can do it without hurting performance, that would be great.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Trent Gamblin)</author>
		<pubDate>Mon, 16 May 2011 09:40:26 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><div class="quote_container"><div class="title"><a href="http://www.allegro.cc/forums/thread/607099/917645#target">Trent Gamblin</a> said:</div><div class="quote"><p>
My suggestion would be to document those display flags and say that they mean the hardware is capable of it but Allegro is not, for a quick fix.
</p></div></div><p>
Isn&#39;t that a contradiction though? The flags indicate that Allegro is capable of it, as far as I know. They do say that the destination is the screen though, and not just any video bitmap, but I don&#39;t personally know if there is a difference.</p><div class="quote_container"><div class="title">Trent Gamblin said:</div><div class="quote"><p>
Now if you could come up with a real fix, that allowed any type of bitmap to be used, that would be a better fix, providing that there is no significant speed decrease. 
</p></div></div><p>

Technically, it should be as simple as using an if else statement to preserve the code that is currently there for memory source bitmaps and allow for the source to be a system or video bitmap. The only other thing necessary would be to make a copy of the line from the source system/video bitmap and pass that to the &#39;stretch_line&#39; function pointer instead of &#39;src-&gt;line[sy] + sxofs&#39;.</p><p>The code I&#39;m referring to is at the end of src/c/cstretch.c in the al_stretch_blit function on lines 399-413 :
</p><div class="source-code"><div class="toolbar"><span class="name">cstretch.c</span><span class="button numbers"><b>#</b></span><span class="button select">Select</span><span class="button expand">Expand</span></div><div class="inner"><span class="number"> 399</span>   <span class="c">/* Stretch it */</span>
<span class="number"> 400</span>
<span class="number"> 401</span>   bmp_select<span class="k2">(</span>dst<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 402</span>
<span class="number"> 403</span>   <span class="k1">for</span> <span class="k2">(</span><span class="k2">;</span> y <span class="k3">&lt;</span> dyend<span class="k2">;</span> y<span class="k3">+</span><span class="k3">+</span>, sy <span class="k3">+</span><span class="k3">=</span> syinc<span class="k2">)</span> <span class="k2">{</span>
<span class="number"> 404</span>      <span class="k2">(</span><span class="k3">*</span>stretch_line<span class="k2">)</span><span class="k2">(</span><a href="http://www.allegro.cc/manual/bmp_write_line"><span class="a">bmp_write_line</span></a><span class="k2">(</span>dst, y<span class="k2">)</span> <span class="k3">+</span> dxofs, src-&gt;line<span class="k2">[</span>sy<span class="k2">]</span> <span class="k3">+</span> sxofs<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 405</span>      <span class="k1">if</span> <span class="k2">(</span>yc <span class="k3">&lt;</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span> <span class="k2">{</span>
<span class="number"> 406</span>   sy<span class="k3">+</span><span class="k3">+</span><span class="k2">;</span>
<span class="number"> 407</span>   yc <span class="k3">+</span><span class="k3">=</span> ycinc<span class="k2">;</span>
<span class="number"> 408</span>      <span class="k2">}</span>
<span class="number"> 409</span>      <span class="k1">else</span>
<span class="number"> 410</span>      yc <span class="k3">-</span><span class="k3">=</span> ycdec<span class="k2">;</span>
<span class="number"> 411</span>   <span class="k2">}</span>
<span class="number"> 412</span>   
<span class="number"> 413</span>   <a href="http://www.allegro.cc/manual/bmp_unwrite_line"><span class="a">bmp_unwrite_line</span></a><span class="k2">(</span>dst<span class="k2">)</span><span class="k2">;</span>
</div></div><p>

It would become something like :
</p><div class="source-code"><div class="toolbar"><span class="button numbers"><b>#</b></span><span class="button select">Select</span><span class="button expand">Expand</span></div><div class="inner"><span class="number">  1</span>   <span class="c">/* Stretch it */</span>
<span class="number">  2</span>   <span class="k1">if</span> <span class="k2">(</span><a href="http://www.allegro.cc/manual/is_memory_bitmap"><span class="a">is_memory_bitmap</span></a><span class="k2">(</span>src<span class="k2">)</span><span class="k2">)</span> <span class="k2">{</span>
<span class="number">  3</span>      bmp_select<span class="k2">(</span>dst<span class="k2">)</span><span class="k2">;</span>
<span class="number">  4</span>   
<span class="number">  5</span>      <span class="k1">for</span> <span class="k2">(</span><span class="k2">;</span> y <span class="k3">&lt;</span> dyend<span class="k2">;</span> y<span class="k3">+</span><span class="k3">+</span>, sy <span class="k3">+</span><span class="k3">=</span> syinc<span class="k2">)</span> <span class="k2">{</span>
<span class="number">  6</span>         <span class="k2">(</span><span class="k3">*</span>stretch_line<span class="k2">)</span><span class="k2">(</span><a href="http://www.allegro.cc/manual/bmp_write_line"><span class="a">bmp_write_line</span></a><span class="k2">(</span>dst, y<span class="k2">)</span> <span class="k3">+</span> dxofs, src-&gt;line<span class="k2">[</span>sy<span class="k2">]</span> <span class="k3">+</span> sxofs<span class="k2">)</span><span class="k2">;</span>
<span class="number">  7</span>         <span class="k1">if</span> <span class="k2">(</span>yc <span class="k3">&lt;</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span> <span class="k2">{</span>
<span class="number">  8</span>      sy<span class="k3">+</span><span class="k3">+</span><span class="k2">;</span>
<span class="number">  9</span>      yc <span class="k3">+</span><span class="k3">=</span> ycinc<span class="k2">;</span>
<span class="number"> 10</span>         <span class="k2">}</span>
<span class="number"> 11</span>         <span class="k1">else</span>
<span class="number"> 12</span>      yc <span class="k3">-</span><span class="k3">=</span> ycdec<span class="k2">;</span>
<span class="number"> 13</span>      <span class="k2">}</span>
<span class="number"> 14</span>   
<span class="number"> 15</span>      <a href="http://www.allegro.cc/manual/bmp_unwrite_line"><span class="a">bmp_unwrite_line</span></a><span class="k2">(</span>dst<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 16</span>   <span class="k2">}</span>
<span class="number"> 17</span>   <span class="k1">else</span> <span class="k2">{</span>
<span class="number"> 18</span>      <span class="c">// get bits per pixel, multiply times width, add padding so it aligns with </span>
<span class="number"> 19</span>      <span class="c">// a multiple of four</span>
<span class="number"> 20</span>      <span class="k1">char</span><span class="k3">*</span> srccopy <span class="k3">=</span> <span class="k2">(</span><span class="k1">char</span><span class="k3">*</span><span class="k2">)</span><a href="http://www.delorie.com/djgpp/doc/libc/libc_551.html" target="_blank">malloc</a><span class="k2">(</span>size <span class="k3">+</span> pad<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 21</span>      <span class="k1">if</span> <span class="k2">(</span><span class="k3">!</span>srccopy<span class="k2">)</span> <span class="k2">{</span><span class="k1">return</span><span class="k2">;</span><span class="k2">}</span>
<span class="number"> 22</span>      <span class="k1">for</span> <span class="k2">(</span><span class="k2">;</span> y <span class="k3">&lt;</span> dyend<span class="k2">;</span> y<span class="k3">+</span><span class="k3">+</span>, sy <span class="k3">+</span><span class="k3">=</span> syinc<span class="k2">)</span> <span class="k2">{</span>
<span class="number"> 23</span>         bmp_select<span class="k2">(</span>src<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 24</span>         <a href="http://www.delorie.com/djgpp/doc/libc/libc_566.html" target="_blank">memcpy</a><span class="k2">(</span>srccopy , <span class="k2">(</span><span class="k1">char</span><span class="k3">*</span><span class="k2">)</span><a href="http://www.allegro.cc/manual/bmp_read_line"><span class="a">bmp_read_line</span></a><span class="k2">(</span>src , sy<span class="k2">)</span> , size<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 25</span>         bmp_select<span class="k2">(</span>dst<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 26</span>
<span class="number"> 27</span>         <span class="k2">(</span><span class="k3">*</span>stretch_line<span class="k2">)</span><span class="k2">(</span><a href="http://www.allegro.cc/manual/bmp_write_line"><span class="a">bmp_write_line</span></a><span class="k2">(</span>dst, y<span class="k2">)</span> <span class="k3">+</span> dxofs, srccopy <span class="k3">+</span> sxofs<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 28</span>         <span class="k1">if</span> <span class="k2">(</span>yc <span class="k3">&lt;</span><span class="k3">=</span> <span class="n">0</span><span class="k2">)</span> <span class="k2">{</span>
<span class="number"> 29</span>            sy<span class="k3">+</span><span class="k3">+</span><span class="k2">;</span>
<span class="number"> 30</span>            yc <span class="k3">+</span><span class="k3">=</span> ycinc<span class="k2">;</span>
<span class="number"> 31</span>         <span class="k2">}</span>
<span class="number"> 32</span>         <span class="k1">else</span>
<span class="number"> 33</span>            yc <span class="k3">-</span><span class="k3">=</span> ycdec<span class="k2">;</span>
<span class="number"> 34</span>      <span class="k2">}</span>
<span class="number"> 35</span>      <a href="http://www.allegro.cc/manual/bmp_unwrite_line"><span class="a">bmp_unwrite_line</span></a><span class="k2">(</span>src<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 36</span>      <a href="http://www.allegro.cc/manual/bmp_unwrite_line"><span class="a">bmp_unwrite_line</span></a><span class="k2">(</span>dst<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 37</span>      <a href="http://www.delorie.com/djgpp/doc/libc/libc_350.html" target="_blank">free</a><span class="k2">(</span>srccopy<span class="k2">)</span><span class="k2">;</span>
<span class="number"> 38</span>   <span class="k2">}</span>
</div></div><p>

</p><div class="quote_container"><div class="title">Trent Gamblin said:</div><div class="quote"><p>
This function is highly optimized right now and I&#39;m going to guess that on a low end machine (which I think is now the main target for Allegro 4) it would make a significant difference to all variations if you made it more generic. But as I say, if you can do it without hurting performance, that would be great.
</p></div></div><p>
It may be slightly slower due to the allocation and memcpy, but that&#39;s for stretching from system and video bitmaps where it was previously unsupported, and the original routine is only altered by an if check, which is negligible.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Edgar Reynaldo)</author>
		<pubDate>Mon, 16 May 2011 10:33:00 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>Ok.. well create patches for this and the ddraw alpha issue and I&#39;ll test them and apply them. I plan to be doing a little more 4.4 development when I get the motherboard Matthew sent me.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Trent Gamblin)</author>
		<pubDate>Mon, 16 May 2011 21:56:49 +0000</pubDate>
	</item>
	<item>
		<description><![CDATA[<div class="mockup v2"><p>I haven&#39;t forgotten about this if you were wondering, I just haven&#39;t gotten to it yet. What with Allegro 4.4.2 coming out recently, there&#39;s no real rush anyway.
</p></div>]]>
		</description>
		<author>no-reply@allegro.cc (Edgar Reynaldo)</author>
		<pubDate>Sun, 22 May 2011 11:16:55 +0000</pubDate>
	</item>
</rss>
