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 2887

Summary: Cursor transparency problem on Linux AMD
Product: SDL Reporter: fabio <pedretti.fabio>
Component: videoAssignee: Ryan C. Gordon <icculus>
Status: ASSIGNED --- QA Contact: Sam Lantinga <slouken>
Severity: normal    
Priority: P2 CC: andreas, bb51, eriktorbjorn, pedretti.fabio, philip, philipp.wiesemann
Version: 2.0.2   
Hardware: x86   
OS: Linux   
URL: http://trac.wildfiregames.com/ticket/2823

Description fabio 2015-02-22 12:28:02 UTC
After 0ad started to offer sdl2 support I tried it on Linux, and while it mostly works fine, I noticed that the mouse cursor has a problem, showing a white box when it should be transparent, see this image: http://trac.wildfiregames.com/raw-attachment/ticket/2823/sdl2-cursor.png

I originally reported the bug here:
http://trac.wildfiregames.com/ticket/2823

According to these:
https://forums.libsdl.org/viewtopic.php?t=10422
http://www.grimrock.net/forum/viewtopic.php?f=12&t=4583
there are other users and games with a similar issue, that happens on Linux with AMD cards (both open and fglrx drivers).
Comment 1 Ryan C. Gordon 2015-02-24 04:28:01 UTC
Ok, I don't know if this is a driver bug or our bug, but the PNG for that buggy cursor _does_ in fact have a full-white block (r,g,b are all == 255) exactly where it's showing in the screenshot, even though it has an alpha of 0.

The parts that appear to mask out correctly are closer to black. A few pieces are r,g,b == 2,3,2, and I can't tell from the screenshot, but those might be showing up but just too hard to see. The white block is pretty obvious though.

So the quick fix is to edit that PNG and make that white block on the right black and it'll work correctly.

The reason for this is likely a driver bug (maybe it ignores alpha unless the rgb value is zero, too?). But it could be that every other driver offers Xcursor support and the fglxr driver doesn't...I don't know if that's true. But if that's the case, it's possible it forces SDL to generate a pixmap cursor and we have a bug there.

But I'm leaning towards it being a driver bug.   :)

If someone could try this with 0ad: get yourself an SDL2 with debug symbols, and set a breakpoint on X11_CreateCursor. Does it end up calling X11_CreateXCursorCursor or X11_CreatePixmapCursor?

(Feel free to copy/paste this reply into the Trac ticket, too.)

--ryan.
Comment 2 fabio 2015-02-25 08:11:08 UTC
(In reply to Ryan C. Gordon from comment #1)
> The reason for this is likely a driver bug (maybe it ignores alpha unless
> the rgb value is zero, too?). But it could be that every other driver offers
> Xcursor support and the fglxr driver doesn't...I don't know if that's true.

Note that I can reproduce this issues also with mesa drivers (gallium r300, gallium llvmpipe and classic swarst).

> If someone could try this with 0ad: get yourself an SDL2 with debug symbols,
> and set a breakpoint on X11_CreateCursor. Does it end up calling
> X11_CreateXCursorCursor or X11_CreatePixmapCursor?

I got this:

(gdb) break X11_CreateCursor
Function "X11_CreateCursor" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y

Breakpoint 1 (X11_CreateCursor) pending.
(gdb) r
[...]
Breakpoint 1, X11_CreateCursor (surface=0x94c6888, hot_x=0, hot_y=0)
    at /build/buildd/libsdl2-2.0.2+dfsg1/src/video/x11/SDL_x11mouse.c:205
205     /build/buildd/libsdl2-2.0.2+dfsg1/src/video/x11/SDL_x11mouse.c: File o directory non esistente.
(gdb) bt
#0  X11_CreateCursor (surface=0x94c6888, hot_x=0, hot_y=0)
    at /build/buildd/libsdl2-2.0.2+dfsg1/src/video/x11/SDL_x11mouse.c:205
#1  0xb7658f6c in SDL_CreateColorCursor_REAL (surface=<optimized out>, hot_x=0, hot_y=0)
    at /build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_mouse.c:655
#2  0xb7651adc in SDL_CreateColorCursor (a=0x94c6888, b=0, c=0)
    at /build/buildd/libsdl2-2.0.2+dfsg1/src/dynapi/SDL_dynapi_procs.h:287
#3  0x084eacf7 in create (hotspoty_=0, hotspotx_=0, pathname=..., vfs=
    std::shared_ptr (count 4, weak 0) 0x86eb280, this=0xb3b7197c)
    at ../../../source/lib/res/graphics/cursor.cpp:105
