We are currently migrating Bugzilla to GitHub issues.
Any changes made to the bug tracker now will be lost, so please do not post new bugs or make changes to them.
When we're done, all bug URLs will redirect to their equivalent location on the new bug tracker.

Bug 2421

Summary: SDL_RenderCopyEx off by one when rotating by 90 and -90.
Product: SDL Reporter: chasesan
Component: renderAssignee: Sam Lantinga <slouken>
Status: RESOLVED FIXED QA Contact: Sam Lantinga <slouken>
Severity: normal    
Priority: P2 CC: jizc, ngolbaz, sylvain.becker, trygve.vea
Version: HG 2.1   
Hardware: x86_64   
OS: Windows 7   
Attachments: Test case, cycle through renderers with n
Image used by test case
patch to solve this issue in for renderer opengles
D3D patch
Updated patch for direct3d renderers
test case for rotations
screenshot with software renderer

Description chasesan 2014-02-26 17:08:22 UTC
When using SDL_RenderCopyEx, I get a problem on some platforms where the output is offset by +/-1 on other platforms and not on others. I tried it with a center of both 0,0 (and offsetting by width/height) and NULL (for centered).

The rotation involved is 90, and/or -90 rotation. The rotation was a constant, no arithmetic was involved when inputting it into SDL_RenderCopyEx.

This occurred with 32x32, 24x24, and 16x16 texture sizes. I apologize that I don't have more precise information, as I received the information as a bug report myself. But I have tracked the problem down to here.

My program requires pixel perfect alignment on several different platforms, so this is something of a showstopper for me.
Comment 1 Sam Lantinga 2014-03-01 18:33:54 UTC
Can you attach a minimal example with images, and describe which platforms work and which don't?

Thanks!
Comment 2 Trygve Vea 2014-06-22 11:53:47 UTC
Created attachment 1698 [details]
Test case, cycle through renderers with n

Requires sdl-bug-2421.bmp to run
Comment 3 Trygve Vea 2014-06-22 11:54:09 UTC
Created attachment 1699 [details]
Image used by test case
Comment 4 Trygve Vea 2014-06-22 11:58:46 UTC
I'm not the original poster for this bug, but I've run into it myself.  I work around the bug by forcing the OpenGL renderer.

I've run some tests.  As far as I can tell, OpenGL is the only renderer that work as expected.

The tests I've made can be viewed here: https://www.dropbox.com/sh/n44e2jvg7dydd3m/AAA5inPLrWLZ36ncjX_C5fz9a

Used test case attached.
Comment 5 Sylvain 2014-06-29 09:15:25 UTC
I tried your test case, and it's nice to switch renderer so easily.
On my linux, this is working for : software, opengl, opengles2.

