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.
Related
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(¤tEvent) != 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
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;
}
I'm doing Lazy Foo's tutorial on SDL (I'm using SDL2-2.0.9), and at the texture rendering part I encountered the following problem: the program compiles and runs as expected, no issue here, but when I close the window, the console doesn't close and the process continues running, so I have to close the console separately.
When I tried to debug it, I found out that the program indeed leaves the main cycle and reaches the "return 0" line in the main function successfully, but then it just hangs like that until I close the console.
The issue is only present when I use the SDL renderer with any option other than SDL_RENDERER_SOFTWARE. If I use SDL_RENDERER_SOFTWARE - the program closes as expected. With other options it stays at "return 0" running other threads (crypt32.dll, ntdll.dll and nvd3dum, in this order in the thread view, meaning that the process is stuck in crypt32).
I'm aware that my main function is not the "real main" as it has been hijacked by SDL, so exit(0) works fine as an ad-hoc solution. But I want to know, why exactly does that happen and is there any other way to fix this, so that I don't have to use exit(0) ?
Here is an example (simplified) code, which demonstrates this issue for me:
#include "SDL.h"
#include <stdio.h>
int main(int argc, char *argv[]) {
SDL_Window *win = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *bitmapTex = NULL;
SDL_Surface *bitmapSurface = NULL;
int width = 640, height = 480;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("Could not initialize SDL");
return 1;
}
win = SDL_CreateWindow("Hello World", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, 0);
renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
bitmapSurface = SDL_LoadBMP("res/x.bmp");
bitmapTex = SDL_CreateTextureFromSurface(renderer, bitmapSurface);
SDL_FreeSurface(bitmapSurface);
bool quit = false;
while (!quit) {
SDL_Event e;
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = true;
}
}
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, bitmapTex, NULL, NULL);
SDL_RenderPresent(renderer);
}
SDL_DestroyTexture(bitmapTex);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
printf("REACHED RETURN 0");
return 0;
}
Works as intended, but after closing the window I see "REACHED RETURN 0" printed in console and that's it, the console stays there. The code can be simplified further, the issue will be present as long as there is an instance of SDL_Renderer created.
UPD: The callstack during the hanging:
> ntdll.dll!_NtWaitForMultipleObjects#20()
KernelBase.dll!_WaitForMultipleObjectsEx#20()
crypt32.dll!ILS_WaitForThreadProc()
kernel32.dll!#BaseThreadInitThunk#12()
ntdll.dll!__RtlUserThreadStart()
ntdll.dll!__RtlUserThreadStart#8()
UPD2: The problem is not with the loop at all, I created the simplest application where I just create a window and a renderer and then return 0, it still gives me a hanging console. Like this:
#include <SDL.h>
int main(int argc, char* args[])
{
if (SDL_Init(SDL_INIT_VIDEO) < 0) return 1;
SDL_Window* window = SDL_CreateWindow("Test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
return 0;
}
Same thing when I destroy them properly. The problem is in the renderer.
UPD3: Here is the Parallel Stack window during the "hanging". There is no "main" thread since I close it successfully, these are the threads which stop the program from closing properly. Other than that, it doesn't give me any understanding of the problem.
i am currently reentering programming in C++ to write a small game. I am using Visual Studio 2017 and SDL2. I am following a series of tutorials to get into SDL. My problem seems to be related to me not entirely understanding the workings of pointers in c++. I am passing a pointer to a function as an argument and want to use it within this function as an argument to another function which returns a pointer to a SDL_Surface. Following my code:
init SDL:
SDL_Surface* init(SDL_Window *window)
{
SDL_Surface *screenSurface = nullptr;
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
printf("%s", "Error in init");
}
else
{
screenSurface = SDL_GetWindowSurface(window);
}
return screenSurface;
}
load bmp:
SDL_Surface* loadMedia(const char file[])
{
SDL_Surface *image = SDL_LoadBMP(file);
if (image == nullptr)
{
printf("%s", "Error in loadMedia");
}
return image;
}
main:
int main(int argc, char *argv[])
{
SDL_Window *window = SDL_CreateWindow("xyz", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
SDL_Surface *screenSurface = init(window);
if (screenSurface == nullptr)
{
printf("%s", "surface is null");
}
SDL_Surface *image = loadMedia("resources/images/village.bmp");
SDL_BlitSurface(image, NULL, screenSurface, NULL);
SDL_UpdateWindowSurface(window);
SDL_Delay(1000);
SDL_FreeSurface(image);
image = nullptr;
SDL_DestroyWindow(window);
window = nullptr;
SDL_Quit();
return 0;
}
if i create
SDL_Window *window = SDL_CreateWindow("xyz",...)
as a global variable and initialize it within init(), everything works fine and screenSurface is initialized with a valid value. As soon as i do as it is in the code, pass the pointer window to init() to create the surface there and then return screenSurface, screenSurface = SDL_GetWindowSurface(window) returns null.
I have been programming mostly SAS and Java the last years and didnt touch c++ for several years, so im sure its just a minor misunderstanding on my side but i cannot figure out what it is.
Thx in advance :)
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 );
}