SDL2 two windows in different threads - c++

I am trying to create a process with two windows. Each window has a different thread for drawing. The problem is that when I run the program, after a random amount of time something goes wrong and gives me a segmentation fault. Here is my code:
main.cpp
std::thread *thr1 = new std::thread(thread_func);
std::thread *thr2 = new std::thread(thread_func);
thread.cpp:
Window *win = new Window(display_name, 1024, 768);
Renderer *rend = win->CreateRenderer();
Texture *pic = new Texture(rend, path);
while (!quit)
{
usleep (10000);
pic->DrawToWindow(src_rect,rect);
rend->SetColor(255,255,255,255);
rend->DrawLine(10,10,300,300,4);
}
delete pic;
delete rend;
delete win;
Window.cpp:
Window::Window(std::string &name, uint32_t w, uint32_t h, uint32_t x, uint32_t y)
: window(nullptr),
windowRect()
{
if (!SDL_WasInit(SDL_INIT_VIDEO))
{
PDEBUG("ERROR: SDL Was not inited please init platform first!\n");
return;
}
//Create Window
window = SDL_CreateWindow(name.c_str(), x, y, w, h, SDL_WINDOW_OPENGL);
if (window == nullptr)
{
PDEBUG("ERROR: SDL_CreateWindow() %s\n", SDL_GetError());
return;
}
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
}
Window::~Window()
{
if (window != nullptr)
{
SDL_DestroyWindow(window);
window = nullptr;
}
}
void
Window::Flush()
{
SDL_GL_SwapWindow(window);
}
Renderer*
Window::CreateRenderer()
{
return new Renderer(this);
}
Renderer.cpp:
Renderer::Renderer(Window *win)
: window(win),
render(nullptr),
context()
{
if (win == nullptr)
{
PDEBUG("ERROR: Window is NULL\n");
return;
}
//Create Renderer
render = SDL_CreateRenderer(win->window, -1, SDL_RENDERER_ACCELERATED);
if (render == nullptr)
{
PDEBUG("ERROR: SDL_CreateRenderer(): %s\n", SDL_GetError());
return;
}
//Create Window OpenGL Context
//context = SDL_GL_CreateContext(win->window);
//if (SDL_GL_MakeCurrent(window->window, context) != 0)
// PDEBUG("ERROR: SDL_GL_MakeCurrent() %s\n", SDL_GetError());
Clear();
}
Renderer::~Renderer()
{
if (render != nullptr)
{
SDL_DestroyRenderer(render);
render = nullptr;
//SDL_GL_DeleteContext(context);
}
}
bool
Renderer::DrawLine(int xStart, int yStart, int xEnd, int yEnd, int width)
{
//if (SDL_GL_MakeCurrent(window->window, context) != 0)
// PDEBUG("ERROR: SDL_GL_MakeCurrent() %s\n", SDL_GetError());
//}
glLineWidth(width);
if (SDL_RenderDrawLine(render, xStart, yStart, xEnd, yEnd) < 0)
{
PDEBUG("ERROR: SDL_RenderDrawLine() %s\n", SDL_GetError());
return false;
}
return true;
}
Do I have to draw in only one thread for two windows, use synchronization to drawing, or use SDL_Thread for threads?

Did i have to draw in only one thread for two windows
Yes.
From the SDL2 threading documentation:
NOTE: You should not expect to be able to create a window, render, or receive events on any thread other than the main one. For platform-specific exceptions or complicated options ask on the mailing list or forum.

Hello I found a solution for 2 windows in different threads.
Here is example:
static bool quit = false;
void
thread_function(SDL_Window* win, SDL_Renderer *rend)
{
SDL_Event event;
while(!quit)
{
//DO THINGS with renderer and window. (Draw, Fill, Present Textures and others)
SDL_PollEvent(&event);
}
}
For Every thread you need to poll event because window events also are in Event Query.

Related

BGFX graphics not updating

