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

Author Topic: HELP! odd drawing issues while loading on another thread (new video/example)  (Read 6338 times)

0 Members and 2 Guests are viewing this topic.

_Fiction_

  • Newbie
  • *
  • Posts: 35
    • View Profile
Hi. What I am doing is using boost threads to load textures and data off the disk while I have a simple update loop for sfml which draws the loading screen. I am having an odd issue that happens only while this second thread is loading.

my code is basically

1.clear render texture to black
2.clear window to red
3. clear window to yellow
4. draw loading screen to texture
5. display texture
6. draw displayed texture to window
7. display window

what I get is the loading screen drawing, but with intermittent and randomly sized strips of the screen which will flash yellow and red (sometimes a yellow bar with a red bar on top of/below  it, sometimes only one color). This doesn't make any sense to me. If if clear the window to yellow it should not have any red left, but this issue keeps happening. Sometimes its a thin strip (its always the entire width of the screen) and sometimes its the entire screen. It just flickers those colors for a split second.

This just seems completely counter to my understanding of how the window is filled w/ pixels. VSync is off and the only time this ever happens is when using the secondary thread. For reference, I'm not using the window or the render texture that I draw my loading screen to in the loading thread.


What gives??? Anyone have any idea how this could happen? I've been frustrated for awhile and finally resorted to posting about it.
« Last Edit: March 30, 2019, 12:48:52 am by _Fiction_ »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: HELP! odd drawing issues while loading stuff on another thread
« Reply #1 on: March 26, 2019, 08:49:59 am »
Do you have a complete and minimal example that reproduces the issue?

With multi-threading there are quite a few things to consider.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

_Fiction_

  • Newbie
  • *
  • Posts: 35
    • View Profile
Re: HELP! odd drawing issues while loading stuff on another thread
« Reply #2 on: March 26, 2019, 09:16:16 am »
I can try to set up a minimalistic version of what is happening. I wasn't even aware it was possible for something like this to happen. Is it possible to give me maybe even an option of what could be happening to allow the red to still show after clearing it to yellow and drawing on it?
« Last Edit: March 26, 2019, 09:18:22 am by _Fiction_ »

_Fiction_

  • Newbie
  • *
  • Posts: 35
    • View Profile
Re: HELP! odd drawing issues while loading stuff on another thread
« Reply #3 on: March 26, 2019, 10:48:49 pm »
EDIT: new code below and better description
« Last Edit: March 30, 2019, 12:35:26 am by _Fiction_ »

_Fiction_

  • Newbie
  • *
  • Posts: 35
    • View Profile
Re: HELP! odd drawing issues while loading stuff on another thread
« Reply #4 on: March 30, 2019, 12:28:29 am »
Okay, I've come back to this problem after a little break and ran the last code I posted again, and realized it did in fact replicate the flicker! Just happens intermittently (like almost every time but not all, and size of the flicker is different each time). I cut off some of the fat from my example to reduce it down to the bare minimum. The 2 second sleep is there to show that the flicker happens immediately after the 2 seconds are up, aka it occurs when the shader load happens. Also, the shader involved doesn't matter, it can be a blank fragment shader but it needs to exist.

Here is a slow motion gif of what is happening. It is very frustrating to see this so often and not know what to do to fix it! (Its very slowed down. The real timing is a 1 frame flicker)

https://gfycat.com/ComfortableDigitalAssassinbug

I am using boost 1_59_0 and sfml 2.4.2 and this is a release build

#include <SFML/Graphics.hpp>
#include <boost/thread.hpp>
#include <iostream>

boost::thread *loadingThread;
sf::Texture tex;
sf::RenderWindow *window;

using namespace sf;
using namespace std;

RenderTexture *preScreenTex;

sf::Shader speedBarShader;

void Load()
{
        sleep(sf::seconds( 2 ));

        if (!speedBarShader.loadFromFile("speedbar_shader.frag", sf::Shader::Fragment))
        {
                cout << "speed bar SHADER NOT LOADING CORRECTLY" << endl;
        }

        while (true);
}

int main()
{

        window = new RenderWindow(sf::VideoMode(1920, 1080), "Breakneck", sf::Style::Fullscreen);
        window->setVerticalSyncEnabled(true);
        preScreenTex = new RenderTexture;
        preScreenTex->create(1920, 1080);
        preScreenTex->clear();

        int frame = 0;
        bool quit = false;
        sf::Event ev;
        loadingThread = NULL;

        while (!quit)
        {
                while (window->pollEvent(ev))
                {

                }

                preScreenTex->clear(Color::Black);
                window->clear(Color::Red);

                if (loadingThread != NULL)
                {
                        preScreenTex->clear(Color::Green);
                }

                if (frame == 60 * 3)
                {
                        loadingThread = new boost::thread(&Load);
                }

                preScreenTex->display();
                sf::Sprite spr;
                spr.setTexture(preScreenTex->getTexture());
                window->draw(spr);
                window->display();

                ++frame;
        }

        return 0;
}


 
« Last Edit: March 30, 2019, 10:34:57 am by _Fiction_ »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
I couldn't run your code at all, since you're using global initialize SFML resources, which isn't allowed and instantly crashes most of the time. I would highly recommend to stay away from global variables in general, whether initialized at global scope or not, they break scoping and make it hard or impossible to reason about the application flow.

So I changed your code around and also replaced boost::thread with std::thread.
Now the code works "fine" on my machine, i.e. no flickers. However since you're using OpenGL from two different threads (yes, loading a shader already does OpenGL calls), you will have to deal with proper context activation, I suggest reading the whole OpenGL tutorial, but especially the part about threading: https://www.sfml-dev.org/tutorials/2.5/window-opengl.php#rendering-from-threads