#4  Cursor_reload (c=0xb3b71974, vfs=std::shared_ptr (count 4, weak 0) 0x86eb280, name=...)
    at ../../../source/lib/res/graphics/cursor.cpp:285
#5  0x084e5497 in call_init_and_reload (type=<optimized out>, type=<optimized out>,
    init_args=<synthetic pointer>, pathname=..., vfs=std::shared_ptr (count 4, weak 0) 0x86eb280,
    hd=0xb3b71950, h=3014702) at ../../../source/lib/res/h_mgr.cpp:446
#6  alloc_new_handle (init_args=<synthetic pointer>, flags=<optimized out>, key=<optimized out>,
    pathname=..., vfs=std::shared_ptr (count 4, weak 0) 0x86eb280, type=0x86d7b08 <V_Cursor>)
    at ../../../source/lib/res/h_mgr.cpp:489
#7  h_alloc (type=0x86d7b08 <V_Cursor>, vfs=std::shared_ptr (count 4, weak 0) 0x86eb280, pathname=...,
    flags=0) at ../../../source/lib/res/h_mgr.cpp:536
#8  0x084e9c6f in cursor_load (forceGL=false, name=..., vfs=std::shared_ptr (count 4, weak 0) 0x86eb280)
    at ../../../source/lib/res/graphics/cursor.cpp:379
#9  cursor_draw (vfs=std::shared_ptr (count 4, weak 0) 0x86eb280, name=0x86e53f4 L"test", x=362, y=461,
    forceGL=false) at ../../../source/lib/res/graphics/cursor.cpp:406
#10 0x0824f0e5 in Render () at ../../../source/ps/GameSetup/GameSetup.cpp:295
#11 0x080725cc in Frame () at ../../../source/main.cpp:367
#12 RunGameOrAtlas (argc=argc@entry=1, argv=argv@entry=0xbffff084) at ../../../source/main.cpp:511
#13 0x0806218a in main (argc=1, argv=0xbffff084) at ../../../source/main.cpp:555


> (Feel free to copy/paste this reply into the Trac ticket, too.)

Will do once we gather some other info :)
Comment 3 fabio 2015-02-26 09:36:43 UTC
I also tried setting a break on X11_CreatePixmapCursor but this one never get reached:

(gdb) break X11_CreatePixmapCursor
Function "X11_CreatePixmapCursor" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y

Breakpoint 1 (X11_CreatePixmapCursor) pending.
(gdb) r
[...]
never reached.


While I get this when setting a break on X11_CreateXCursorCursor:

(gdb) break X11_CreateXCursorCursor
Function "X11_CreateXCursorCursor" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y

Breakpoint 1 (X11_CreateXCursorCursor) pending.
(gdb) r
[...]
Breakpoint 1, X11_CreateCursor (surface=0x94cd788, hot_x=0, hot_y=0)
    at /build/buildd/libsdl2-2.0.2+dfsg1/src/video/x11/SDL_x11mouse.c:214
214	/build/buildd/libsdl2-2.0.2+dfsg1/src/video/x11/SDL_x11mouse.c: File o directory non esistente.
(gdb) bt
#0  X11_CreateCursor (surface=0x94cd788, hot_x=0, hot_y=0)
    at /build/buildd/libsdl2-2.0.2+dfsg1/src/video/x11/SDL_x11mouse.c:214
#1  0xb7658f6c in SDL_CreateColorCursor_REAL (surface=<optimized out>, hot_x=0, hot_y=0)
    at /build/buildd/libsdl2-2.0.2+dfsg1/src/events/SDL_mouse.c:655
