The SDL forums have moved to discourse.libsdl.org.
This is just a read-only archive of the previous forums, to keep old links working.


SDL Forum Index
SDL
Simple Directmedia Layer Forums
resize window SDL2
john skaller
Guest

Hi, I'm back to ask if anyone can comment on the following issue.
I have some code which crashes on resizing a window.

As far as I can tell this is a design fault in SDL and cannot
be fixed, but I could be wrong.

Some rough history: SDL originally was designed for full screen games.
But a window was allowed as well to make debugging and development
easier.

In SDL2, the old windowing API was partly scrapped and redesigned
to allow multiple windows, and more advanced API to allow accelerated
drawing introduced.

Unfortunately the documentation is a bit light, and the some legacy
API still exists which simply cannot work.

To do stuff in SDL you need a surface or a renderer.
Blits use a surface, drawing uses a renderer. Blits can
be done rendering too by making a texture.

There is a renderer which can be used on an in-memory surface,
the so-called software renderer.

To get a surface from a window you call a function:

SDL_GetWindowSurface

you can then blit to that surface, or make a software renderer
and draw on it. Then you update the window to put the drawing
on the actual hardware window.

But there's a problem. You must not free the surface obtained
from a window. It is free'd automatically when the window is closed.

Unfortunately, that's not the end of it. If the window is resizable and
resized, the surface obviously MUST be "wrong" at some point.
It's not clear exactly when. It's not clear what happens.

It IS clear, however, that in the absence of a lock, the API simply
cannot work. It's a design fault.

The window is resized asynchronously. So the ONLY possible way the
API could work is that any previously obtained surface remains valid
until the next attempt to obtain a surface (or the window is closed).
or some other *specified* function is called.

This means that the surface dimensions, pixels, etc, will be wrong,
but the surface should still update the window without crashing.

However if you then get another surface, it would be different,
having the right dimensions, so the old one would HAVE to be deleted.
Otherwise every call to get another surface would have to add all the
surfaces to a list and only delete them all when the window is closed.
Leading to a massive leak.

But the documentation does not say that this happens.

It actually says the surface is invalidated by a resize, but only because
I myself recently added that note. Now I suspect I'm wrong.

I suspect it IS in fact invalidated by a resize, i.e. it is deleted.

But this is not acceptable. Because the window resize is an asynchronous
event driven by the user, and the program can only detect it has happened
AFTER the fact by reading a resize event from the event queue. Which is too
late if you were actually drawing the window during the resize, the surface
would have been deleted under your feet.

SO: in order to safely use the surface you get from a window it is
*essential* that it be documented when that surface is no longer valid
and that *has* to be in terms of a set of API calls that may invalidate it.
It cannot be invalidated (deleted) by merely resizing the window asynchronously.

The only sane behaviour I can think of is that it is invalidated by an update.
It doesn't say that in the documentation.

