SFML community forums
Help => System => Topic started by: Jalfor on December 03, 2011, 12:44:40 pm
-
Just grabbed some code I've been working on from my Windows machine and loaded it onto Linux and it isn't working. The error message suggests that it is on SFML's end, not mine, though when I tried the minimal threading example from the tutorials, it worked fine.
The error message is:
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
ElectroToy: ../../src/xcb_io.c:273: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
Aborted
Process returned 134 (0x86) execution time : 0.232 s
Press ENTER to continue.
My code (I haven't worked on it for long yet so don't judge :p)
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <iostream>
#define WIDTH 800
#define HEIGHT 600
sf::RenderWindow App();
sf::Uint8 *pixels = new sf::Uint8[WIDTH * HEIGHT * 4];
void draw(int x, int y, int r, int g, int b)
{
pixels[(x + WIDTH * y) * 4 + 0] = r;
pixels[(x + WIDTH * y) * 4 + 1] = g;
pixels[(x + WIDTH * y) * 4 + 2] = b;
pixels[(x + WIDTH * y) * 4 + 3] = 255;
}
void display(void *UserData)
{
sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "Speed Test");
sf::Image screen(WIDTH, HEIGHT);
sf::Sprite sprite;
while (1)
{
screen.LoadFromPixels(WIDTH, HEIGHT, pixels);
sprite.SetImage(screen);
App.Clear();
App.Draw(sprite);
App.Display();
}
}
int main()
{
sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "Speed Test");
sf::Thread graphics(&display);
sf::Clock clock;
const sf::Input & Input = App.GetInput();
bool mouseX = Input.GetMouseX();
bool mouseY = Input.GetMouseY();
bool leftMouse = Input.IsMouseButtonDown(sf::Mouse::Left);
bool rightMouse = Input.IsMouseButtonDown(sf::Mouse::Right);
graphics.Launch();
while (1)
{
sf::Event Event;
while (App.GetEvent(Event))
{
if (Event.Type == sf::Event::Closed)
App.Close();
}
if (leftMouse)
draw(mouseX, mouseY, 255, 255, 255);
}
}
-
Are you aware that:
- you have one RenderWindow in your main() function
- you have another RenderWindow in your display() function
- sf::RenderWindow App() declares a function and has nothing to do with the two other App variables?
What you want is a single RenderWindow instance, shared by the main and secondary threads, right?
-
Yes, that is exactly what I was trying to do but I couldn't get it working.
Could someone please help me with this?
-
I'd personally use a Singleton, but it's arguable what is best.
-
Don't declare a global RenderWindow.
Declare a RenderWindow local to the main() function.
Pass a pointer to it to your thread function.
That's it ;)
-
Oh of course...didn't think of that. Thanks a bunch
-
Okay, I've been trying to get this working but it...well...isn't. I've got rid of most of it because it is irrelevant to my problem though I am still working on what I posted above just so you know. The code below compiles and runs on windows with MSVC++ though says something like could not create OpenGL context for this device. On Linux with Code blocks and GCC though it won't compile at all as it is complaining about conversion from int* to sf::WindowHandle. Keep in mind, my code isn't debugged because I can't, so if you pick anything up, feel free to fix it :)
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#define WIDTH 800
#define HEIGHT 600
void display(void *UserData)
{
sf::RenderWindow App = (int*)UserData;
sf::Image screen(WIDTH, HEIGHT);
sf::Sprite sprite;
while (1)
{
App.Clear();
App.Draw(sprite);
}
}
int main()
{
sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "ElectroToy");
sf::Thread graphics(&display, &App);
graphics.Launch();
while (1)
{
App.Display();
}
}
-
sf::RenderWindow App = (int*)UserData;
Here you're declaring a new RenderWindow instance, trying to construct it with a pointer to a RenderWindow interpreted as a pointer to int. Doesn't make sense at all :)
Here is the correct code:
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#define WIDTH 800
#define HEIGHT 600
void display(void *UserData)
{
sf::RenderWindow* App = static_cast<sf::RenderWindow*>(UserData);
sf::Image screen(WIDTH, HEIGHT);
sf::Sprite sprite;
while (1)
{
App->Clear();
App->Draw(sprite);
}
}
int main()
{
sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "ElectroToy");
sf::Thread graphics(&display, &App);
graphics.Launch();
while (1)
{
App.Display();
}
}
But your code won't work as expected. Why are you using a thread?
-
Firstly, I am using a thread because I plan to have the main bit of the game running in one thread, and having another one doing nothing but drawing because the drawing things to bitmaps then displaying them isn't very fast and I would rather it didn't slow the whole thing down.
Ok, so I have put the fix into the code though for reasons I cannot understand, on linux it complains about the threading with the error I posted in first post. On Windows it just doesn't display the window unless I put the function call in the main thread.
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <iostream>
#define WIDTH 800
#define HEIGHT 600
sf::Uint8 *pixels = new sf::Uint8[WIDTH * HEIGHT * 4];
void draw(int x, int y, int r, int g, int b)
{
pixels[(x + WIDTH * y) * 4 + 0] = r;
pixels[(x + WIDTH * y) * 4 + 1] = g;
pixels[(x + WIDTH * y) * 4 + 2] = b;
pixels[(x + WIDTH * y) * 4 + 3] = 255;
}
void display(void *UserData)
{
sf::RenderWindow* App = static_cast<sf::RenderWindow*>(UserData);
sf::Image screen(WIDTH, HEIGHT);
sf::Sprite sprite;
while (1)
{
screen.LoadFromPixels(WIDTH, HEIGHT, pixels);
sprite.SetImage(screen);
App->Clear();
App->Draw(sprite);
App->Display();
}
}
int main()
{
sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "ElectroToy");
sf::Thread graphics(&display, &App);
sf::Clock clock;
const sf::Input & Input = App.GetInput();
bool mouseX = Input.GetMouseX();
bool mouseY = Input.GetMouseY();
bool leftMouse = Input.IsMouseButtonDown(sf::Mouse::Left);
bool rightMouse = Input.IsMouseButtonDown(sf::Mouse::Right);
graphics.Launch();
while (1)
{
sf::Event Event;
while (App.GetEvent(Event))
{
if (Event.Type == sf::Event::Closed)
App.Close();
}
if (leftMouse)
draw(mouseX, mouseY, 255, 255, 255);
}
}
-
You must call App.SetActive(false) before launching the graphics thread.
And you should protect your pixel data with a mutex.
-
That fixed the problem on Windows with MSVC++ though Linux with Code::Blocks is still giving the threading error.
Also, what is the advantage of using a mutex as display() only ever reads and main() only ever writes?
-
Linux with Code::Blocks is still giving the threading error
Which one?
Also, what is the advantage of using a mutex as display() only ever reads and main() only ever writes?
The effects of concurrent access will probably be limited in your case, but it can still happen. You could update a pixel in the middle of its upload to the graphics card; even a single read/write operation can be interrupted since not all platforms ensure that these operations are atomic.
-
The effects of concurrent access will probably be limited in your case, but it can still happen. You could update a pixel in the middle of its upload to the graphics card; even a single read/write operation can be interrupted since not all platforms ensure that these operations are atomic.
Ok, I'll add it once I have this working.
As for which Linux Distro; Debian (Unstable) KDE
-
As for which Linux Distro; Debian (Unstable) KDE
My question was "which error", not "which Linux", sorry.
-
Ah, this one:
[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
ElectroToy: ../../src/xcb_io.c:178: dequeue_pending_request: Assertion `!xcb_xlib_unknown_req_in_deq' failed.
Aborted
Process returned 134 (0x86) execution time : 0.211 s
Press ENTER to continue.
-
Sometimes XInitThreads() must be called to make X aware that it's running in a multi-threaded application, but it shouldn't be necessary here.
-
How exactly do I call XInitThreads()...I assume I need to include something though I don't have the slightest clue what, and I couldn't find it with a Google search.
-
You must include <X11/Xlib.h> (and of course this code is for Linux only).
-
Thanks :D
-
Did it solve your problem?
-
Okay, I know this reply is a little late, but it did not. I have managed to narrow down the issue a bit though.
This code gives the threading error (during run-time) described on the previous page.
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#define WIDTH 800
#define HEIGHT 600
void display(void *UserData)
{
sf::RenderWindow* App = static_cast<sf::RenderWindow*>(UserData);
sf::Image screen(WIDTH, HEIGHT);
sf::Sprite sprite;
while (1)
{
App->Clear();
App->Draw(sprite);
}
}
int main()
{
sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "ElectroToy");
sf::Thread graphics(&display, &App);
graphics.Launch();
App.SetActive();
while (1)
App.Display();
}
However, if you remove all statements that do anything to App other than App.SetActive(false), it works.
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#define WIDTH 800
#define HEIGHT 600
void display(void *UserData)
{
sf::RenderWindow* App = static_cast<sf::RenderWindow*>(UserData);
sf::Image screen(WIDTH, HEIGHT);
sf::Sprite sprite;
while (1)
{
App->Clear();
App->Draw(sprite);
App->Display();
}
}
int main()
{
sf::RenderWindow App(sf::VideoMode(WIDTH, HEIGHT, 32), "ElectroToy");
sf::Thread graphics(&display, &App);
graphics.Launch();
App.SetActive();
graphics.Wait();
}
Now, my main application I'm working on (which is just the above further on in development) will also simply supply this error if calls to App happen in the main function as well as another one.Though at the moment, I have got rid of all App calls from the main function into another function in the same thread. This seems to execute a random number of times (usually, somewhere around 40 times) before showing the threading error. (The threading error only shows in Debug configuration) I am still trying to narrow down the cause of this and the current code is a little too long to post on the forums but if you want to see it, I'll post it. (It's just a bit of a mess).
Thanks for any help
-
Your first code is not supposed to work: a window can only be active in one thread at the same time. Note that calling Clear/Draw/Display implicitely tries to activate the window.
Your second code works as expected, all the graphics calls are done in the same thread. Except that SetActive() should be SetActive(false) in the main thread.
-
That explains everything...thanks a bunch
-
Actually, I think I need help on just one other small thing that isn't quite worth making a new thread about. What would the best way of getting events from the "graphics" thread into the main thread. I frankly, cannot see how to do this without tossing huge amounts of data between threads and even then, I'm not quite sure what to do.
Thanks a lot
-
Which events? The window's ones (sf::Event)?
-
Yes, I should have said. the
while (App.GetEvent(Event))
bit is what I need to get out of the that thread. Of course, I could just put it in the other thread but then I don't see how to access it as I can't think of a way to pass a pointer's address from the thread to the main function
-
GetEvent must be called in the same thread where the window was created, that's a limitation of some OSes. If I remember correctly, on OS X, windows and events are even restricted to the main thread.
-
So, I have to put all the display stuff and event handling stuff in the main thread and all the rest in different threads.
Thanks, as usual, you're a great help
-
So, I have to put all the display stuff and event handling stuff in the main thread and all the rest in different threads
There's no restriction on the "display stuff" -- whatever you put in this expression.