#2  0xb7651adc in SDL_CreateColorCursor (a=0x94cd788, b=0, c=0)
    at /build/buildd/libsdl2-2.0.2+dfsg1/src/dynapi/SDL_dynapi_procs.h:287
#3  0x084eacf7 in create (hotspoty_=0, hotspotx_=0, pathname=..., vfs=
    std::shared_ptr (count 4, weak 0) 0x86eb280, this=0xb3b7197c)
    at ../../../source/lib/res/graphics/cursor.cpp:105
#4  Cursor_reload (c=0xb3b71974, vfs=std::shared_ptr (count 4, weak 0) 0x86eb280, name=...)
    at ../../../source/lib/res/graphics/cursor.cpp:285
#5  0x084e5497 in call_init_and_reload (type=<optimized out>, type=<optimized out>, 
    init_args=<synthetic pointer>, pathname=..., vfs=std::shared_ptr (count 4, weak 0) 0x86eb280, 
    hd=0xb3b71950, h=3014702) at ../../../source/lib/res/h_mgr.cpp:446
#6  alloc_new_handle (init_args=<synthetic pointer>, flags=<optimized out>, key=<optimized out>, 
    pathname=..., vfs=std::shared_ptr (count 4, weak 0) 0x86eb280, type=0x86d7b08 <V_Cursor>)
    at ../../../source/lib/res/h_mgr.cpp:489
#7  h_alloc (type=0x86d7b08 <V_Cursor>, vfs=std::shared_ptr (count 4, weak 0) 0x86eb280, pathname=..., 
    flags=0) at ../../../source/lib/res/h_mgr.cpp:536
#8  0x084e9c6f in cursor_load (forceGL=false, name=..., vfs=std::shared_ptr (count 4, weak 0) 0x86eb280)
    at ../../../source/lib/res/graphics/cursor.cpp:379
#9  cursor_draw (vfs=std::shared_ptr (count 4, weak 0) 0x86eb280, name=0x86e53f4 L"test", x=167, y=731, 
    forceGL=false) at ../../../source/lib/res/graphics/cursor.cpp:406
#10 0x0824f0e5 in Render () at ../../../source/ps/GameSetup/GameSetup.cpp:295
#11 0x080725cc in Frame () at ../../../source/main.cpp:367
#12 RunGameOrAtlas (argc=argc@entry=1, argv=argv@entry=0xbffff084) at ../../../source/main.cpp:511
#13 0x0806218a in main (argc=1, argv=0xbffff084) at ../../../source/main.cpp:555
Comment 4 Philip Taylor 2015-02-28 00:30:52 UTC
Did a test with this image as a cursor:

  http://trac.wildfiregames.com/attachment/ticket/2823/alpha-test.png

and some demo renderings on light/dark backgrounds:

  http://trac.wildfiregames.com/attachment/ticket/2823/cursor-blending.png

The top pair matches what I see on the proprietary NVIDIA drivers on Linux, and is the expected behaviour.

The bottom pair apparently matches what is seen on the AMD drivers which had the bug reported here.


For that demo, I rendered the cursor in GL with

  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

for the top pair, and

  glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

for the bottom pair.


So in the incorrect case, it seems the drivers are blending the cursor as if it were using premultiplied alpha. But the image data is non-premultiplied, so that gives the wrong output whenever alpha!=255 and rgb!=0. Either the hardware needs to use the non-premultiplied blending equation, or the image needs to be converted to premultiplied before the hardware gets it. (But I don't know whether SDL or the display driver is meant to be responsible for that.)
Comment 5 Torbjörn Andersson 2015-03-05 20:59:15 UTC
Could this be what I'm seeing in Another World - 20th Anniversary Edition (purchased from GOG), as well? I do have an AMD Radeon R7 260X graphics card, and the cursor there is an arrow in a translucent magenta square. I was going to file a bug report to that game's bug tracker, but if it's already known, and possibly a driver issue, that seems unnecessary.

(Unfortunately, I can't provide any screenshots because every way I've tried to make one either doesn't show the cursor at all, or shows it correctly without the magenta background.)
Comment 6 Andreas Löf 2015-10-01 11:25:53 UTC
I've also observed this on 2.0.3.