So you are safe if you draw on the surface, do an update, and refetch
the surface. [The update could fail if the window is resized, but that
won't cause a segfault from accessing free()d memory]

I actually do this and my code still crashes.

I'm running OSX 10.6.8 from SDL2.0.3 binary.
Unfortunately I can't compile SDL on this platform and I can't upgrade at
the moment either.

I had a look at the software renderer in the repository, and the clipping
code doesn't seem right (seems one pixel off).

On OSX, when I resize the window I get crud everywhere: I'm not refilling
the background. It looks like the surface pixels are being realloc()d
(because some of the old stuff is visible, but stretched diagonally).
[BTW: SDL says I do NOT need to lock the surface]

It is quite possible there's a bug in my code causing the crash,
but the fact remains the SDL2 API is broken: if it isn't bugged,
then at least the documentation is.

My code is written in Felix with a binding I wrote which translates
it all to C++. I wrote a small C program to demonstrate the problem
but it doesn't crash Smile

--
john skaller

http://felix-lang.org



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
resize window SDL2
Alex Szpakowski
Guest

Internal window resizing happens inside SDL_PumpEvents (which is called implicitly by SDL_PumpEvent), so it’s not asynchronous.

SDL_LockSurface and SDL_UnlockSurface also exist – are you making sure to use those when necessary?

Quote:
On Feb 15, 2015, at 6:07 PM, john skaller wrote:

Unfortunately, that's not the end of it. If the window is resizable and
resized, the surface obviously MUST be "wrong" at some point.
It's not clear exactly when. It's not clear what happens.

It IS clear, however, that in the absence of a lock, the API simply
cannot work. It's a design fault.

The window is resized asynchronously. So the ONLY possible way the
API could work is that any previously obtained surface remains valid
until the next attempt to obtain a surface (or the window is closed).
or some other *specified* function is called.
_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
resize window SDL2
Alex Szpakowski
Guest

Sorry, a typo: SDL_PumpEvents is called by SDL_PollEvent.

Also, in OS X in particular SDL_GetWindowSurface uses a SDL_Renderer and SDL_Texture internally. It might benefit your code to just use SDL_Render directly rather than using the Window Surface functions.

Quote:
On Feb 15, 2015, at 6:21 PM, Alex Szpakowski wrote:

Internal window resizing happens inside SDL_PumpEvents (which is called implicitly by SDL_PumpEvent), so it’s not asynchronous.


_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
resize window SDL2
john skaller
Guest

On 16/02/2015, at 9:26 AM, Alex Szpakowski wrote:

[On previous email: SDL says no need to lock the surface]

Quote:
Sorry, a typo: SDL_PumpEvents is called by SDL_PollEvent.

Ok, that makes sense, so you're saying, the window surface remains
valid until SDL_PumpEvents (called by SDL_PollEvent).

This doesn't explain my crash, but it could be caused by some
other problem.

Quote:

Also, in OS X in particular SDL_GetWindowSurface uses a SDL_Renderer and SDL_Texture internally. It might benefit your code to just use SDL_Render directly rather than using the Window Surface functions.

Yes, I know. However, there's a reason for starting with the more basic
functions.

One of these is roughly that code which starts with a surface
and creates a renderer will work on a window surface and a separate
surface the same way and in particular, it should work be possible to use those
functions in any thread (since it's all in memory stuff).

This may well be slower, but for a GUI this probably doesn't matter.
For a game doing graphics with a high frame rate it probably does matter.
A renderer created directly by a window doesn't offer the same assurance
(it might and probably does call thread-unsafe hardware accelerated operations
eg via OpenGL).

In any case I'm writing a tutorial/test suite so starting with the most
basic operations and working up seems to make some sense.

--
john skaller

http://felix-lang.org



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
resize window SDL2
Jonny D


Joined: 12 Sep 2009
Posts: 932
Irrespective of what might be going on here, I would suggest staying away from SDL_GetWindowSurface().  It's almost always going to be emulated, and hence, a feature that is not very future-proof.

Working solely on surfaces is not a recommended modern practice and doesn't translate well to any other modern graphics API.  Surfaces are great for operations that make sense in software, but just don't expect code (or tutorials) that use surfaces exclusively to be relevant for long.


Jonny D






On Mon, Feb 16, 2015 at 8:12 AM, john skaller wrote:
Quote:

On 16/02/2015, at 9:26 AM, Alex Szpakowski wrote:

[On previous email: SDL says no need to lock the surface]

Quote:
Sorry, a typo: SDL_PumpEvents is called by SDL_PollEvent.

Ok, that makes sense, so you're saying, the window surface remains
valid until SDL_PumpEvents (called by SDL_PollEvent).

This doesn't explain my crash, but it could be caused by some
other problem.

Quote:

Also, in OS X in particular SDL_GetWindowSurface uses a SDL_Renderer and SDL_Texture internally. It might benefit your code to just use SDL_Render directly rather than using the Window Surface functions.

Yes, I know. However, there's a reason for starting with the more basic
functions.

One of these is roughly that code which starts with a surface
and creates a renderer will work on a window surface and a separate
surface the same way and in particular, it should work be possible to use those
functions in any thread (since it's all in memory stuff).

This may well be slower, but for a GUI this probably doesn't matter.
For a game doing graphics with a high frame rate it probably does matter.
A renderer created directly by a window doesn't offer the same assurance
(it might and probably does call thread-unsafe hardware accelerated operations
eg via OpenGL).

In any case I'm writing a tutorial/test suite so starting with the most
basic operations and working up seems to make some sense.

--
john skaller

http://felix-lang.org



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org


resize window SDL2
john skaller
Guest

On 17/02/2015, at 3:38 AM, Jonathan Dearborn wrote:

Quote:
Irrespective of what might be going on here, I would suggest staying away from SDL_GetWindowSurface(). It's almost always going to be emulated, and hence, a feature that is not very future-proof.

Working solely on surfaces is not a recommended modern practice and doesn't translate well to any other modern graphics API. Surfaces are great for operations that make sense in software, but just don't expect code (or tutorials) that use surfaces exclusively to be relevant for long.

I take you point, but I wonder how to work on a RAM only canvas.

I suppose I can work on independent surfaces and just render them
to the hardware window. Perhaps that would be better.

--
john skaller

http://felix-lang.org



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
resize window SDL2
john skaller
Guest

Hi, I could use some help on this.

Some background first: Java was developed by Sun to compete on the
desktop with Windows. In particular Java was "write once run anywhere"
and it came with a GUI. Neither Java nor the GUI were very good, but
the appeal of a platform independent GUI was one of the main reasons
for Java's success.

I am developing a "write once run anywhere" system too, but it is uses
a different technology. Instead of a VM and bytecode compiler, my
system generates C++ source which is then compiled down to
machine binary by your system C++ compiler. This should be faster,
and in particular, better for game development :-)

Because I generate C++, bindings to C libraries are particularly
easy to create and usually involve mapping types but little or no
executable code (unlike, say, bindings in Python). Here's an
example of a library of bindings .. for SDL of course:

http://felix-lang.org/$/usr/local/lib/felix/felix-latest/share/lib/sdl

Before developing games I need some tools. In particular
a GUI would be useful. And of course it has to be platform
independent! So of course I'm trying to use SDL because
the aim of SDL is to provide a platform independent game
development environment.

http://felix-lang.org/$/usr/local/lib/felix/felix-latest/share/lib/gui

It's a bit crude at the moment, but the methodology seems to
work up to a point:

http://felix-lang.org/$/usr/local/lib/felix/felix-latest/share/src/web/tutopt//sdlgui

But I have a problem. Tests gui_04_* on do event handling. When I resize a
window the program seems to work, unless the bounding rect of the stuff
I'm drawing is entirely outsize the window rect. That seems to crash my
program every time.

This is a clear indication of a bug in SDL because none of my code
knows anything about clipping etc.. Indeed, examining some of the SDL
code and docs, it is not specified clearly what happens intersecting
non-intersecting rects and it is not clear that every drawing routine
in the whole of SDL correctly handles negative width or height.
SDL_IntersectRect DOES product a negative dimension if there
is no intersection, and this is set to a SDL_Surface clipping rectangle.
A lot of SDL code does not do any special checks for this.
In some cases it works anyhow. It's hard to be sure.

Unfortunately I cannot experiment because I'm running OSX 10.6.8 and
can no longer compile SDL from source.

However here's the quandary. I have tried to make a C program
doing roughly the same drawing operations crash with a resize
and it doesn't.

Which is a strong indication SDL works and the bug is in my code :-)
[And I'm sure I'm not the only SDL user about .. :]

So now I have a contradiction.

Using gdb I find more than one of my programs crashes with
exactly the same single symbol on the stack, unfortunately
it has nothing to do with the problem. It's not even a function.
The indication is corruption.

Using Valgrind, my program crashes, Valgrind crashes, the
iTerm terminal emulator crashes and my computer hangs.
A hardware reset is required.

The crash also occurs on Linux, so it isn't OSX specific.
[Not surprising, since I'm using software rendering].

I am not asking for debugging help but thinking help!
Logically, the bug is in SDL because my code is entirely
independent of the context creating the crash, and the SDL C handling
this is very suspicious, but my C code designed to demonstrate
this fails to crash, indicating a corruption caused by my system
or my test code, bindings, or compiler. But the bindings and
test code work without resizing and the compiler compiles a
lot of other code and is fairly robust after 20+ years of development.

--
john skaller

http://felix-lang.org



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
resize window SDL2
john skaller
Guest

On 22/02/2015, at 11:16 AM, john skaller wrote:

Quote:
Hi, I could use some help on this.

Ok, I have managed to get Valgrind to tell where the error is:

==1417== Invalid write of size 8
==1417== at 0x1002A11E0: ??? (in /Library/Frameworks/SDL2.framework/Versions/A/SDL2)
==1417== by 0x100009FB0: flxusr::gui_04_wm_01::_init_::resume() (gui_04_wm_01.cpp:602)
==1417== by 0x100067243: flx::rtl::fthread_t::run() (flx_rtl.cpp:80)
==1417== by 0x1000694E8: flx::run::sync_sched::frun() (flx_sync.cpp:209)
==1417== by 0x1000640D7: flx::run::async_sched::prun(flx::run::async_sched::block_flag_t) (flx_async_world.cpp:132)
==1417== by 0x10006AE09: flx::run::flx_world::run_until_complete() (flx_world.cpp:327)
==1417== by 0x10000384A: felix_run(int, char**) (flx_run.include:330)
==1417== by 0x100003961: main (flx_run_main.cxx:4)
==1417== Address 0x11b2a90f0 is not stack'd, malloc'd or (recently) free'd
==1417==
==1417==
==1417== Process terminating with default action of signal 11 (SIGSEGV)
==1417== Access not within mapped region at address 0x11B2A90F8


surf = (SDL_Surface*) ::SDL_GetWindowSurface(w_uncurry); //assign simple
pixelformat = (*surf).format; //assign simple
bgpixels = (_a5115t_55683) ::SDL_MapRGB(pixelformat, c.r, c.g, c.b); //assign simple
_genout_urv55214 = (int) ::SDL_SetClipRect(surf, (SDL_Rect*)&r); //init
_genout_urv55144 = _genout_urv55214; //init
_genout_urv55131 = _genout_urv55144; //init
(void)_genout_urv55131;
_genout_urv55215 = SDL_FillRect (surf, NULL, bgpixels); //init

The last line there is line 602.

now, the docs say "NULL to fill the entire surface".

Certainly this is wrong. The actual code in the Mercurial repository says:

/* If 'rect' == NULL, then fill the whole surface */
if (rect) {
/* Perform clipping */
if (!SDL_IntersectRect(rect, &dst->clip_rect, &clipped)) {
return 0;
}
rect = &clipped;
} else {
rect = &dst->clip_rect;
}

which clearly fills the clip rect of the surface NOT the whole surface.

The cliprect is set by SDL_SetClipRect, which sets the actual
cliprect to the intersection of the supplied cliprect and the window
bounding rect, which has non-positive width or height.

Then there's a bit of a nasty selection of an optimal fill routine.
Includes special code for SSE etc .. I would not be surprised if
these routine cannot handle negative width/height values,
they're pretty complicated.

So it is again looking like a bug in SDL.
The reason my C code doesn't crash is it calls SDL_FillRect with
an actual rectangle. The generated C++ sets the clip rect then
calls SDL_FillRect with NULL.



--
john skaller

http://felix-lang.org



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
resize window SDL2
john skaller
Guest

On 23/02/2015, at 12:43 AM, john skaller wrote:

Quote:
On 22/02/2015, at 11:16 AM, john skaller wrote:

Quote:
Hi, I could use some help on this.



Ok, it is DEFINITELY a bug in SDL. Perhaps someone can try this test code.
It crashes immediately on OSX 10.6.8, Macbook Pro.

#include "SDL2/SDL.h"

void draw(SDL_Window *w, int x, int y)
{
SDL_Rect r;
r.x=x; r.y=y; r.w=100; r.h=100;
SDL_Surface *s = SDL_GetWindowSurface (w);
SDL_SetClipRect (s,&r);
SDL_PixelFormat *f = s->format;
uint32_t bgpixels = SDL_MapRGB(f, 200,200,200);
SDL_FillRect(s,NULL,bgpixels);
SDL_UpdateWindowSurface (w);
}

void fred()
{
int x = 190;
int y = 170;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *w = SDL_CreateWindow ("title",20,20,100,100,SDL_WINDOW_RESIZABLE);
draw (w,x,y);
SDL_PumpEvents();
SDL_Event e;
SDL_WaitEvent(&e);
while (e.type != SDL_QUIT)
{
fprintf (stderr, "Event ..\n");
draw(w, x,y);
SDL_WaitEvent(&e);
}
}
int main() { fred(); return 0; }

--
john skaller

http://felix-lang.org



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
resize window SDL2
john skaller
Guest

On 23/02/2015, at 1:09 AM, john skaller wrote:

Quote:

Ok, it is DEFINITELY a bug in SDL. Perhaps someone can try this test code.
It crashes immediately on OSX 10.6.8, Macbook Pro.

Confirmed, crashes on Linux too:

Program received signal SIGSEGV, Segmentation fault. SDL_FillRect4SSE (h=<optimized out>, w=<optimized out>, color=13158600, pitch=400, pixels=0x7ffff7fff148 <error: Cannot access memory at address 0x7ffff7fff148>) at /home/fletch/project/SDL2-2.0.3/src/video/SDL_fillrect.c:130 130 DEFINE_SSE_FILLRECT(4, Uint32)

This has the added advantage of identifying the specific sub-routine SDL_FillRect4SSE().

The culprit is in fact line 261 of SDL_FillRect.c in Mercurial repository which clearly
cannot handle negative height or width,

The solution is quite simple.

on Line 255 of SDL_FillRect.c in the repo, add this code:

if (SDL_NullRect (rect)) return SDL_True;

now go off an check that other routines make this test too, eg Blit,
line drawing, etc. I think these work however.


Quote:
#include "SDL2/SDL.h"

void draw(SDL_Window *w, int x, int y)
{
SDL_Rect r;
r.x=x; r.y=y; r.w=100; r.h=100;
SDL_Surface *s = SDL_GetWindowSurface (w);
SDL_SetClipRect (s,&r);
SDL_PixelFormat *f = s->format;
uint32_t bgpixels = SDL_MapRGB(f, 200,200,200);
SDL_FillRect(s,NULL,bgpixels);
SDL_UpdateWindowSurface (w);
}

void fred()
{
int x = 190;
int y = 170;
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *w = SDL_CreateWindow ("title",20,20,100,100,SDL_WINDOW_RESIZABLE);
draw (w,x,y);
SDL_PumpEvents();
SDL_Event e;
SDL_WaitEvent(&e);
while (e.type != SDL_QUIT)
{
fprintf (stderr, "Event ..\n");
draw(w, x,y);
SDL_WaitEvent(&e);
}
}
int main() { fred(); return 0; }

--
john skaller

http://felix-lang.org



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

--
john skaller

http://felix-lang.org



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
resize window SDL2
john skaller
Guest

On 23/02/2015, at 9:22 AM, john skaller wrote:

Quote:

On 23/02/2015, at 1:09 AM, john skaller wrote:

Quote:

Ok, it is DEFINITELY a bug in SDL. Perhaps someone can try this test code.
It crashes immediately on OSX 10.6.8, Macbook Pro.

Confirmed, crashes on Linux too:

Program received signal SIGSEGV, Segmentation fault. SDL_FillRect4SSE (h=<optimized out>, w=<optimized out>, color=13158600, pitch=400, pixels=0x7ffff7fff148 <error: Cannot access memory at address 0x7ffff7fff148>) at /home/fletch/project/SDL2-2.0.3/src/video/SDL_fillrect.c:130 130 DEFINE_SSE_FILLRECT(4, Uint32)

This has the added advantage of identifying the specific sub-routine SDL_FillRect4SSE().

The culprit is in fact line 261 of SDL_FillRect.c in Mercurial repository which clearly
cannot handle negative height or width,

The solution is quite simple.

on Line 255 of SDL_FillRect.c in the repo, add this code:

if (SDL_NullRect (rect)) return SDL_True;

Correction: SDL_RectEmpty.

I'm having a friend check this fixes the problem right now.
[I cannot compile SDL any more on OSX 10.6.8].


--
john skaller

http://felix-lang.org



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
Re: resize window SDL2
DLudwig


Joined: 09 Feb 2012
Posts: 179
This looks like a bug to me. I'm able to reproduce it on Win32, and on iOS with a few minor modifications. I've added some comments to the Bugzilla entry on it (at https://bugzilla.libsdl.org/show_bug.cgi?id=2868 ), along with a simplified test program, and John's fix encoded as a patch (tested + working).

Sam, Ryan -- if you like, and the patch looks good to you, I'd be happy to push the fix to hg.libsdl.org.

Cheers!
-- David L.
resize window SDL2
john skaller
Guest

On 23/02/2015, at 12:42 PM, DLudwig wrote:
Quote:

Sam, Ryan -- if you like, and the patch looks good to you, I'd be happy to push the fix to hg.libsdl.org.

Quick question: why return SDL_FALSE?

Wouldn't one return that if the operation failed?
Writing completely off the surface (by doing nothing) is no
more a failure than a partial (i.e. clipped) write.

Is there a consistent convention here?

BTW: thanks for your work David!!

--
john skaller

http://felix-lang.org



_______________________________________________
SDL mailing list

http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org
Re: resize window SDL2
DLudwig


Joined: 09 Feb 2012
Posts: 179
john skaller wrote:
Quick question: why return SDL_FALSE?


SDL_FillRect() uses a convention whereby an int, rather than SDL_bool, is returned: 0 on success, and something else (usually -1) for failure.


Cheers!
-- David L.