Welcome, Guest. Please login or register. Did you miss your activation email?

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - iwn

Pages: [1] 2
1
Graphics / LNK4098 warning for LIBCMT while building graphics DLL
« on: November 11, 2011, 01:44:06 am »
Laurent and slotdev, thanks for the clarification.

2
Graphics / Crash w/ VC++ 2010, SFML static libs and static sf::Texture?
« on: November 11, 2011, 01:37:55 am »
Quote
When you say "SFML static libs", is it just BUILD_SHARED_LIBS which is disabled, or did you also enable STATIC_STD_LIBS?


Just BUILD_SHARED_LIBS. STATIC_STD_LIBS is FALSE in all of my tests.

Quote
But anyway, avoid globals, especially SFML resources that use OpenGL and require an OpenGL context, they will always cause problems.


I had one instance where I was using a Texture as a static class member, and that led me to the aforementioned behavior when compiling with Visual C++. I then realized that it probably wasn't a very good idea in the first place, but I was still curious as to why it was happening.

I suspect it is related to something like the "static initialization order fiasco" described in the C++ FAQ Lite:

  http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14

Figured I'd ask just in case anyone knew more specifically how things could have gone awry.

Thanks for your response.

3
Graphics / LNK4098 warning for LIBCMT while building graphics DLL
« on: November 10, 2011, 10:04:39 am »
When compiling SFML2 using Visual C++ 2010 Express I receive the following warning:

Code: [Select]

Linking CXX shared library ..\..\..\lib\sfml-graphics-2.dll
 Creating library ..\..\..\lib\sfml-graphics.lib and object ..\..\..\lib\sfml-graphics.exp
 LINK : warning LNK4098: defaultlib 'LIBCMT' conflicts with use of other libs; use /NODEFAULTLIB:library


Is it harmless in this instance? Why does it appear here?

4
Graphics / Crash w/ VC++ 2010, SFML static libs and static sf::Texture?
« on: November 10, 2011, 09:50:01 am »
Good day,

Take the following program:

Code: [Select]

#include <SFML/Graphics.hpp>

sf::Texture texture;

int main() {
  return 0;
}


When compiled with MinGW g++ against SFML DLLs, it runs successfully.

When compiled with MinGW g++ against SFML static libs, it runs successfully.

When compiled with VC++ 2010 against SFML DLLs, it runs successfully.

When compiled with VC++ 2010 against SFML static libs, it crashes with the call stack:

Code: [Select]

  ntdll.dll!77aa22c2()
  [Frames below may be incorrect and/or missing, no symbols loaded for ntdll.dll]
