Run my callback on UI thread each frame

Is there any way to call my callback each frame from UI thread?
I’m asking about universal solution for all platforms.
Thank you

I found similar question without answer
http://forums.libsdl.org/viewtopic.php?t=10687&highlight=thread

Your question doesn’t make sense (at least to me) as asked. The main thread is the one you’re writing your program in. Unless you are using something not SDL, your UI is in the main thread most likely. Unless it’s not, in which case it’s not because you or your UI library (so not SDL) decided to do it that way.

JosephSent via mobile

On Dec 28, 2014, at 15:59, dmuratshin wrote:

I found similar question without answer
http://forums.libsdl.org/viewtopic.php?t=10687&highlight=thread


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

SDL has 2 common threads on iOS / Android:

  • native app UI thread
  • SDL thread (for my game code)

I need execute some special code (not game) from UI thread and searching way to sync with it every frame.

Android, that explains it. :smiley: I can’t really help with Android unfortunately because I haven’t got one. But hopefully the Android folks will now see the thread and be able to help make sense of it.

JosephSent via mobile

On Dec 29, 2014, at 11:38, dmuratshin wrote:

SDL has 2 common threads on iOS / Android:

  • native app UI thread
  • SDL thread (for my game code)

I need execute some special code (not game) from UI thread and searching way to sync with it every frame.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

DarioOO wrote:

the above solution is almost universal, you may have problems with Emscripten thread model, but all other platforms should be fine

//… inside loop of UI thread (A)
and where is such place ‘UI thread loop’ in SDL code?:slight_smile:

On iOS the main thread handles UI, FWIW.On Dec 29, 2014, at 3:38 PM, dmuratshin wrote:

SDL has 2 common threads on iOS / Android:

  • native app UI thread
  • SDL thread (for my game code)

I need execute some special code (not game) from UI thread and searching way to sync with it every frame.


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

[quote=“DarioOO”]I’m not sure I fully understood your question but I assume the following:

  1. you have a render thread A
  2. you have a UI thread B

I expose a full solution (more than you need).

You want B register a callback that A can call
You want A register a callback that B can call–

You inherently need syncronization, in particular 2 mutexes: mA, mB;

UI thread:

Code:

//UI THREAD (A)

mA = SDL_CreateMutex();
mB = SDL_CreateMutex();

//… inside loop of UI thread (A)

SDL_mutexP(mA); //protect A

//… UI processing code (events etc.)

SDL_mutexP(mB); //protect B
callBackA();
registerCallbackForRenderThread(callBackB);
SDL_mutexV(mB);

SDL_mutexV(mA); //let B run its own callback

Render Thread:

Code:

//… inside loop of render thread (B)

SDL_mutexP(mA); //lock A to avoid deadlock
SDL_mutexP(mB); //protect B

//...rendering code

registerCallBackForUIThread(callBackA);
callBackB();
SDL_mutexV(mB);

SDL_mutexV(mA);

This way you almost lose all advantages of multithreading because each thread waits the other (well not totally true, when 1 thread release both mutexes it may happens that the other thread can do 2/3 or even more complete loops, you don’t have guarantee about duration of 1 loop, but you have a thread safe way to let each thread call a callback from the other thread at each loop/frame).

Of course if you need only 1 callback the code is slightly simpler (and faster too):

UI thread:

Code:

//UI THREAD (A)

mB = SDL_CreateMutex();

//… inside loop of UI thread (A)

//… UI processing code (events etc.)

SDL_mutexP(mB); //protect B
callBackA();
SDL_mutexV(mB);

Render Thread:

Code:

//… inside loop of render thread (B)
SDL_mutexP(mB); //protect B
//…rendering code
registerCallBackForUIThread(callBackA); //safe as long thread A don’t touch variables touched by this function unless mB is locked.
SDL_mutexV(mB);

DarioOO wrote:> I’m not sure I fully understood your question but I assume the following:

  1. you have a render thread A
  2. you have a UI thread B

I expose a full solution (more than you need).

You want B register a callback that A can call
You want A register a callback that B can call

You inherently need syncronization, in particular 2 mutexes: mA, mB;

UI thread:

Code:

//UI THREAD (A)

mA = SDL_CreateMutex();
mB = SDL_CreateMutex();

//… inside loop of UI thread (A)

SDL_mutexP(mA);
callBackA();
SDL_mutexV(mA);

SDL_mutexP(mB);
// now A have control, it can register a new callback to be called by B and can call its own
registerCallbackForRenderThread(callBackB);
SDL_mutexV(mB);

Render Thread:

Code:

//… inside loop of render thread (B)
SDL_mutexP(mA);
registerOnA(callBackA);
SDL_mutexV(mA);

SDL_mutexP(mB);
// now B have control, it can register a new callback to be called by B and can call its own
callBackB();
SDL_mutexV(mB);

I guess you need not tips about syntax for callbacks and how to expose 2 mutex to 2 different threads. The mutexes can be moved inside function calls, but I think having them outside makes them “more important” so other people that see your code will think very well before touching.[/code]