A am trying to compile a simple bgfx program (from this link) and failing, because the window is not updating. Closing the window is fine, so i think the problem is in bgfx. I also tried other tutorials and those didn't work either
Code:
#include <stdio.h>
#include <bgfx/bgfx.h>
#include <bgfx/platform.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>
SDL_Window* window = NULL;
const int WIDTH = 640;
const int HEIGHT = 480;
int main (int argc, char* args[]) {
// Initialize SDL systems
if(SDL_Init( SDL_INIT_VIDEO ) < 0) {
printf("SDL could not initialize! SDL_Error: %s\n",
SDL_GetError());
}
else {
//Create a window
window = SDL_CreateWindow("BGFX Tutorial",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
WIDTH, HEIGHT,
SDL_WINDOW_SHOWN);
if(window == NULL) {
printf("Window could not be created! SDL_Error: %s\n",
SDL_GetError());
}
}
// Collect information about the window from SDL
SDL_SysWMinfo wmi;
SDL_VERSION(&wmi.version);
if (!SDL_GetWindowWMInfo(window, &wmi)) {
return 1;
}
bgfx::PlatformData pd;
// and give the pointer to the window to pd
pd.ndt = wmi.info.x11.display;
pd.nwh = (void*)(uintptr_t)wmi.info.x11.window;
// Tell bgfx about the platform and window
bgfx::setPlatformData(pd);
// Render an empty frame
bgfx::renderFrame();
// Initialize bgfx
bgfx::init();
// Reset window
bgfx::reset(WIDTH, HEIGHT, BGFX_RESET_VSYNC);
// Enable debug text.
bgfx::setDebug(BGFX_DEBUG_TEXT /*| BGFX_DEBUG_STATS*/);
// Set view rectangle for 0th view
bgfx::setViewRect(0, 0, 0, uint16_t(WIDTH), uint16_t(HEIGHT));
// Clear the view rect
bgfx::setViewClear(0,
BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH,
0x443355FF, 1.0f, 0);
// Set empty primitive on screen
bgfx::touch(0);
// Poll for events and wait till user closes window
bool quit = false;
SDL_Event currentEvent;
while(!quit) {
while(SDL_PollEvent(&currentEvent) != 0) {
if(currentEvent.type == SDL_QUIT) {
quit = true;
}
}
}
// Free up window
SDL_DestroyWindow(window);
// Shutdown SDL
SDL_Quit();
return 0;
}
Why is this happening, and how to fix it?
P.S.: I am using kali linux

Empty SDL2 window taking lots (40%+) GPU to render?

I've been trying to learn how to use SDL2, and am trying to follow the tutorials here for that. From example 7 (texture loading / hardware rendering), I've put together this stripped down example. As far as I can tell, the code is only calling SDL_RenderClear() and SDL_RenderPresent() in the render loop, VSYNC'd to my monitor (100 Hz in this case). However, I'm seeing Windows report 40% GPU utilization when doing this, which seems high for doing nothing. My GPU sits at 1-2% utilization when the SDL2 program is not running.
Removing just the SDL_RenderPresent() call brings the usage all the way down to 1-2% again, but then nothing gets drawn, which makes me think that the issue is either in SDL2's rendering, or (much more likely), how I've configured it.
Is this high GPU utilization (when doing nothing) expected? Is there anything I can do to minimize the GPU utilization (while still using hardware rendering)?
===================================
Machine details:
Windows 10
Threadripper 3970x CPU (3.7 GHz 32 core)
256 GB RAM DDR4 3200 MHz
1x RTX 3090 GPU
3x 1440p 100Hz monitors
GPU utilization (shown via Task Manager and Xbox Game Bar):
Code:
#define SDL_MAIN_HANDLED
/*This source code copyrighted by Lazy Foo' Productions (2004-2020)
and may not be redistributed without written permission.*/
// Using SDL, SDL_image, standard IO, and strings
#include <SDL.h>
#include <stdio.h>
#include <string>
// Screen dimension constants
const int SCREEN_WIDTH = 1920;
const int SCREEN_HEIGHT = 1080;
// Starts up SDL and creates window
bool init();
// Frees media and shuts down SDL
void close();
// The window we'll be rendering to
SDL_Window* gWindow = NULL;
// The window renderer
SDL_Renderer* gRenderer = NULL;
bool init() {
// Initialization flag
bool success = true;
// Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
success = false;
} else {
// Create window
gWindow = SDL_CreateWindow(
"SDL Tutorial",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SDL_WINDOW_SHOWN);
if (gWindow == NULL) {
printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
} else {
// Create renderer for window
gRenderer =
SDL_CreateRenderer(gWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (gRenderer == NULL) {
printf("Renderer could not be created! SDL Error: %s\n", SDL_GetError());
success = false;
} else {
// Initialize renderer color
SDL_SetRenderDrawColor(gRenderer, 0xFF, 0x00, 0x00, 0x00);
}
}
}
return success;
}
void close() {
// Destroy window
SDL_DestroyRenderer(gRenderer);
SDL_DestroyWindow(gWindow);
gWindow = NULL;
gRenderer = NULL;
// Quit SDL subsystems
SDL_Quit();
}
int main(int argc, char* args[]) {
// Start up SDL and create window
if (!init()) {
printf("Failed to initialize!\n");
} else {
// Main loop flag
bool quit = false;
// Event handler
SDL_Event e;
// While application is running
while (!quit) {
// Handle events on queue
while (SDL_PollEvent(&e) != 0) {
// User requests quit
if (e.type == SDL_QUIT) {
quit = true;
}
}
// Clear screen
SDL_RenderClear(gRenderer);
//Update screen
SDL_RenderPresent( gRenderer );
}
}
// Free resources and close SDL
close();
return 0;
}

