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

Author Topic: Blocking main thread causes failed texture load  (Read 5705 times)

0 Members and 1 Guest are viewing this topic.

HardCoded

  • Newbie
  • *
  • Posts: 23
    • View Profile
Blocking main thread causes failed texture load
« on: July 16, 2013, 04:55:05 am »
I was testing some stuff and got this to work:
01) Open File Dialog opens (using some old deprecated C++ code..)
02) File is selected
03) Texture A is loaded from a file (not related to open file dialog)
04) Texture B is loaded from a file (not related to open file dialog)
05) Texture C is loaded from a file (not related to open file dialog)

The problem is, the A and C load and render fine. But B fails to load and no error message is output onto the console. It just fails quietly.. And even reports that the texture is loaded.
As in, the error here never triggers but the texture loaded is just.. Blank:
if (!texture.loadFromFile("filename")) {
    //error
}
 

Also notice that none of the textures loaded are related to the file chosen in the OFD. When I remove the code for the OFD so the main thread is never blocked, all three textures load and render without issues.

It's only when I block the thread that the 2nd texture fails to load.. Which is weird. I would think that it should be the first texture that fails, if any of the three has to fail.

The deprecated C++ code I'm talking about is:
    OPENFILENAME opendialog = {0};
    WCHAR szFile[260] = {0};

    opendialog.lStructSize = sizeof (opendialog);
    opendialog.hwndOwner = hwnd;
    opendialog.hInstance = GetModuleHandle(NULL);
    opendialog.lpstrFile = &szFile[0];
    opendialog.nFilterIndex = 0;
    opendialog.nMaxFile = 256;
    opendialog.lpstrInitialDir = NULL;
    opendialog.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    GetOpenFileName(&opendialog);
    return std::wstring(szFile);
 
« Last Edit: July 16, 2013, 04:56:43 am by HardCoded »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
AW: Blocking main thread causes failed texture load
« Reply #1 on: July 16, 2013, 09:36:17 am »
What exactly do you mean with "blocking the main thread"?

You might want to provide a complete and minimal example.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Blocking main thread causes failed texture load
« Reply #2 on: July 16, 2013, 09:45:41 am »
This is strange. You should write a complete and minimal code that reproduces the problem.

Quote
What exactly do you mean with "blocking the main thread"?
GetOpenFileName opens the standard "open file" dialog, which is modal and thus blocks the calling thread.
Laurent Gomila - SFML developer

HardCoded

  • Newbie
  • *
  • Posts: 23
    • View Profile
Re: Blocking main thread causes failed texture load
« Reply #3 on: July 16, 2013, 09:55:59 am »
Exactly what I said, blocking the main thread =/
GetOpenFileName() blocks the main thread and shows an open file dialog until it is closed.
This blocking causes texture loading to fail where it would, otherwise, succeed.

After reducing it to the following simple example, it fails and outputs an error message on the first texture for me. But in the more complex code I have, it's the second texture that fails quietly (or, rather, loads a blank texture).

But I think the underlying problem's the same in both cases. Blocking the main thread just before calling loadFromFile() will cause it to bug when it would, otherwise, succeed.

#include<SFML/Window.hpp>
#include<SFML/Graphics.hpp>
#include<Windows.h>
#include<string>
#include<iostream>
int main () {
    sf::RenderWindow window(sf::VideoMode(800, 600), "test");
    OPENFILENAME opendialog = {0};
    WCHAR szFile[260] = {0};

    opendialog.lStructSize = sizeof (opendialog);
    opendialog.hwndOwner = window.getSystemHandle();
    opendialog.hInstance = GetModuleHandle(NULL);
    opendialog.lpstrFile = &szFile[0];
    opendialog.nFilterIndex = 0;
    opendialog.nMaxFile = 256;
    opendialog.lpstrInitialDir = NULL;
    opendialog.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    //This call blocks the main thread; blocking causes texture loading to fail
    GetOpenFileName(&opendialog);

    sf::Texture t1;
    sf::Texture t2;
    sf::Texture t3;

    if (!t1.loadFromFile("sfml-logo-small.png")) {
        std::cout<<"Failed to load t1"<<std::endl;
        return 0;
    }
    if (!t2.loadFromFile("sfml-logo-small.png")) {
        std::cout<<"Failed to load t2"<<std::endl;
        return 0;
    }
    if (!t3.loadFromFile("sfml-logo-small.png")) {
        std::cout<<"Failed to load t3"<<std::endl;
        return 0;
    }
   
    sf::Sprite s1;
    sf::Sprite s2;
    sf::Sprite s3;

    s1.setTexture(t1);
    s2.setTexture(t2);
    s3.setTexture(t3);

    s1.setPosition(0, 0);
    s2.setPosition(0, 100);
    s3.setPosition(0, 200);

    while (true) {
        window.clear();
        window.draw(s1);
        window.draw(s2);
        window.draw(s3);
        window.display();
    }

    return 0;
}
 

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Blocking main thread causes failed texture load
« Reply #4 on: July 16, 2013, 02:33:29 pm »
Exactly what I said, blocking the main thread =/
GetOpenFileName() blocks the main thread and shows an open file dialog until it is closed.
Well not everyone knows the Windows API well, to see that GetOpenFileName will block the thread.