the above solution is almost universal, you may have problems with Emscripten thread model, but all other platforms should be fine

I’m not sure I fully understood your question but I assume the following:

  1. you have a render thread A
  2. you have a UI thread B

I expose a full solution (more than you need).

You want B register a callback that A can call
You want A register a callback that B can call–

You inherently need syncronization, in particular 2 mutexes: mA, mB;

UI thread:

Code:

//UI THREAD (A)

mA = SDL_CreateMutex();
mB = SDL_CreateMutex();

//… inside loop of UI thread (A)

SDL_mutexP(mA);
callBackA();
SDL_mutexV(mA);

SDL_mutexP(mB);
// now A have control, it can register a new callback to be called by B and can call its own
registerCallbackForRenderThread(callBackB);
SDL_mutexV(mB);

Render Thread:

Code:

//… inside loop of render thread (B)
SDL_mutexP(mA);
registerOnA(callBackA);
SDL_mutexV(mA);

SDL_mutexP(mB);
// now B have control, it can register a new callback to be called by B and can call its own
callBackB();
SDL_mutexV(mB);

/code]

I guess you need not tips about syntax for callbacks and how to expose 2 mutex to 2 different threads. The mutexes can be moved inside function calls, but I think having them outside makes them “more important” so other people that see your code will think very well before touching.

dmuratshin wrote:

//… inside loop of UI thread (A)
and where is such place ‘UI thread loop’ in SDL code?:slight_smile:

It’s not in SDL code, you create threads. Here is a complete example (really bad design, is just to show concepts, I would never release such code).

Hope it compiles and has no bugs :smiley:

Code:

void (*renderCallback)(void); //function pointer AKA callback
int (*uiCallback)(void);

SDL_mutex *renderMutex, *uiMutex;
static int RenderThread(void *ptr);

SDL_Window *window;

int closeRenderThread(){
printf(“closing the rendering thread\n”);
return 1;
}

int aknowledgeRendered1Frame(){
printf(“a frame was rendered (Render Thread)\n”);
return 0;
}

void aknowledgeProcessedEvents(){
printf(“events processed (UI thread)\n”);
}

void main(void)
{

SDL_Init(SDL_INIT_EVERYTHING);

window = SDL_CreateWindow(
    "RenderThread and UiThread",                  // window title
    SDL_WINDOWPOS_UNDEFINED,           // initial x position
    SDL_WINDOWPOS_UNDEFINED,           // initial y position
    640,                               // width, in pixels
    480,                               // height, in pixels
    SDL_WINDOW_OPENGL                  // flags - see below
);


renderCallback= NULL;
uiCallback= aknowledgeRendered1Frame;

renderMutex = SDL_CreateMutex();
uiMutex = SDL_CreateMutex();

SDL_Thread *thread;
int                 threadReturnValue;
thread = SDL_CreateThread(RenderThread, "RenderThread", (void *)NULL);


SDL_Event event;
int quit = 0;
while (quit = 0)  // UI thread (responsible of input processing and OS events)
{
    //--------- LOOP BEGIN
    SDL_mutexP(uiMutex);    

    if (SDL_WaitEvent(&event))
    {
        switch (event.type)
        {
            case SDL_QUIT:
                printf("SDL_QUIT signal received.\n");
                quit = 1;
        }
    }
    
    // other stuff you do goes here ...
    
    //--------------LOOP END
    SDL_mutexP(renderMutex);
    if(renderCallback!=NULL)
        renderCallback();
    if(quit==1)
        uiCallback = closeRenderThread;
    SDL_mutexV(renderMutex);
    SDL_mutexV(uiMutex);
}

SDL_WaitThread(thread, &threadReturnValue);
SDL_DestroyWindow(window);
SDL_Quit();


printf("Program terminated\n");
return 0;

}

static int RenderThread(void *ptr)
{
int FrameCount =0;
int quit = 0;
SDL_GLContext glcontext = SDL_GL_CreateContext(window);

while (quit == 0){
    //--------- LOOP BEGIN
    SDL_mutexP(uiMutex); //renderMutex first to avoid deadlock
    SDL_GL_MakeCurrent(window,glcontext);

    SDL_mutexP(renderMutex);
    
    //...DO YOUR RENDERING (OpenGL calls)
    glClearColor( (frameCount%255)/255.0f, 0, 0, 1); //just change color every frame
    glClear(GL_COLOR_BUFFER_BIT);

    SDL_Delay(10); //10 milliseconds delay
    SDL_GL_SwapWindow(window);


    frameCount ++;

    if(renderCallback == NULL)
        renderCallback = aknowledgeProcessedEvents;

    if(uiCallback!=NULL)
        if(uiCallback()==1)
            quit = 1;

    SDL_mutexV(renderMutex);
    SDL_mutexV(uiMutex); 
    //--------------LOOP END
}

SDL_GL_DeleteContext(glcontext); 
return FrameCount;

}

[/code]