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 - Suslik

Pages: [1] 2 3
1
SFML projects / Re: SFGUI (0.3.0 released)
« on: April 27, 2016, 10:41:35 pm »
SFGUI crashes for me if I close console application window with its own "close" button. code is as follows:
#include <SFGUI/SFGUI.hpp>
#include <SFGUI/Widgets.hpp>

#include <SFML/Graphics.hpp>

int main()
{
  sf::RenderWindow appWindow;
  appWindow.resetGLStates();
  sfg::SFGUI sfgui;
  while (1);
  return 0;
}
 

More complicated code including standard samples crashes as well when I close console window.

It crashes somewhere in sfg::SFGUI spamming all the console with messages like these:


With an access violation like this:


I'm using Visual Studio 2015 with latest official SFML 2.3.0 x86 distribution and prebuilt SFGUI from here https://nightlybuilds.ch/project/show/5/SFGUI/

I have tested my previous setup that uses year-old(approximately) versions of both SFML and SFGUI and they both work fine without crashing.

2
First of all, I've been using SFML for quite some time now both for my work and for educational purposes (my students really get a jumpstart into C++ graphics with it) and I'm really happy with most of its design decisions.

However, there's a few design decisions I don't like. One of them I wanted to discuss today regards native OpenGL rendering with SFML.

As far as I see, currently SFML supports native OpenGL rendering in a way when user theoretically can inject any kind of OpenGL code between native SFML calls and it should work as long as the user knows what they're doing. SFML even provides some basic API call to help doing so like sf::Texture::bind() or sf::Shader::bind(). However, in practice it turns out that in order to mix native OpenGL with SFML, user must have deeper OpenGL understanding than functionality he's actually going to use because of hidden states that SFML sets.

Here's an example of very basic OpenGL code injected into SFML:
sf::RenderWindow window(...);
while(window.isOpen())
{
  while(window.pullEvent(...)){...}
  window.setActive(1); //just to be sure
  float vertices[] = {0, 0, 0,   100, 0, 0,  0, 100, 0};
  int indices[] = {0, 1, 2};
  glEnableClientState (GL_VERTEX_ARRAY);
  glVertexPointer(3, GL_FLOAT, sizeof(float) * 3, vertices);
  glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);

  window.display();
}
 
The code is very straightforward and it if you run it, it works great. Right? Wrong. Thing is, it works well *most of the time* because SFML has internal buffer bindings for its own rendering, for example here:
Code: [Select]
//RenderTarget.h, line 356
void RenderTarget::resetGLStates()
{
  //...
  glCheck(glEnableClientState(GL_VERTEX_ARRAY));
  glCheck(glEnableClientState(GL_COLOR_ARRAY));
  glCheck(glEnableClientState(GL_TEXTURE_COORD_ARRAY)); 
  //...
}
And when the user calls glDrawElements() or any similar function, colors are actually read from internal SFML buffers and of course that's undefined behaviour. It may even not crash most of the time, but when it does, crash occurs in nvogl.dll(windows) and that's pretty hard to track especially for those learning OpenGL.

Similar problems arise when using native OpenGL texturing. Since most OpenGL users are used to normalized texture coordinates, it's very confusing to track down glMatrixMode(GL_TEXTURE) that SFML uses.

Yes I understand that it's easy to say that the user must not make any assumptions on any states left by SFML. But due to vast number of non-obvious states that the user may forget to set to default values, debugging such errors may prove to be very frustrating, especially when the same code works perfectly fine in native code without SFML. I really think SFML should provide some functionality similar to resetGlStates(), but instead of resetting states for SFML usage, reset them to default OpenGL ones(matrices, client buffers, etc).

3
General discussions / Re: Shader uniform API -- part II
« on: January 31, 2016, 05:01:03 am »
So I want to pass a generic 4x4 matrix as a uniform to sf::Shader without
Code: [Select]
shader.setParameter("matrixColumn0", data[0][0], data[0][1], data[0][2], data[0][3]);
shader.setParameter("matrixColumn1", data[1][0], data[1][1], data[1][2], data[1][3]);
shader.setParameter("matrixColumn2", data[2][0], data[2][1], data[2][2], data[2][3]);
shader.setParameter("matrixColumn3", data[3][0], data[3][1], data[3][2], data[3][3]);
Do I have any options that do not include SFML git version manual recompilation?