I've tried it with VS 2012 x86 on my Windows 8 x64 machine and my AMD card. Works fine, with and without GetOpenFileName().
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

HardCoded

  • Newbie
  • *
  • Posts: 23
    • View Profile
Re: Blocking main thread causes failed texture load
« Reply #5 on: July 16, 2013, 03:15:36 pm »
That's strange =/
It breaks on my laptop, though.

OS Name   Microsoft Windows 7 Home Premium
Version   6.1.7601 Service Pack 1 Build 7601
Other OS Description    Not Available
OS Manufacturer   Microsoft Corporation
System Name   ACER-PC
System Manufacturer   Acer
System Model   Aspire 4750
System Type   x64-based PC
Processor   Intel(R) Core(TM) i7-2630QM CPU @ 2.00GHz, 2001 Mhz, 4 Core(s), 8 Logical Processor(s)
BIOS Version/Date   Phoenix Technologies Ltd. V1.23, 28/4/2011
SMBIOS Version   2.6
Windows Directory   C:\Windows
System Directory   C:\Windows\system32
Boot Device   \Device\HarddiskVolume2
Locale   Singapore
Hardware Abstraction Layer   Version = "6.1.7601.17514"
User Name   acer-PC\acer
Time Zone   Malay Peninsula Standard Time
Installed Physical Memory (RAM)   4.00 GB
Total Physical Memory   3.85 GB
Available Physical Memory   970 MB
Total Virtual Memory   8.24 GB
Available Virtual Memory   2.30 GB
Page File Space   4.38 GB
Page File   C:\pagefile.sys

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Blocking main thread causes failed texture load
« Reply #6 on: July 16, 2013, 03:23:42 pm »
You could've left out quite a bit of information there and instead provided us with what compiler you use and how you got SFML. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

HardCoded

  • Newbie
  • *
  • Posts: 23
    • View Profile
Re: Blocking main thread causes failed texture load
« Reply #7 on: July 16, 2013, 03:31:09 pm »
Yeah, I considered leaving out the location and other stuff but was too lazy =P
I use VS2012 and I'm using SFML2.0's "Visual C++ 11 (2012) - 32 bits" version from this page: http://sfml-dev.org/download/sfml/2.0/

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Blocking main thread causes failed texture load
« Reply #8 on: July 16, 2013, 03:35:47 pm »
Just tested it with that version, still works fine. So it must be some problem on your PC or graphics card, which reminds me, what graphics card do you use? :D
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

HardCoded

  • Newbie
  • *
  • Posts: 23
    • View Profile
Re: Blocking main thread causes failed texture load
« Reply #9 on: July 16, 2013, 04:23:59 pm »
Intel(R) HD Graphics 3000

HardCoded

  • Newbie
  • *
  • Posts: 23
    • View Profile
Re: Blocking main thread causes failed texture load
« Reply #10 on: July 18, 2013, 04:51:40 am »
Okay, so here's another test I did to see just how long I'd have to wait before being able to load textures again:
#include<SFML/Window.hpp>
#include<SFML/Graphics.hpp>
#include<Windows.h>
#include<string>
#include<iostream>
int main () {
    sf::RenderWindow window(sf::VideoMode(800, 600), "test");
    OPENFILENAME opendialog = {0};
    WCHAR szFile[260] = {0};

    opendialog.lStructSize = sizeof (opendialog);
    opendialog.hwndOwner = window.getSystemHandle();
    opendialog.hInstance = GetModuleHandle(NULL);
    opendialog.lpstrFile = &szFile[0];
    opendialog.nFilterIndex = 0;
    opendialog.nMaxFile = 256;
    opendialog.lpstrInitialDir = NULL;
    opendialog.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    //This call blocks the main thread; blocking causes texture loading to fail
    GetOpenFileName(&opendialog);

    sf::Texture t1;
    while (!t1.loadFromFile("sfml-logo-small.png")) {
        std::cout<<"Failed to load t1"<<std::endl;
    }
    std::cout<<"SUCCESS"<<std::endl;

    return 0;
}
 