SDL2 cannot open any BMP files

Im trying to play around with SDL2 following lazyfoo's tutorials to get accustomed to it, but even the basic most program doesn't work properly. I can open a basic blank window with no image and keep it open, but as soon as I try to open a BMP file in a window, it all acts weird and doesn't work anymore. My code, that initially shows no errors:
#include <SDL2/SDL.h>
#include <cstdio>
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
SDL_Window *newWindow = nullptr;
SDL_Surface *loadedImage = nullptr;
SDL_Surface *screenSurface = nullptr;
bool quit = false;
SDL_Event event;
bool initWindow() {
bool state = true;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
std::puts("Error init");
state = false;
}
else
{
newWindow = SDL_CreateWindow("Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT, SDL_WINDOWEVENT_SHOWN);
if (nullptr == newWindow)
{
std::puts("Error window");
state = false;
}
else
{
screenSurface = SDL_GetWindowSurface(newWindow);
}
}
return state;
}
bool loadMedia() {
bool success = true;
loadedImage = SDL_LoadBMP("LAND3.BMP");
if (loadedImage == nullptr)
{
printf("Error image %s \n", SDL_GetError());
success = false;
}
return success;
}
void closeWindow() {
SDL_FreeSurface(loadedImage);
loadedImage = nullptr;
SDL_DestroyWindow(newWindow);
newWindow = nullptr;
SDL_Quit();
}
int main(int argc, char *args[]) {
if (!initWindow())
{
std::puts("Error init main");
}
else
{
if (!loadMedia())
{
std::puts("Error image main");
}
else
{
while (!quit)
{
if (event.type == SDL_QUIT)
{
quit = true;
}
else
{
SDL_BlitSurface(loadedImage, nullptr, screenSurface, nullptr);
SDL_UpdateWindowSurface(newWindow);
}
}
}
}
closeWindow();
return 0;
}
When running this program, I get no errors but the UI starts acting all crazy; resolution gets very small(way smaller than 480p set up by me), all windows resize and this lasts for a brief period. If I replace the while(!quit) loop with a SDL_Delay(1000), this behaviour lasts approximately as long as the delay.
Initially my suspicion was that the file I was using the first time was corrupted(I had just renamed an existing picture), but then I downloaded a sample BMP file and nothing changed.
When using the debugger I get an error from loadMedia() that the file could not be loaded, regardless of which one I use. I am using MinGW and cLion.
What might be the issue?
The constant SDL_WINDOWEVENT_SHOWN is not a valid flag for the function SDL_CreateWindow. That constant is not intended as a flag, but as an event ID. You probably meant to use the constant SDL_WINDOW_SHOWN instead.
The constant SDL_WINDOWEVENT_SHOWN happens to have the same value as SDL_WINDOW_FULLSCREEN (both have the value 1). Therefore, your incorrect function call
newWindow = SDL_CreateWindow("Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT, SDL_WINDOWEVENT_SHOWN);
is equivalent to:
newWindow = SDL_CreateWindow("Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SCREEN_WIDTH,
SCREEN_HEIGHT, SDL_WINDOW_FULLSCREEN);
In other words, you are unintentionally asking SDL to create the window in 640*480 fullscreen mode. That is probably the reason for your desktop being resized.
The reason for the file not being found is probably because the file is not in your program's current working directory. You can either ensure that the file is in that directory or you can use an absolute path to the file, for example "C:\\Users\\MyUsername\\Desktop\\LAND3.BMP".
I doubt that your problem of not being able to kill your application using the task manager is the fault of SDL. It is probably a design flaw of Microsoft Windows. See this link on how to make the task manager more accessible from a hung fullscreen application.

SDL2 - Window cannot be reopened

I am writing a simple SDL2 application with 2 windows.
The first window (window variable) is shown when the application starts, the second one (window2 variable) is hidden.
Expected behavior:
I click on the first window, the second window pops up, then I close the second window.
And I can close and reopen the window as much as I want.
Observed behavior:
Once I close the second window, if I reclick in the first window, the second window doesn't appear as expected.
As stated in my comment: the window doesn't appear in my window manager (i.e. Wayland).
The code:
#include <SDL2/SDL.h>
int main()
{
SDL_Window* window, *window2 = NULL;
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
return 1;
} else {
window = SDL_CreateWindow("ONE", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
window2 = SDL_CreateWindow("TWO", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, 320, 240, SDL_WINDOW_HIDDEN);
if (window == NULL || window2 == NULL) {
SDL_DestroyWindow(window);
SDL_DestroyWindow(window2);
return 1;
}
bool running = true;
while(running) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_WINDOWEVENT) {
if (event.window.event == SDL_WINDOWEVENT_CLOSE) {
if (SDL_GetWindowID(window) == event.window.windowID) {
running = false;
} else {
SDL_HideWindow(window2);
}
}
} else if (event.type == SDL_MOUSEBUTTONDOWN) {
SDL_ShowWindow(window2);
}
}
}
}
SDL_DestroyWindow(window);
SDL_DestroyWindow(window2);
SDL_Quit();
return 0;
}
This is an SDL bug that may or may not have been fixed by this patch.
You should call SDL_RaiseWindow to place the second window on top of the other.
From lazyfoo's legendary SDL tutorials:
void LWindow::focus()
{
//Restore window if needed
if( !mShown )
SDL_ShowWindow( mWindow );
//Move window forward
SDL_RaiseWindow( mWindow );
}