Update:
I did recompile current git-default version that contained sf::Shader::SetUniform(...) function but when they are used in actual project, they cause linking errors due to functions like this(Glsl.h, line 40) not being labelled as library interface(it means they are not exported in .lib/.dll) :
Code: [Select]
void copyMatrix(const float* source, std::size_t elements, float* dest);

Adding __declspec(dllexport) like this:
Code: [Select]
void SFML_GRAPHICS_API copyMatrix(const float* source, std::size_t elements, float* dest);
solves the problem.

There's also some serious incompatibility going regarding z-buffer that is turned on by default on Windows in SFML 2.3.1 and turned off on linux(at least on drivers I tested). In SFML 2.3.2 it's turned off by default under both OS'es. I had to set sf::ContextSettings::depthBits manually to enable it.

4
The plugin is single-threaded CPU-bounded due to heavy physical calculations. Debug renderer is GPU-bounded but takes considerable CPU time as well because it processes a lot of info to visualize it. If I run them both in one thread their computation time adds and debug renderer has a significant impact on plugin performance overall. If I run them in separate threads, debug renderer does its thing independently and since it's read-only for physical data I barely need any syncronizations -> sync overhead is negligible.
But... this isn't multi-threaded rendering... unless I am understanding you wrong. If there is only a single instance of your renderer, then running it in parallel to your physics simulation doesn't mean you are rendering from multiple threads simultaneously. I assumed from the thread title and your initial example that you had multiple truly independent loops rendering simultaneously, which doesn't provide a performance benefit over simply rendering both windows from the same thread.
The debug renderer consists of multiple windows and every window is rendered from a separate thread.

5
I don't have the time to look for them for you unfortunately.
I thought it's just a common sense to prove your point if you claim a very debatable statement to be a fact. I have never encountered any problems with other programs crashing while recording so apparently I'm curious that you did.

I'm interested, what are your reasons for using it? Performance? Code simplicity? Maybe both? Because I can tell you that you aren't going to get both. It's always going to be a trade-off between simplicity and performance, as is typical with low level APIs.
I'm writing a physics simulation plugin for some program. The plugin is single-threaded CPU-bounded due to heavy physical calculations. Debug renderer is GPU-bounded but takes considerable CPU time as well because it processes a lot of info to visualize it. If I run them both in one thread their computation time adds and debug renderer has a significant impact on plugin performance overall. If I run them in separate threads, debug renderer does its thing independently and since it's read-only for physical data I barely need any syncronizations -> sync overhead is negligible.

6
Window / Re: Rendering in multithread cause crash. (On linux)
« on: January 15, 2015, 01:29:08 am »
With mutexes this is very slow, for processing events, the window is closing one year after I click on the button. :/
Rofl when they say something like "mutexes and other syncronization primitives are generally slow" it should be read as "every operation may take up to a hundred microseconds" and it may become a problem if there's millions of syncronizations like that are occuring every second. Apparently what you see is some kind of a deadlock, not mutexes being slow.

7
You can't first peek all hWnd-related messages and then peek all others, because in the meantime there may flow in new hWnd-related messages which then would be skipped/discarded by the other peeks. That would cause other nasty bugs.
Unfortunately I don't understand why one peeks would screw the others because as far as I understand peeks just remove requested types of messages while leaving all others intact. So I see no reason why the queue would overflow if you peek hWnd-related messages first and then all others.