And..
It never ever succeeds. Ever.
I get the error: "Failed to load image "sfml-logo-small.png". Reason: Unable to open file".. Forever.

It just loops on and on.

---
And another test; passing in NULL to hwndOwner and without a window.
#include<SFML/Window.hpp>
#include<SFML/Graphics.hpp>
#include<Windows.h>
#include<string>
#include<iostream>
int main () {
    OPENFILENAME opendialog = {0};
    WCHAR szFile[260] = {0};

    opendialog.lStructSize = sizeof (opendialog);
    opendialog.hwndOwner = NULL;
    opendialog.hInstance = GetModuleHandle(NULL);
    opendialog.lpstrFile = &szFile[0];
    opendialog.nFilterIndex = 0;
    opendialog.nMaxFile = 256;
    opendialog.lpstrInitialDir = NULL;
    opendialog.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    //This call blocks the main thread; blocking causes texture loading to fail
    GetOpenFileName(&opendialog);
   
    sf::Texture t1;
    while (!t1.loadFromFile("sfml-logo-small.png")) {
        std::cout<<"Failed to load t1"<<std::endl;
    }
    std::cout<<"SUCCESS"<<std::endl;

    return 0;
}
 

Also, just loops an error forever.


Without GetOpenFileName(), it works on the first attempt, outputs "SUCCESS" and closes.
« Last Edit: July 18, 2013, 04:57:16 am by HardCoded »

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Blocking main thread causes failed texture load
« Reply #11 on: July 18, 2013, 04:57:09 am »
I get the error: "Failed to load image "sfml-logo-small.png". Reason: Unable to open file".. Forever.

Sounds almost as if SFML can't find the texture's file on the disk. Almost like somehow your working directory changed after using the OpenFileDialog. What happens if you provide an absolute path (ie "C:\\Images\\sfmllogo.png") after calling OpenFileDialog?

Another thing to test would be if blocking the main thread is really the issue. Write up a small multithreaded example that starts another thread and then waits until that thread exits. In the other thread just wait for maybe 10 seconds and then exit and then allow the main thread to continue loading textures. If the problem persists after you block the main thread with your own thread then something is setup wrong or something, but if all works good then somehow the OpenFileDialog is messing with your paths somehow.
« Last Edit: July 18, 2013, 05:02:01 am by zsbzsb »
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

HardCoded

  • Newbie
  • *
  • Posts: 23
    • View Profile
Re: Blocking main thread causes failed texture load
« Reply #12 on: July 18, 2013, 05:13:10 am »
I was just about to write a multi-threaded test.
WCHAR szFile[260] = {0};

void threadOFD () {
    OPENFILENAME opendialog = {0};
   

    opendialog.lStructSize = sizeof (opendialog);
    opendialog.hwndOwner = NULL;
    opendialog.hInstance = GetModuleHandle(NULL);
    opendialog.lpstrFile = &szFile[0];
    opendialog.nFilterIndex = 0;
    opendialog.nMaxFile = 256;
    opendialog.lpstrInitialDir = NULL;
    opendialog.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    //This call blocks the main thread; blocking causes texture loading to fail
    GetOpenFileName(&opendialog);
}

int main () {
    sf::Thread thread(&threadOFD);
    thread.launch();

    //while (szFile[0] == '\0') {}

    sf::Texture t1;
    while (!t1.loadFromFile("sfml-logo-small.png")) {
        std::cout<<"Failed to load t1"<<std::endl;
    }
    std::cout<<"SUCCESS"<<std::endl;

    return 0;
}
 
When the while-loop is commented:
01) Console opens
02) OFD opens
03) Texture loads
04) Outputs success
05) OFD closes
06) Application closes

When I un-comment the while-loop:
01) Console opens
02) OFD opens
03) Texture fails to load
04) Loop 03

