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

Author Topic: sf::Texture::update memory leak.  (Read 4493 times)

0 Members and 1 Guest are viewing this topic.

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
sf::Texture::update memory leak.
« on: June 29, 2015, 07:55:07 pm »
Spoke with eXpl0it3r on irc a bit about this.

Anyway, so I have a multithreaded application. Seems that calling sf::Texture::update repeatedly, leaks. Tracking it revealed that it's specifically sf::priv::WglContext::createContext which leaks, and it leaks a lot, very quickly (~42 MiB in 3 sec).
sf::priv::WglContext::makeCurrent also causes a leak, but no where near as much (~72 KiB in 3 sec).

Essentially, my application has a thread controlled by an SDK I'm using, of which I have no control over. It calls a function that I write, and waits until it returns. I have this function launch a thread to do some processing on what the SDK passed to me, and detach from it, so I can let the SDK's thread continue.

I'm taking the image it gives, me converting it to an sf::Texture, and then in another thread, drawing said sf::Texture with an sf::Sprite on a sf::RenderWindow.
I have mutexes around any access to the texture.

Minimal example:
#include <SFML/Graphics.hpp>

#include <mutex>
#include <thread>

int main()
{
        using byte = unsigned char;

        sf::Texture texture;

        std::mutex textureMutex;

        std::thread([&]()
        {
                while (true)
                {
                        sf::sleep(sf::milliseconds(32));
                        std::thread([&]()
                        {
                                std::lock_guard<std::mutex> textureLock(textureMutex);

                                std::vector<byte> bytes(640 * 480 * 4);

                                if (texture.getSize() == sf::Vector2u{0, 0})
                                {
                                        texture.create(640, 480);
                                }

                                texture.update(bytes.data());
                        }).detach();
                }
        }).join();
       
        return 0;
}
 

The sf::sleep is there to simulate time waiting for the call from the SDK.
Also, without it, SFML outputs this:
Code: [Select]
An internal OpenGL call failed in TextureSaver.cpp (38) : GL_INVALID_OPERATION,
the specified operation is not allowed in the current state
An internal OpenGL call failed in Texture.cpp (390) : GL_INVALID_OPERATION, the
specified operation is not allowed in the current state
An internal OpenGL call failed in Texture.cpp (391) : GL_INVALID_OPERATION, the
specified operation is not allowed in the current state
An internal OpenGL call failed in TextureSaver.cpp (45) : GL_INVALID_OPERATION,
the specified operation is not allowed in the current state
Failed to create an OpenGL context for this window:
and an abort() gets called from crtmbox.c for every set of the above messages. Though, that seems less relevant.

Also, here is the VS *.diagsession file from running VS' Memory Analysis tool (had to put it on my Dropbox, as it's too big).

Oops, forgot versions and hardware and stuff:

OS: Windows 8.1 Enterprise
CPU: i7-4790
GPU: Intel HD Graphics 4600 (tried default driver and latest driver)
SFML: 2.3 from Github, compiled myself

Given that it's an Intel GPU, I'm assuming this is probably a driver issue... I'd try another graphics card, but I don't think we have any here at work.
« Last Edit: June 29, 2015, 08:14:35 pm by dabbertorres »

kitteh-warrior

  • Guest
Re: sf::Texture::update memory leak.
« Reply #1 on: June 29, 2015, 08:05:45 pm »
I'm wondering if this has anything to do with the setActive(bool) problems that were discussed here and here?

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: sf::Texture::update memory leak.
« Reply #2 on: June 29, 2015, 08:20:02 pm »
Well, if you didn't notice, a window is not in the example, as one is not needed to demonstrate the issue. So no call to setActive.

So, I'd say no.

And as well, even if this "isn't a memory leak", this is still a problem. As I run out of memory quickly. My application stops getting calls from the SDK, as it is unable to allocate memory for the images it passes to me.

kitteh-warrior

  • Guest
Re: sf::Texture::update memory leak.
« Reply #3 on: June 29, 2015, 08:27:17 pm »
Doesn't a texture also involve associating a context, thus causing a similar effect? I may be completely wrong in my way of thinking.  :P

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: sf::Texture::update memory leak.
« Reply #4 on: June 29, 2015, 08:30:08 pm »
It does, but you don't quite have control over it as much as you do with a context for a window (activating/deactivating) is my line of thought. Then again, I could be wrong as well. :P

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: sf::Texture::update memory leak.
« Reply #5 on: June 29, 2015, 10:25:01 pm »
SFML doesn't like it if you keep creating thousands of threads every frame and use them to manipulate OpenGL objects. I wouldn't label this so much a bug as I would "undocumented behaviour". The workaround is simple really... don't update the texture in the thread you keep creating. When you change that one little detail this memory explosion will also disappear.

As for how you would do that in your concrete case, well... get creative ;D. You are already using a lot of C++ threading facility objects, using a few more shouldn't hurt.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

dabbertorres

  • Hero Member
  • *****
  • Posts: 505
    • View Profile
    • website/blog
Re: sf::Texture::update memory leak.
« Reply #6 on: July 02, 2015, 07:06:50 pm »
Later that day and after digging through some more of SFML's code, I came to a similar conclusion. Thanks for the confirmation.

For what it's worth, and for anyone else that may come across this post, I fixed it by using a permanent "texture update thread".
Rather than "fire and forget" threads that update the texture, I launch a second thread when I launch my window's draw thread. This second thread shares a pointer to the incoming image data. The thread contains a while loop ( while(window.isOpen()) ), and all the necessary calls to update the texture. Every loop iteration, it checks if the image data pointer is not null. If so, it locks the texture to be updated, updates it, unlocks it, and nulls the image data pointer. If that pointer is null, it just does nothing.
This way, only one thread is ever needed, thus only one OpenGL context is ever created to update the texture. Took a little bit of redesign, but it works just fine now (and probably much better off this way too, beyond SFML/OpenGL stuff).

If you're interested in more details of such a design, you'll want to do a search on "thread pools".

 

anything