Meanwile I did some testing.
#include <Windows.h>
int main()
{
  sf::RenderWindow window1(sf::VideoMode(800, 600), "Window1");
  sf::RenderWindow window2(sf::VideoMode(500, 500), "Window2");
  while(1)
  {
    MSG msg;
    while(PeekMessage(&msg, window1.getSystemHandle(), 0, 0, PM_REMOVE))
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
    while(PeekMessage(&msg, window2.getSystemHandle(), 0, 0, PM_REMOVE))
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
    while(PeekMessage(&msg, (HWND)-1, 0, 0, PM_REMOVE))
    {
      printf("Received message %d\n", msg.message);
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
    /*sf::Event event;
    while(window1.pollEvent(event));*/

  }
  return 0;
}
 
This unfortunately does not work. The loop with -1 simply does not get any messages, looks like I'm either using this feature wrong or it's broken.

Also I did some research on how it's done in GUI libraries. For example merging Qt and MFC is done via a plugin QtMfcApp: http://doc.qt.digia.com/solutions/4/qtwinmigrate/winmigrate-walkthrough.html
Considerable amount of pain should be suffered in order to mix wxWidgets and MFC as well: http://svn.wxwidgets.org/viewvc/wx/wxWidgets/trunk/samples/mfc/mfctest.cpp?view=markup

Most GUI libraries use a message loop with PeekMessage(.., NULL, ...) and yes most libraries indeed screw each other's message loops so additional steps have to be undertaken to merge them together under windows if message order is important for your app(for most apps it is). I suppose the workaround with a separate thread for every window is not that much of a trouble compared to other solutions lol.

8
From SDL:
void
WIN_PumpEvents(_THIS)
{
    const Uint8 *keystate;
    MSG msg;
    DWORD start_ticks = GetTickCount();

    if (g_WindowsEnableMessageLoop) {
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            /* Always translate the message in case it's a non-SDL window (e.g. with Qt integration) */
            TranslateMessage(&msg);
            DispatchMessage(&msg);

            /* Make sure we don't busy loop here forever if there are lots of events coming in */
            if (SDL_TICKS_PASSED(msg.time, start_ticks)) {
                break;
            }
        }
    }

    /* Windows loses a shift KEYUP event when you have both pressed at once and let go of one.
       You won't get a KEYUP until both are released, and that keyup will only be for the second
       key you released. Take heroic measures and check the keystate as of the last handled event,
       and if we think a key is pressed when Windows doesn't, unstick it in SDL's state. */

    keystate = SDL_GetKeyboardState(NULL);
    if ((keystate[SDL_SCANCODE_LSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_LSHIFT) & 0x8000)) {
        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LSHIFT);
    }
    if ((keystate[SDL_SCANCODE_RSHIFT] == SDL_PRESSED) && !(GetKeyState(VK_RSHIFT) & 0x8000)) {
        SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RSHIFT);
    }
}
 
I've asked around our coding community. Looks like the correct way would probably be to make a loop of PeekMessage(.., hWnd, ..) to process messages directed to this particular window, then make additional loop with PeekMessage(.., -1, ..). If it works(it's only a suggestion though), it still won't be totally awesome because that PeekMessage(.., -1, ..) loop should be either in MFC/Qt(external gui library) OR in sfml, but this way it'll still cause way less bugs than using NULL as hWnd and should process global messages not related to any particular window as well.

Reason why you can't just use PeekMessage(.., hWnd, ..) is because of messages not directed to any particular window. Like this one for example: http://msdn.microsoft.com/ru-ru/library/windows/desktop/ms632641%28v=vs.85%29.aspx

9
I have no idea what you were trying to fix because I can't reproduce it but if processing all messages instead of those you're supposed to makes it work "better", why not just log all the "extra" messages you process and find the one responsible? Also using -1 in PeekMessage instead of NULL  was adviced multiple times, at least it's worth trying because it won't break as much.

10
I already made a workaround by creating every window in a separate thread to use separate message queues but that directly contradicts to:
Quote
On OS X, windows and events must be managed in the main thread
from http://www.sfml-dev.org/tutorials/2.0/window-window.php

11
I think the problem is even if the commit fixes some things it does so in a wrong way. You're definitely not supposed to process messages directed to windows other than yours. If you were trying to fix https://github.com/SFML/SFML/issues/69 or https://github.com/SFML/SFML/issues/328 apparently this is not the right way because messages are not supposed to be processed this way and it produces 100% reproducible bugs while trying to fix something that looks more like Windows SDK bug reproducible only on few machines.

If you want to obtain thread messages instead of hWnd messages, use this:
Quote
If hWnd is -1, PeekMessage retrieves only messages on the current thread's message queue whose hwnd value is NULL, that is, thread messages as posted by PostMessage (when the hWnd parameter is NULL) or PostThreadMessage.