Absolute paths don't work, either. Well, they work BUT they don't work right.
int main () {
    OPENFILENAME opendialog = {0};
    WCHAR szFile[260] = {0};

    opendialog.lStructSize = sizeof (opendialog);
    opendialog.hwndOwner = NULL;
    opendialog.hInstance = GetModuleHandle(NULL);
    opendialog.lpstrFile = &szFile[0];
    opendialog.nFilterIndex = 0;
    opendialog.nMaxFile = 256;
    opendialog.lpstrInitialDir = NULL;
    opendialog.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    //This call blocks the main thread; blocking causes texture loading to fail
    GetOpenFileName(&opendialog);

    sf::Texture t1;
    while (!t1.loadFromFile("C:\\Users\\acer\\Desktop\\document.png")) {
        std::cout<<"Failed to load t1"<<std::endl;
    }
    sf::Texture t2;
    while (!t2.loadFromFile("C:\\Users\\acer\\Desktop\\document.png")) {
        std::cout<<"Failed to load t2"<<std::endl;
    }
    sf::Texture t3;
    while (!t3.loadFromFile("C:\\Users\\acer\\Desktop\\document.png")) {
        std::cout<<"Failed to load t3"<<std::endl;
    }

    sf::Sprite spr1;
    sf::Sprite spr2;
    sf::Sprite spr3;
    spr1.setTexture(t1);
    spr2.setTexture(t2);
    spr3.setTexture(t3);

    spr1.setPosition(0, 100);
    spr2.setPosition(0, 200);
    spr3.setPosition(0, 300);

    sf::RenderWindow w1(sf::VideoMode(800, 600), "test");
    while (true) {
        w1.clear();
        w1.draw(spr1);
        w1.draw(spr2);
        w1.draw(spr3);
        w1.display();
    }

    std::cout<<"SUCCESS"<<std::endl;

    return 0;
}
 

As you can see, t1, t2 and t3 are all loading the same file from an absolute path. However, t2 "fails quietly". t1 loads the right texture and displays. t3 loads the right texture and displays. t2 loads a blank texture and displays.. Nothing.

Also, in my slightly more complex code that I'm using, I used absolute paths to test it, loads a blank =/ And it's *also* the 2nd texture. I guess I could get around it by loading a blank texture twice after an OFD opens to ensure textures loaded after that run fine..

Hmm..

It would also appear that you were right about the OFD messing my directory up. Any idea how to get around that?
« Last Edit: July 18, 2013, 05:21:11 am by HardCoded »

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: Blocking main thread causes failed texture load
« Reply #13 on: July 18, 2013, 05:20:36 am »
When I meant multithreaded test I mean something more like the following without the calls to the file dialog. What happens with the following code? This should block the main thread too for about 15 seconds.

void threadOFD () {
    sf::sleep(sf::milliseconds(15000)); // 15 seconds
}

int main () {
    sf::Thread thread(&threadOFD);
    thread.launch();
    thread.wait();



    sf::Texture t1;
    while (!t1.loadFromFile("sfml-logo-small.png")) {
        std::cout<<"Failed to load t1"<<std::endl;
    }
    std::cout<<"SUCCESS"<<std::endl;

    return 0;
}
 

Edit to reply to your edit  ;)

Quote
It would also appear that you were right about the OFD messing my directory up. Any idea how to get around that?

After doing some research your best bet would be to call GetCurrentDirectory to retrieve your current directory and then call SetCurrentDirectory to restore to the value before you used the OFD.
« Last Edit: July 18, 2013, 05:34:07 am by zsbzsb »
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

HardCoded

  • Newbie
  • *
  • Posts: 23
    • View Profile
Re: Blocking main thread causes failed texture load
« Reply #14 on: July 18, 2013, 05:39:29 am »
Whoops, I came up with this instead =x
#include "Shlwapi.h"
    /*snip*/
    WCHAR szDir [260] = {0};
    GetModuleFileName(GetModuleHandle(NULL), &szDir[0], 260);
    PathRemoveFileSpec(&szDir[0]);
    /*snip*/
    opendialog.lpstrInitialDir = &szDir[0];
    /*snip*/
 
With this, the initial directory that the OFD is on is also changed, though =/

I'll look into Get and Set Current Directory, thanks!

About the thread stuff.. I have to admit I haven't done any actual threading for, like, over a year (and I never got into it =/). I remember many headaches with threading. It still scars me.