opengles1 is not working, because the rendered failed and I see garbage. To double check the test case, I would just recommend to check to the Window/Render creation : 

 27   w = SDL_CreateWindow(i.name, 32, 32, 320, 240, 0);
 28   if (w == NULL)
 29   {
 30     printf("Failed to create windows: %s\n", SDL_GetError());
 31   }
 32   r = SDL_CreateRenderer(w, cur_renderer, SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
 33   if (r == NULL)
 34   {
 35     printf("Failed to create render: %s\n", SDL_GetError());
 36   }
Comment 6 Trygve Vea 2014-06-29 12:58:07 UTC
(In reply to Sylvain from comment #5)
> I tried your test case, and it's nice to switch renderer so easily.
> On my linux, this is working for : software, opengl, opengles2.

From what I read, you got a different result than me when using the software renderer in Linux.  That's very odd.  When I tested SDL 2.0.3, I got this result: https://www.dropbox.com/sh/n44e2jvg7dydd3m/AAB_uJDLmNn08Aj3FGTTPVqUa/linux-software.png

And, you are not supposed to see the red squares if the white square is rendered in the correct position.

Can you verify what your result was?

> opengles1 is not working, because the rendered failed and I see garbage. To
> double check the test case, I would just recommend to check to the
> Window/Render creation : 
> 
>  27   w = SDL_CreateWindow(i.name, 32, 32, 320, 240, 0);
>  28   if (w == NULL)
>  29   {
>  30     printf("Failed to create windows: %s\n", SDL_GetError());
>  31   }
>  32   r = SDL_CreateRenderer(w, cur_renderer,
> SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC);
>  33   if (r == NULL)
>  34   {
>  35     printf("Failed to create render: %s\n", SDL_GetError());
>  36   }

That makes sense.

If SDL_CreateRenderer fails, it may be a new bug.  Have you posted information about that somewhere?
Comment 7 Sylvain 2014-06-29 17:18:03 UTC
Trygve,

I am not using 2.0.3 but the SDL trunk directly.

For the renderers software / opengl and opengles2, it is fine : I see the white squares rotated (I changed a little bit the image so I see the rotation!), and no "red" frame, which means the rotation is correctly positioned.

So it's working correctly for me on linux.


For, opengles, I got an error : 
"Failed to create render: Could not create GL context GLXBadProfileARB"
That happens in X11_GL_CreateContext. It seems to create a 3.0 context? 
That's fore sure a different issue. (I will report it)
Comment 8 Sylvain 2014-06-30 14:47:20 UTC
Trying with older version, it seems it was broken (red square).
But latest trunk, it seems fine.

Trygve, give a try with the latest trunk.
Comment 9 Sylvain 2014-06-30 17:28:13 UTC
Gabriel solved my "opengles" creation problem.

So I can give the result : 

I see the red-square for the "opengles" renderer, which means the problem is there for this renderer.
Comment 10 Sylvain 2014-06-30 20:28:53 UTC
Created attachment 1719 [details]
patch to solve this issue in for renderer opengles

It appears the RenderCopyEx is done as expected, 
this is the red rectangle which is not correctly positionned !

So, here's patch with a 0.5 float increment, like for opengles2, for DrawLines, and also Draw Points.
Comment 11 Sylvain 2014-06-30 20:41:54 UTC
Maybe same patch to apply to Direct3D renderers.
Comment 12 Sam Lantinga 2014-07-08 06:28:15 UTC
Sylvain, I applied your patch, thanks!
https://hg.libsdl.org/SDL/rev/bc47cf4c679d

Direct3D doesn't have this issue, due to coordinate definition differences.

Please reopen this bug if it's still active for any other renderer.
Comment 13 Trygve Vea 2014-07-08 18:48:24 UTC
(In reply to Sam Lantinga from comment #12)
> Sylvain, I applied your patch, thanks!
> https://hg.libsdl.org/SDL/rev/bc47cf4c679d
> 
> Direct3D doesn't have this issue, due to coordinate definition differences.
> 
> Please reopen this bug if it's still active for any other renderer.

I'm quite sure that this bug is still valid, also for Direct3D.  Have you checked the attached test case?  I just ran it against a newly built SDL2.dll, and it returns the same results as it did with the screenshots I link to earlier in this report.

I should probably write a proper test for this, it's a very subtle thing - but not as subtle if you render to a texture with low resolution.
Comment 14 Sam Lantinga 2014-07-09 08:41:30 UTC
I see this also fails for the software renderer. I'll investigate when I have time.

Thanks!
Comment 15 Nader Golbaz 2014-07-22 15:20:24 UTC
Created attachment 1782 [details]
D3D patch
Comment 16 Trygve Vea 2014-07-22 16:07:25 UTC
(In reply to Nader Golbaz from comment #15)
> Created attachment 1782 [details]
> D3D patch

I just tested the patch, and can confirm that it works for direct3d.  I can not confirm that it works for direct3d11.

I applied the patch to current trunk; while testing, I also noticed that this looks like less of a problem on the software renderer now - only the top right box is rendered at the wrong position.
Comment 17 Nader Golbaz 2014-07-22 16:48:39 UTC
Patch for d3d11 is not correct. apparently there is another bug in D3D11_RenderDrawLines.
Comment 18 Nader Golbaz 2014-07-31 20:08:55 UTC
Created attachment 1800 [details]
Updated patch for direct3d renderers
Comment 19 Sylvain 2016-08-07 13:35:23 UTC
Created attachment 2545 [details]
test case for rotations

Here's a test-case to see an offset of 1, when rotating with software renderer.


It fails for the "software" renderer: offset on x/y of +2, and also the texture seems sometime truncated.
But it works for opengl, opengles and opengles2 renderers.
Comment 20 Sylvain 2016-08-07 13:38:41 UTC
Created attachment 2546 [details]
screenshot with software renderer

Here's a screenshot:

1st: initial texture.
2nd: 90deg : shifted +1 on x axis. truncated last column.
3rd: 180deg: shifted +2 on x axis, shifted +2 on y axis.
4th: 270deg: shifted +2 on x axis.
Comment 21 Sylvain 2016-11-05 14:58:40 UTC
The software rendering part is fixed by this commit: https://hg.libsdl.org/SDL/rev/1e1ce9f6d215
Comment 22 Sam Lantinga 2016-11-06 17:26:04 UTC
Verified test case with direct3d, direct3d11, opengl, opengles2, and software renderers.

Thanks!
Comment 23 Nader Golbaz 2016-11-06 22:14:37 UTC
In the case of D3D11, we need drawing last point separately.

--- SDL_render_d3d11.c
+++ SDL_render_d3d11.c
@@ -2576,7 +2576,12 @@
         NULL);
 
     D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, count);
-    D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, count);
+
+    if (points[0].x != points[count - 1].x || points[0].y != points[count - 1].y) {
+        ID3D11DeviceContext_IASetPrimitiveTopology(rendererData->d3dContext, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
+        ID3D11DeviceContext_Draw(rendererData->d3dContext, 1, count - 1);
+    }
+
     SDL_stack_free(vertices);
     return 0;
 }
Comment 24 Sam Lantinga 2016-11-06 23:20:26 UTC
Got it, thanks!
https://hg.libsdl.org/SDL/rev/f781e05bcfb5