If you use NULL in PeekMessage you obtain other unwanted behaviour as well. For example this code:
int main()
{
  sf::RenderWindow window1(sf::VideoMode(800, 600), "Window1");
  sf::RenderWindow window2(sf::VideoMode(500, 500), "Window2");
  while(1)
  {
    sf::Event event;
    while(window1.pollEvent(event));
  }
  return 0;
}
 
processes messages both for window1 and window2 while there's message loop only for window1.

12
Ok, look here:
This is the commit that caused this problem.
https://github.com/SFML/SFML/commit/5d377fdb38312d2c7292451def6e2ce61541b9ec

And this is what it does:
Quote
It seems hard to find reliable documentation about this issue, so let's try something and see what good or bad effect it will have.

13
I'm don't know what kind of "thread" messages there are and why it was originally decided to go this way.
To reformulate in an easy way what MSDN says, PeekMessage with NULL hWnd receives all window messages that belong to the thread regardless of window they came from.

To help with your problem, you'd have to provide a bit more information. What kind of event does get triggered?
As I already said, an event from pushing button "stop plugin" from the program I'm writing the plugin for is triggered.

Why would the processing of a "foreign" event crash your application?
Because the "foreign" event is used for stopping my plugin. It's instance gets invalid while processing messages from the "foreign" window.

Can you build SFML in debug mode and debug things to find out where exactly within SFML it crashes?
I think I already did this in zero post. My debugWindow->pollEvent() calls sf::Window::popEvent(), that calls WindowImplWin32::processEvents() and it's code is in zero post: PeekMessage() with NULL as the second argument receives all messages instead of messages related to debugWindow. It includes the message from a button that's supposed to kill my plugin and it gets killed while processing messages which leads to an immediate crash on the next iteration of while(debugWindow->pollEvent(event)) because this-> and this->debugWindow become invalid after calling the destructor.

14
This isn't even specific to SFML, you can try to find other multi-window software that uses independent loops and you will encounter the same problem.
A proof please? If it is indeed so I suppose the behaviour is acceptable. Advice like "avoid using multithreaded rendering" is not, because it's supposed to work and I have my reasons for using it.

15
Ok, here's the minimal code:
#include <SFML/Graphics.hpp>

sf::RenderWindow *window1, *window2;
bool isRunning = 1;

void ThreadFunc1()
{
  while(isRunning)
  {
    window1->clear();
    window1->display();
  }
}

void ThreadFunc2()
{
  while(isRunning)
  {
    window2->clear();
    window2->display();
  }
}

int main()
{
  window1 = new sf::RenderWindow(sf::VideoMode(800, 600), "Awesome window");
  window1->setActive(false);
  sf::Thread thread1(ThreadFunc1);
  thread1.launch();

  window2 = new sf::RenderWindow(sf::VideoMode(800, 600), "Not as awesome window as the first one but still great");
  window2->setActive(false);
  sf::Thread thread2(ThreadFunc2);
  thread2.launch();

  while(isRunning)
  {
    sf::Event event;

    while(window1->pollEvent(event))
    {
      if(event.type == sf::Event::Closed)
      {
        isRunning = 0;
      }
    }
    while(window2->pollEvent(event))
    {
      if(event.type == sf::Event::Closed)
      {
        isRunning = 0;
      }
    }

    printf("we're alive\n");
  }
}
 
It creates 2 windows and a separate rendering thread for each of them while processing window events in the main thread. It works just fine if you compile and run it. However if you have some kind of recording software that captures OpenGL or D3D context running in your system, after running this test program for a few secods you get this:

or this:

but most often this:

When the crash happens, stack pointer always points either to window1->display() or window2->display().

The crash happens with different kinds of recording software like Bandicam, Action! and a few others when they're in OpenGL/D3D recording mode. It happens when these programs are just running and not even recording anything. The test program may run for a few seconds, sometimes it may semi-freeze for a second or two and reliably crashes after 3-10 seconds of running.

Any ideas how to work this around or reason why this happens?

Pages: [1] 2 3
anything