Modified code:
#include <SFML/Graphics.hpp>
#include <thread>
#include <iostream>

std::thread* loadingThread;
sf::RenderWindow* window;
sf::RenderTexture *preScreenTex;
sf::Shader* speedBarShader;

void Load()
{
    sleep(sf::seconds(2));

    if (!speedBarShader->loadFromFile("speedbar_shader.frag", sf::Shader::Fragment))
    {
        std::cout << "speed bar SHADER NOT LOADING CORRECTLY\n";
    }

    while (true);
}

int main()
{
    window = new sf::RenderWindow(sf::VideoMode(1920, 1080), "Breakneck", sf::Style::Fullscreen);
    window->setVerticalSyncEnabled(true);
    preScreenTex = new sf::RenderTexture;
    preScreenTex->create(1920, 1080);
    preScreenTex->clear();
    speedBarShader = new sf::Shader();

    int frame = 0;
    bool quit = false;
    sf::Event ev;
    loadingThread = NULL;

    while (!quit)
    {
        while (window->pollEvent(ev))
        {

        }

        preScreenTex->clear(sf::Color::Black);
        window->clear(sf::Color::Red);

        if (loadingThread != NULL)
        {
            preScreenTex->clear(sf::Color::Green);
        }

        if (frame == 60 * 3)
        {
            loadingThread = new std::thread(&Load);
        }

        preScreenTex->display();
        sf::Sprite spr;
        spr.setTexture(preScreenTex->getTexture());
        window->draw(spr);
        window->display();

        ++frame;
    }
}
 
« Last Edit: March 30, 2019, 11:55:13 am by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

_Fiction_

  • Newbie
  • *
  • Posts: 35
    • View Profile
Thank you for the response. I wasn't aware/thinking about the global variables, sorry about that. I don't use them in my original program and didn't think about it for the example.

On my end I also replaced boost thread with std thread, and also fixed the globals, but I still get the same issues. Just confirming that.

I have now read the page on the openGL contexts, but I'm a little confused how I would implement what they are saying here. I am rendering on my main thread and then just doing shader loading/other stuff in my secondary thread. How would I use contexts in relation to this? I guess I'm not fully wrapping my head around what kind of adjustments I should make.

it also seems like the rendertexture and renderwindow require context activation separately, but I don't see how the shader ties in to those and which one it ties into or when to activate/deactivate. Thanks for helping me out with this.
« Last Edit: March 30, 2019, 08:36:14 pm by _Fiction_ »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
The best solution is to no do any OpenGL in a multi-threaded way. Even if you get the context activation correctly, OpenGL itself isn't multi-threaded.
If you want to remove the slow read time from disk for say loading a shader from a file, I recommend write file loader in a separate thread and then use loadFromMemory in the main thread.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

_Fiction_

  • Newbie
  • *
  • Posts: 35
    • View Profile
This would imply that there's not really a way to load stuff in the background while having a smooth visual experience though. I'm trying to not have any skips while transitioning between levels, and I want a smooth transition between a level, the loading screen, and the next level. Is there no way to do that, even if I use the secondary thread to draw and load the resources in the main thread?

fallahn

  • Hero Member
  • *****
  • Posts: 507
  • Buns.
    • View Profile
    • Trederia
It's certainly possible to draw a loading screen in a new thread while loading resources in the main thread. I do it like this:

https://github.com/fallahn/xygine/blob/master/xyginext/src/core/State.cpp#L90

and launch it like this:

https://github.com/fallahn/xygine/blob/master/Demo/src/MenuState.cpp#L99

The resources used to draw the loading screen obviously have to already be loaded of course, and are loaded in the main thread. You can probably get away with doing this once when the game first starts. Bear in mind you can't process events in the new thread because, as far as I remember, events have to be processed by the thread which creates the window. HTH

_Fiction_

  • Newbie
  • *
  • Posts: 35
    • View Profile
I modified my code to do pretty much what yours does fallahn, where the main thread is loading, and there is a separate drawing thread. The first time in my program that I run it, there is no flicker, but if I exit a level and run it again, I get the flicker immediately when starting up the drawing thread, even with no loading occurring. It is so frustrating to me that no one can tell me what is going wrong or replicate the flicker, since no matter what I do it seems to happen somehow with no explanation. I feel like if I knew what was causing the flicker normally, I would be able to fix it. Why is no one else able to replicate it? I just want to know what is happening. It feels like my project is stuck until I figure this out :\

fallahn

  • Hero Member
  • *****
  • Posts: 507
  • Buns.
    • View Profile
    • Trederia
There's a few things you could do to try narrowing down the culprit. After all it could be something such as bad drivers (Intel GPUs are notorious for bad OpenGL support)

  • Try updating your graphics card drivers if possible :)
  • Try your executable on someone else's machine - preferably with both a similar and different manufacturer GPU. If it doesn't flicker you've at least narrowed it down to your machine. Otherwise it's probably code related
  • If you don't have access to another machine try building the demo from my repository. I've never seen problems with it so if you do get flickering, again it points to potentially hardware/GPU drivers
  • Try a GPU profiler such as nsight, CodeXL or GPU PerfStudio. They might be able to shed some light on what's going on under the hood.
  • Clean and rebuild your dev environment. Yes it's a chore, but sometimes headers from older versions of libraries can stick around and cause obscure bugs. Make sure all the libs you use, such as SFML are up to date, preferably building from source

Also don't let it get to you too much - I've had many frustrating bugs in the past, but I find that if it's something which doesn't break the actual gameplay then carry on regardless. You can always come back to a problem, and working on something else might even reveal an inadvertant solution :)