> testimage.exe!sf::priv::MutexImpl::Lock()  Line 52 + 0xc bytes C++
  testimage.exe!sf::Mutex::Lock()  Line 62 C++
  testimage.exe!sf::Lock::Lock(sf::Mutex & mutex)  Line 39 C++
  testimage.exe!sf::GlResource::GlResource()  Line 52 + 0xd bytes C++
  testimage.exe!sf::Texture::Texture()  Line 48 + 0x16 bytes C++
  testimage.exe!`dynamic initializer for 'texture''()  Line 3 + 0x28 bytes C++
  msvcr100d.dll!_initterm(void (void)* * pfbegin, void (void)* * pfend)  Line 873 C
  testimage.exe!__tmainCRTStartup()  Line 473 + 0xf bytes C
  testimage.exe!mainCRTStartup()  Line 371 C
  kernel32.dll!7530339a()
  ntdll.dll!77ab9ed2()
  ntdll.dll!77ab9ea5()


Could anyone more experienced than I please explain why this happens in the one instance and not the others?

5
Graphics / Multiple threads with sf::Context and sf::Image
« on: May 31, 2011, 08:17:11 am »
I've sent you a patch. Please let me know if you have trouble receiving it.

6
Graphics / Multiple threads with sf::Context and sf::Image
« on: May 31, 2011, 12:56:23 am »
Assuming, of course, that there is a reasonable and fairly straightforward solution to this ;)

I'll poke at it a bit more here and let you know if I come up with anything.

7
Graphics / Multiple threads with sf::Context and sf::Image
« on: May 31, 2011, 12:49:36 am »
You're right, this only really shows up when you end up spawning many threads across the lifetime of the program. My initial use case involved a lazy image loader that spawned a separate thread for each image I wanted to use. Something like this:

Code: [Select]

class MyImageLoader : public Thread {
  MyImageLoader(string imageName);
  void Run() {
    image = new Image();
    // load the image data and do some moderate processing on it
    ready = true;
  }
};

class MyImage {
  MyImage(string imageName) {
    myImage = NULL;
    myLoader = new MyImageLoader(imageName);
    myLoader->Launch();
  }
  void Draw(RenderWindow window) {
    // If loader is done, take our image and cleanup the loader.
    if (myLoader && myLoader.ready) {
      myImage = myLoader->image;
      delete myLoader;
      myLoader = NULL;
    }
    // If we have our image, draw it. Otherwise, it must be
    // loading -- draw nothing.
    if (myImage) {
      window.Draw(new Sprite(*myImage));
    }
  }
};


I intended to eventually go back and rework it into some sort of single-threaded worker queue, but this did the job for the time being and it seemed to work fine until I started hitting the GL errors. SFML2 appears to have cleared those up, but by the time I had boiled it down to a minimal example, I realized it was susceptible to this memory consumption issue as well.

Even though it may be poorly architected, I don't think there's anything really wrong with the code above, and if someone wanted to write such code, I don't see why SFML should prevent or discourage them from doing so.

8
Graphics / Multiple threads with sf::Context and sf::Image
« on: May 30, 2011, 11:22:49 pm »
Yes, you are definitely correct. I hadn't considered exchanging contexts across threads like that.

9
Graphics / Multiple threads with sf::Context and sf::Image
« on: May 30, 2011, 11:04:23 pm »
From a practical perspective, I'm still not sure it matters much, but from a correctness perspective I can't disagree with you. It would probably be easier to just build it correctly up front than to try and prove otherwise, so I'll give it a shot. Would you mind if I try this out and send you a patch for comment?

10
Graphics / Multiple threads with sf::Context and sf::Image
« on: May 30, 2011, 09:32:50 pm »
When I said "active" I meant the same thing as reachable. And by reachable allocation, I believe valgrind means to say that there was a pointer somewhere in memory that addresses the allocation at the time I killed the process. Presumably, a reachable memory allocation is in use by the application and will be cleaned up later.

----

I dug a little deeper into this and I belive I've found the root cause of the memory consumption in SFML2. Consider this code sample:

Code: [Select]

#include <iostream>
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>

// When running either test with main1, the program's memory footprint
// will remain more or less static.
// When running either test with main2, the program's memory footprint
// will grow rapidly until it exhausts system resources.

// CONFIG

#define TEST test1     // test to run, either test1 or test2
#define MAIN main1     // main method to use, either main1 or main2

// test1 creates a user GlContext explicitly

void test1() {
  // ** Thread is contextless
  sf::Context c1;
  // ** Thread has active context c1
} // c1 goes out of scope
  // ~Context is called for c1:
  //   myContext->~GlContext calls GetInternalContext()->SetActive(true) during
  //   c1.SetActive(false)
  //   Because we did not previously have an internal context,
  //   GetIntrnalContext() creates one, then SetActive(true) makes it active
  //   ** Thread has active internal context
  //   ** internalContexts.size() increases by 1
  // ~GlResource is called for c1:
  //   If there are no other GlResources (ex. a RenderWindow in the main
  //   thread), then
  //     We call GlContext::GlobalCleanup():
  //       ** Thread's internal context is deleted
  //       ** internalContexts.size() is 0
  //   Otherwise, there are other resources -- postpone cleanup
  //     ** internalContexts.size() remains unchanged

// test2 creates an internal GlContext implicitly

void test2() {
  // ** Thread is contextless
  sf::Image* image = new sf::Image(); // calls EnsureContext()
  // EnsureContext() calls GetInternalContext(), and because we
  // have no internal context at this point, one is created and activated
  // ** Thread has active internal context
  // ** internalContexts.size() increases by 1
  delete image;
  // image is deleted:
  // ~GlResource is called for image:
  //   If there are no other GlResources (ex. a RenderWindow in the main
  //   thread), then
  //     We call GlContext::GlobalCleanup():
  //       ** Thread's internal context is deleted
  //       ** internalContexts.size() is 0
  //   Otherwise, there are other resources -- postpone cleanup
  //     ** internalContexts.size() remains unchanged
}

// main1 runs fine with either test1 or test2

void main1() {
  // ** internalContexts.size() is 0
  while (true) {
    sf::Thread thread(&TEST);
    thread.Launch();
    // ** internalContexts.size() increases by 1 during thread's run
    thread.Wait();
    // ** internalContexts.size() returns to 0

    // When last GlResource goes out of scope we
    // call GlContext::GlobalCleanup() -- memory
    // footprint remains the same.
  }
}

// main2 continually consumes resources with either test1 or test2

void main2() {
  // ** internalContexts.size() is 0
  sf::RenderWindow window;
  // ** internalContexts.size() is 1
  while (true) {
    sf::Thread thread(&TEST);
    thread.Launch();
    // ** internalContexts.size() increases by 1 during thread's run
    thread.Wait();
    // ** internalContexts.size() remains unchanged

    // GlContext::GlobalCleanup() is not called because
    // sf::RenderWindow remains in scope and keeps
    // GlResource::count at 2 -- memory footprint
    // grows until we either run out of memory or exhaust
    // system resources (i.e. X display connections),
    // then we may get GL errors or program crash.
  }
}

int main() {
  MAIN();
  return 0;
}


Postponing the GlContext cleanup via the global internalContexts seems to be by design, and I believe I understand why this needs to be in place for certain cases where the thread terminates abnormally. But in cases like the one above, where a thread exits cleanly, and it clearly dismisses the GL resources it used during it's run, having the context linger around in internalContexts doesn't make sense (at least, to me).

I guess I'm really asking this: Why must we always have a context allocated to a thread, or rather, why is internalContext == NULL is an inappropriate state for a thread, especially when a thread starts it's life contextless? Specifically, why do we need to do this

Code: [Select]

  --- SFML/Window/GlContext.cpp:223 ---
  if (this == currentContext)
  {
    // To deactivate the context, we actually activate another one so that we make
    // sure that there is always an active context for subsequent graphics operations
    return GetInternalContext()->SetActive(true);
  }


when we could instead do something like this?

Code: [Select]

  if (this == currentContext)
  {
    currentContext = NULL;
    if (internalContext && (this != internalContext)) {
      return internalContext->SetActive(true);
    } else {
      return true;
    }
  }


As far as I can tell, this will achive nearly the same thing as the original code, except it will not, as a side affect, instantiate an internal GlContext for a thread when there wasn't one there to begin with (as happens in test1(), above). I say nearly because in the case internalContext is NULL, it won't change the true active context, via GL calls -- the thread will still technically have a context as far as GL is concerned (i.e. wglGetCurrentContext() != NULL). However, at the next interaction with a GlResource, EnsureContext() should end up calling GetInternalContext()->SetActive(true), which will create a new internal context, and activate the context at that time. Or, if there is no further interaction with a GlResource, the destructor for GlContext will make the appropriate GL calls to truly place the thread into a contextless state (i.e. wglMakeCurrent(NULL, NULL)).

Am I just plain wrong? If not, can you see any unwanted side-effects resulting from a change like this?

11
Graphics / Multiple threads with sf::Context and sf::Image
« on: May 27, 2011, 09:04:59 am »
I'm not that familiar with valgrind, but the summary seems to suggest that the memory consumption is due to active allocations, rather than leaks, no?

I re-ran valgrind with --leak-check=full --show-reachable=yes and it gives the three largest, reachable allocations as:

Code: [Select]

==30039== Memcheck, a memory error detector
==30039== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==30039== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==30039== Command: ./testcontext4
==30039==
==30039==
==30039== HEAP SUMMARY:
==30039==     in use at exit: 218,235,115 bytes in 32,584 blocks
==30039==   total heap usage: 50,698 allocs, 18,114 frees, 241,961,036 bytes allocated
==30039==

<snip>

==30039== 24,117,248 bytes in 23 blocks are still reachable in loss record 673 of 676
==30039==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==30039==    by 0x4C39A2C: _mesa_malloc (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4CB4C4B: _swrast_CreateContext (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4BF934F: ??? (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4508625: ??? (in /usr/lib/libGL.so.1.2)
==30039==    by 0x44E44AF: ??? (in /usr/lib/libGL.so.1.2)
==30039==    by 0x44E5BFF: glXCreateContext (in /usr/lib/libGL.so.1.2)
==30039==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==30039==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==30039==    by 0x40FA2BB: (anonymous namespace)::GetInternalContext() (GlContext.cpp:90)
==30039==    by 0x40FA4F5: sf::priv::GlContext::EnsureContext() (GlContext.cpp:138)
==30039==    by 0x40FB929: sf::GlResource::GlResource() (GlResource.cpp:64)
==30039==
==30039== 35,276,544 bytes in 24 blocks are still reachable in loss record 674 of 676
==30039==    at 0x40235D0: memalign (vg_replace_malloc.c:581)
==30039==    by 0x402368E: posix_memalign (vg_replace_malloc.c:709)
==30039==    by 0x4C398DA: _mesa_align_malloc (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4C399AB: _mesa_align_calloc (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4C8E5BF: _tnl_init_vertices (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4CE79CC: _swsetup_CreateContext (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4BF9367: ??? (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4508625: ??? (in /usr/lib/libGL.so.1.2)
==30039==    by 0x44E44AF: ??? (in /usr/lib/libGL.so.1.2)
==30039==    by 0x44E5BFF: glXCreateContext (in /usr/lib/libGL.so.1.2)
==30039==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==30039==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==30039==
==30039== 38,720,000 bytes in 800 blocks are still reachable in loss record 675 of 676
==30039==    at 0x40235D0: memalign (vg_replace_malloc.c:581)
==30039==    by 0x402368E: posix_memalign (vg_replace_malloc.c:709)
==30039==    by 0x4C398DA: _mesa_align_malloc (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4D61F31: _mesa_vector4f_alloc (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4C7B809: ??? (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4C7855C: _tnl_install_pipeline (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4C78268: _tnl_CreateContext (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4BF935F: ??? (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4508625: ??? (in /usr/lib/libGL.so.1.2)
==30039==    by 0x44E44AF: ??? (in /usr/lib/libGL.so.1.2)
==30039==    by 0x44E5BFF: glXCreateContext (in /usr/lib/libGL.so.1.2)
==30039==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==30039==
==30039== 51,343,544 bytes in 23 blocks are still reachable in loss record 676 of 676
==30039==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==30039==    by 0x4C39A2C: _mesa_malloc (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4CB4BE6: _swrast_CreateContext (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4BF934F: ??? (in /usr/lib/dri/swrast_dri.so)
==30039==    by 0x4508625: ??? (in /usr/lib/libGL.so.1.2)
==30039==    by 0x44E44AF: ??? (in /usr/lib/libGL.so.1.2)
==30039==    by 0x44E5BFF: glXCreateContext (in /usr/lib/libGL.so.1.2)
==30039==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==30039==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==30039==    by 0x40FA2BB: (anonymous namespace)::GetInternalContext() (GlContext.cpp:90)
==30039==    by 0x40FA4F5: sf::priv::GlContext::EnsureContext() (GlContext.cpp:138)
==30039==    by 0x40FB929: sf::GlResource::GlResource() (GlResource.cpp:64)
==30039==
==30039== LEAK SUMMARY:
==30039==    definitely lost: 24,512 bytes in 131 blocks
==30039==    indirectly lost: 983,280 bytes in 4,820 blocks
==30039==      possibly lost: 18,520 bytes in 91 blocks
==30039==    still reachable: 217,208,803 bytes in 27,542 blocks
==30039==         suppressed: 0 bytes in 0 blocks
==30039==
==30039== For counts of detected and suppressed errors, rerun with: -v
==30039== ERROR SUMMARY: 18 errors from 18 contexts (suppressed: 89 from 12)


To me, it looks like we're creating a number of sf::GLResources and/or sf::GLContexts that aren't going away when the thread dies, but I may be misunderstanding the way the GL code is intended to work.

Can you offer any insight here?

12
Graphics / Multiple threads with sf::Context and sf::Image
« on: May 27, 2011, 08:32:35 am »
Here's the valgrind output for the most recent sample code, after running for a couple minutes.

valgrind --leak-check=yes ./testcontext4

Code: [Select]

==28864== Memcheck, a memory error detector
==28864== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==28864== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info
==28864== Command: ./testcontext4
==28864==
==28864==
==28864== HEAP SUMMARY:
==28864==     in use at exit: 777,424,068 bytes in 116,874 blocks
==28864==   total heap usage: 174,908 allocs, 58,034 frees, 869,300,595 bytes allocated
==28864==
==28864== 124 bytes in 1 blocks are definitely lost in loss record 280 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x473ABC2: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473AC63: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A5A3: xcb_connect_to_display_with_auth_info (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A8DB: xcb_connect (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x456BD72: _XConnectXCB (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x455BC16: XOpenDisplay (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x4101523: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:47)
==28864==    by 0x40FA381: sf::priv::GlContext::GlobalInit() (GlContext.cpp:108)
==28864==    by 0x40FB90A: sf::GlResource::GlResource() (GlResource.cpp:57)
==28864==    by 0x40FE41D: sf::Window::Window() (Window.cpp:53)
==28864==    by 0x4070565: sf::RenderWindow::RenderWindow() (RenderWindow.cpp:34)
==28864==
==28864== 124 bytes in 1 blocks are definitely lost in loss record 281 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x473ABC2: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473AC63: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A5A3: xcb_connect_to_display_with_auth_info (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A8DB: xcb_connect (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x456BD72: _XConnectXCB (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x455BC16: XOpenDisplay (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x4102B1D: sf::priv::VideoModeImpl::GetDesktopMode() (VideoModeImpl.cpp:122)
==28864==    by 0x40FBDD7: sf::VideoMode::GetDesktopMode() (VideoMode.cpp:60)
==28864==    by 0x4101637: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==28864==    by 0x40FA381: sf::priv::GlContext::GlobalInit() (GlContext.cpp:108)
==28864==    by 0x40FB90A: sf::GlResource::GlResource() (GlResource.cpp:57)
==28864==
==28864== 124 bytes in 1 blocks are definitely lost in loss record 282 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x473ABC2: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473AC63: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A5A3: xcb_connect_to_display_with_auth_info (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A8DB: xcb_connect (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x456BD72: _XConnectXCB (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x455BC16: XOpenDisplay (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x4101523: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:47)
==28864==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==28864==    by 0x40FA2BB: (anonymous namespace)::GetInternalContext() (GlContext.cpp:90)
==28864==    by 0x40FA798: sf::priv::GlContext::SetActive(bool) (GlContext.cpp:227)
==28864==    by 0x40FA3AD: sf::priv::GlContext::GlobalInit() (GlContext.cpp:114)
==28864==
==28864== 124 bytes in 1 blocks are definitely lost in loss record 283 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x473ABC2: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473AC63: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A5A3: xcb_connect_to_display_with_auth_info (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A8DB: xcb_connect (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x456BD72: _XConnectXCB (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x455BC16: XOpenDisplay (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x41036F9: sf::priv::WindowImplX11::WindowImplX11(sf::VideoMode, std::string const&, unsigned long) (WindowImplX11.cpp:114)
==28864==    by 0x40FF132: sf::priv::WindowImpl::New(sf::VideoMode, std::string const&, unsigned long) (WindowImpl.cpp:58)
==28864==    by 0x40FE82C: sf::Window::Create(sf::VideoMode, std::string const&, unsigned long, sf::ContextSettings const&) (Window.cpp:126)
==28864==    by 0x8048FC7: main (testcontext4.cpp:27)
==28864==
==28864== 160 bytes in 1 blocks are possibly lost in loss record 290 of 678
==28864==    at 0x4023796: calloc (vg_replace_malloc.c:467)
==28864==    by 0x401103B: _dl_allocate_tls (dl-tls.c:300)
==28864==    by 0x43BC5A0: pthread_create@@GLIBC_2.1 (allocatestack.c:579)
==28864==    by 0x411980B: sf::priv::ThreadImpl::ThreadImpl(sf::Thread*) (ThreadImpl.cpp:41)
==28864==    by 0x41194CF: sf::Thread::Launch() (Thread.cpp:52)
==28864==    by 0x8049018: main (testcontext4.cpp:31)
==28864==
==28864== 282 bytes in 1 blocks are definitely lost in loss record 322 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x4508253: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E8063: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==28864==    by 0x40FA381: sf::priv::GlContext::GlobalInit() (GlContext.cpp:108)
==28864==    by 0x40FB90A: sf::GlResource::GlResource() (GlResource.cpp:57)
==28864==    by 0x40FE41D: sf::Window::Window() (Window.cpp:53)
==28864==
==28864== 282 bytes in 1 blocks are definitely lost in loss record 323 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x4508253: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E8063: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410171D: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*, sf::ContextSettings const&, sf::priv::WindowImpl const*, unsigned int) (GlxContext.cpp:80)
==28864==    by 0x40FA5C1: sf::priv::GlContext::New(sf::ContextSettings const&, sf::priv::WindowImpl const*, unsigned int) (GlContext.cpp:159)
==28864==    by 0x40FE850: sf::Window::Create(sf::VideoMode, std::string const&, unsigned long, sf::ContextSettings const&) (Window.cpp:129)
==28864==    by 0x8048FC7: main (testcontext4.cpp:27)
==28864==
==28864== 282 bytes in 1 blocks are definitely lost in loss record 324 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x4508253: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E8063: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==28864==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==28864==    by 0x40FA2BB: (anonymous namespace)::GetInternalContext() (GlContext.cpp:90)
==28864==    by 0x40FA798: sf::priv::GlContext::SetActive(bool) (GlContext.cpp:227)
==28864==
==28864== 10,404 bytes in 51 blocks are possibly lost in loss record 524 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x44E3E6A: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E7EA8: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E8191: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==28864==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==28864==    by 0x40FA2BB: (anonymous namespace)::GetInternalContext() (GlContext.cpp:90)
==28864==
==28864== 11,408 bytes in 92 blocks are definitely lost in loss record 532 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x473ABC2: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473AC63: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A5A3: xcb_connect_to_display_with_auth_info (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A8DB: xcb_connect (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x456BD72: _XConnectXCB (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x455BC16: XOpenDisplay (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x4101523: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:47)
==28864==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==28864==    by 0x40FA2BB: (anonymous namespace)::GetInternalContext() (GlContext.cpp:90)
==28864==    by 0x40FA4F5: sf::priv::GlContext::EnsureContext() (GlContext.cpp:138)
==28864==    by 0x40FB929: sf::GlResource::GlResource() (GlResource.cpp:64)
==28864==
==28864== 11,532 bytes in 93 blocks are definitely lost in loss record 533 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x473ABC2: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473AC63: ??? (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A5A3: xcb_connect_to_display_with_auth_info (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x473A8DB: xcb_connect (in /usr/lib/libxcb.so.1.1.0)
==28864==    by 0x456BD72: _XConnectXCB (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x455BC16: XOpenDisplay (in /usr/lib/libX11.so.6.3.0)
==28864==    by 0x4102B1D: sf::priv::VideoModeImpl::GetDesktopMode() (VideoModeImpl.cpp:122)
==28864==    by 0x40FBDD7: sf::VideoMode::GetDesktopMode() (VideoMode.cpp:60)
==28864==    by 0x4101637: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==28864==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==28864==    by 0x40FA2BB: (anonymous namespace)::GetInternalContext() (GlContext.cpp:90)
==28864==
==28864== 13,056 (204 direct, 12,852 indirect) bytes in 1 blocks are definitely lost in loss record 540 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x44E3E6A: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E7EA8: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E8191: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==28864==    by 0x40FA381: sf::priv::GlContext::GlobalInit() (GlContext.cpp:108)
==28864==    by 0x40FB90A: sf::GlResource::GlResource() (GlResource.cpp:57)
==28864==
==28864== 13,056 (204 direct, 12,852 indirect) bytes in 1 blocks are definitely lost in loss record 541 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x44E3E6A: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E7EA8: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E8191: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410171D: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*, sf::ContextSettings const&, sf::priv::WindowImpl const*, unsigned int) (GlxContext.cpp:80)
==28864==    by 0x40FA5C1: sf::priv::GlContext::New(sf::ContextSettings const&, sf::priv::WindowImpl const*, unsigned int) (GlContext.cpp:159)
==28864==    by 0x40FE850: sf::Window::Create(sf::VideoMode, std::string const&, unsigned long, sf::ContextSettings const&) (Window.cpp:129)
==28864==
==28864== 25,944 bytes in 92 blocks are definitely lost in loss record 568 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x4508253: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E8063: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==28864==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==28864==    by 0x40FA2BB: (anonymous namespace)::GetInternalContext() (GlContext.cpp:90)
==28864==    by 0x40FA4F5: sf::priv::GlContext::EnsureContext() (GlContext.cpp:138)
==28864==
==28864== 26,112 (204 direct, 25,908 indirect) bytes in 1 blocks are definitely lost in loss record 569 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x44E3E6A: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E7EA8: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E81D3: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==28864==    by 0x40FA381: sf::priv::GlContext::GlobalInit() (GlContext.cpp:108)
==28864==    by 0x40FB90A: sf::GlResource::GlResource() (GlResource.cpp:57)
==28864==
==28864== 26,112 (204 direct, 25,908 indirect) bytes in 1 blocks are definitely lost in loss record 570 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x44E3E6A: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E7EA8: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E81D3: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410171D: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*, sf::ContextSettings const&, sf::priv::WindowImpl const*, unsigned int) (GlxContext.cpp:80)
==28864==    by 0x40FA5C1: sf::priv::GlContext::New(sf::ContextSettings const&, sf::priv::WindowImpl const*, unsigned int) (GlContext.cpp:159)
==28864==    by 0x40FE850: sf::Window::Create(sf::VideoMode, std::string const&, unsigned long, sf::ContextSettings const&) (Window.cpp:129)
==28864==
==28864== 60,996 bytes in 299 blocks are possibly lost in loss record 593 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x44E3E6A: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E7EA8: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E81D3: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==28864==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==28864==    by 0x40FA2BB: (anonymous namespace)::GetInternalContext() (GlContext.cpp:90)
==28864==
==28864== 1,191,564 (18,972 direct, 1,172,592 indirect) bytes in 93 blocks are definitely lost in loss record 640 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x44E3E6A: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E7EA8: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E8191: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==28864==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==28864==    by 0x40FA2BB: (anonymous namespace)::GetInternalContext() (GlContext.cpp:90)
==28864==
==28864== 2,367,420 (18,768 direct, 2,348,652 indirect) bytes in 92 blocks are definitely lost in loss record 653 of 678
==28864==    at 0x4025018: malloc (vg_replace_malloc.c:236)
==28864==    by 0x44E3E6A: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E7EA8: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E81D3: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x450C624: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E84E1: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E54B2: ??? (in /usr/lib/libGL.so.1.2)
==28864==    by 0x44E55E4: glXGetConfig (in /usr/lib/libGL.so.1.2)
==28864==    by 0x4101C67: sf::priv::GlxContext::CreateContext(sf::priv::GlxContext*, unsigned int, sf::ContextSettings const&) (GlxContext.cpp:197)
==28864==    by 0x410165A: sf::priv::GlxContext::GlxContext(sf::priv::GlxContext*) (GlxContext.cpp:62)
==28864==    by 0x40FA541: sf::priv::GlContext::New() (GlContext.cpp:145)
==28864==    by 0x40FA2BB: (anonymous namespace)::GetInternalContext() (GlContext.cpp:90)
==28864==
==28864== LEAK SUMMARY:
==28864==    definitely lost: 88,782 bytes in 473 blocks
==28864==    indirectly lost: 3,598,764 bytes in 17,641 blocks
==28864==      possibly lost: 71,560 bytes in 351 blocks
==28864==    still reachable: 773,664,962 bytes in 98,409 blocks
==28864==         suppressed: 0 bytes in 0 blocks
==28864== Reachable blocks (those to which a pointer was found) are not shown.
==28864== To see them, rerun with: --leak-check=full --show-reachable=yes
==28864==
==28864== For counts of detected and suppressed errors, rerun with: -v
==28864== ERROR SUMMARY: 19 errors from 19 contexts (suppressed: 89 from 12)

13
Graphics / Multiple threads with sf::Context and sf::Image
« on: May 27, 2011, 08:15:29 am »
Thanks for clarifying the usage of sf::Context in SFML2. I revised the last sample by removing the unnecessary sf::Context and replacing it with the image creation loop from my first post.

Code: [Select]

#include <iostream>
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>

#define NULL_RUN 0  // when 1, skip image creation loop

class ContextThread : public sf::Thread {
    public:
        ContextThread() :
            sf::Thread(&ContextThread::Run, this)
        {
            // ctor
        }
        void Run() {
#if !NULL_RUN
            for (int i = 0; i < 10; i++) {
                sf::Image* image = new sf::Image();
                image->Create(100, 100);
                delete image;
            }
#endif
        }
};

int main() {
    sf::RenderWindow app;
    app.Create(sf::VideoMode(800, 600, 32), "Test", sf::Style::Close);

    while (app.IsOpened()) {
        ContextThread* thread = new ContextThread();
        thread->Launch();
        thread->Wait();
        delete thread;

        sf::Event Event;
        while (app.PollEvent(Event))
        {
            // Exit on window close
            if (Event.Type == sf::Event::Closed) {
                app.Close();
            }
        }
    }

    return 0;
}


When I run this code on Windows 7, the process ramps up to about 350MB working set and then maintains that. After about 60 seconds, I get a run of GL errors, which recur every 30 to 60 seconds.

  An internal OpenGL call failed in Image.cpp (XXX) : GL_INVALID_OPERATION, the specified operation is not allowed in the current state

On Debian Linux I'm seeing similar behavior with regard to memory, but no GL errors. Instead, it crashes after a few minutes with:

  Maximum number of clients reachedFailed to connect to the X server while trying to get the desktop video modes
  Maximum number of clients reachedSegmentation fault

14
Graphics / Multiple threads with sf::Context and sf::Image
« on: May 27, 2011, 07:45:33 am »
I'm running Windows 7, but I see similar behavior on Debian Linux as well.

15
Graphics / Multiple threads with sf::Context and sf::Image
« on: May 27, 2011, 12:48:35 am »
Thanks, Laurent. I have a followup to this.

I reworked the code for SFML2 as you suggested, and the GL errors did disappear. However, I'm still seeing issues with memory consumption. I've reduced it down to the following code, which steadily increases it's memory footprint with each call to sf::Context::Context. I thought it might be related to accumulating thread overhead, but when setting NULL_RUN=1, the footprint stays relatively static. I see similar behavior on both Windows 7 / ATI Radeon 4800 and Linux / Intel 855GM  using the latest git master.

Code: [Select]

#include <iostream>
#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>

#define NULL_RUN 0  // when 1, skip context creation

class ContextThread : public sf::Thread {
    public:
        ContextThread() :
            sf::Thread(&ContextThread::Run, this)
        {
            // ctor
        }
        void Run() {
#if !NULL_RUN
            sf::Context context;
#endif
        }
};

int main() {
    sf::RenderWindow app;
    app.Create(sf::VideoMode(800, 600, 32), "Test", sf::Style::Close);

    while (app.IsOpened()) {
        ContextThread* thread = new ContextThread();
        thread->Launch();
        thread->Wait();
        delete thread;

        sf::Event Event;
        while (app.PollEvent(Event))
        {
            // Exit on window close
            if (Event.Type == sf::Event::Closed) {
                app.Close();
            }
        }
    }

    return 0;
}


Am I still using the sf::Context correctly here? If so, is this behavior  expected?

Pages: [1] 2
anything