C++ SDL Reaction Time Game

Me and my friend needs to create a reaction time game.
Something like this.
Right now we just managed to show an image of the red button, but we need help how to make a hitbox, where if you click the red button, it becomes green.
Would someone could show us how?
We are using SDL, I guess that's important to mention.
Here is our code so far:
#include <SDL/SDL.h>
void Plot(SDL_Surface *sur, int x, int y, SDL_Surface *dest)
{
SDL_Rect rect = {x, y};
SDL_BlitSurface(sur, NULL, dest, &rect);
}
SDL_Surface *LoadImage(const char *filename)
{
SDL_Surface *sur = NULL;
sur = SDL_LoadBMP(filename);
if(sur == NULL)
{
printf("Img not found");
}
SDL_Surface *opsur = NULL;
if(sur != NULL)
{
opsur = SDL_DisplayFormat(sur);
SDL_SetColorKey(opsur, SDL_SRCCOLORKEY, 0xFFFFFF);
if(opsur != NULL)
SDL_FreeSurface(sur);
}
return opsur;
}
int main(int argc, char **argv)
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
SDL_WM_SetCaption("Eksamensprojekt", NULL);
SDL_Event Event;
bool Running = true;
SDL_Surface *sur = LoadImage("Red.bmp");
while(Running)
{
while(SDL_PollEvent(&Event))
{
if(Event.type == SDL_QUIT)
Running = false;
}
SDL_FillRect(screen, &screen->clip_rect, 0x000000);
Plot(sur, 215, 140, screen);
SDL_Flip(screen);
}
}
You can use SDL_Rect as a hit box. You can use SDL's own event handling system for checking when mouse button is clicked and the position of it. Then you just need to check if the mouse position is within the SDL_Rect.
You can read more about SDL here.
So... a little help on the way. You have a main loop and you pull events.
if ( event.type == SDL_MOUSEBUTTONDOWN ){
//Get mouse coordinates
int x = event.motion.x;
int y = event.motion.y;
//If the mouse is over the button
if( checkSpriteCollision( x, y ) ){
// Yay, you hit the button
doThings();
}
else
{
// D'oh I missed
}
}
Add this to the while, that will at least get you started.
Like this?
while(Running)
{
while(SDL_PollEvent(&Event))
{
if(Event.type == SDL_QUIT)
Running = false;
if ( event.type == SDL_MOUSEBUTTONDOWN ){
//Get mouse coordinates
int x = event.motion.x;
int y = event.motion.y;
//If the mouse is over the button
if( checkSpriteCollision( x, y ) ){
// Yay, you hit the button
doThings();
}
else {
// D'oh I missed
}
}
}
SDL_FillRect(screen, &screen->clip_rect, 0x000000);
Plot(sur, 215, 140, screen);
SDL_Flip(screen);
}
}