gpu errors
This commit is contained in:
@@ -17,11 +17,16 @@ namespace Game::Renderer {
|
|||||||
|
|
||||||
// Build the texture for the font; Call getSDLTexture() afterwards
|
// Build the texture for the font; Call getSDLTexture() afterwards
|
||||||
void build(SDL_Color color, std::string text);
|
void build(SDL_Color color, std::string text);
|
||||||
|
// Rebuild GPU-backed texture after a renderer/device reset
|
||||||
|
bool reload(SDL_Renderer* renderer);
|
||||||
|
|
||||||
SDL_Texture* getSDLTexture();
|
SDL_Texture* getSDLTexture();
|
||||||
std::string getId();
|
std::string getId();
|
||||||
private:
|
private:
|
||||||
TTF_Font* mFont;
|
TTF_Font* mFont;
|
||||||
SDL_Renderer* mRenderer;
|
SDL_Renderer* mRenderer;
|
||||||
|
// Remember last build params so we can rebuild fonts on device reset
|
||||||
|
std::string mLastText;
|
||||||
|
SDL_Color mLastColor;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -21,10 +21,15 @@ namespace Game::Renderer {
|
|||||||
float getHeight();
|
float getHeight();
|
||||||
bool isTiled() { return mIsTiled; }
|
bool isTiled() { return mIsTiled; }
|
||||||
void setTiled(bool tiled) { mIsTiled = tiled; }
|
void setTiled(bool tiled) { mIsTiled = tiled; }
|
||||||
|
// Reload GPU-backed texture using a new renderer after device reset
|
||||||
|
virtual bool reload(SDL_Renderer* renderer);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SDL_Texture* mTex;
|
SDL_Texture* mTex;
|
||||||
std::string mId;
|
std::string mId;
|
||||||
|
// For textures created from disk, store the path so we can reload on device reset
|
||||||
|
std::string mPath;
|
||||||
|
bool mIsFromFile = false;
|
||||||
private:
|
private:
|
||||||
bool mIsTiled = false; // Whether the texture is a tileset that should be rendered as a single tile or not
|
bool mIsTiled = false; // Whether the texture is a tileset that should be rendered as a single tile or not
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ namespace Game::Renderer {
|
|||||||
void Font::build(SDL_Color color, std::string text) {
|
void Font::build(SDL_Color color, std::string text) {
|
||||||
if (!mFont) { return; }
|
if (!mFont) { return; }
|
||||||
|
|
||||||
|
// Store last build parameters so we can rebuild after device resets
|
||||||
|
mLastText = text;
|
||||||
|
mLastColor = color;
|
||||||
|
|
||||||
SDL_Surface* surf = TTF_RenderText_Blended(mFont, text.c_str(), text.size(), color);
|
SDL_Surface* surf = TTF_RenderText_Blended(mFont, text.c_str(), text.size(), color);
|
||||||
if (!surf) {
|
if (!surf) {
|
||||||
ERROR("TTF_RenderText_Blended Error: " << SDL_GetError() << " (This object may be unusuable)");
|
ERROR("TTF_RenderText_Blended Error: " << SDL_GetError() << " (This object may be unusuable)");
|
||||||
@@ -57,6 +61,14 @@ namespace Game::Renderer {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Font::reload(SDL_Renderer* renderer) {
|
||||||
|
mRenderer = renderer;
|
||||||
|
if (mLastText.empty()) return false;
|
||||||
|
// Rebuild the texture using the stored last text and color
|
||||||
|
build(mLastColor, mLastText);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_Texture* Font::getSDLTexture() { return mTex; }
|
SDL_Texture* Font::getSDLTexture() { return mTex; }
|
||||||
std::string Font::getId() { return mId; }
|
std::string Font::getId() { return mId; }
|
||||||
}
|
}
|
||||||
@@ -24,12 +24,18 @@ namespace Game::Renderer {
|
|||||||
bool Renderer::init(SDL_Window* window) {
|
bool Renderer::init(SDL_Window* window) {
|
||||||
// Request VSync before/at renderer setup; some backends honor this hint.
|
// Request VSync before/at renderer setup; some backends honor this hint.
|
||||||
SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");
|
SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");
|
||||||
|
// Create renderer using the portable API. Some SDL3 backends may not support the old flags,
|
||||||
|
// so fall back to a software renderer via hint if the first attempt fails.
|
||||||
mRenderer = SDL_CreateRenderer(window, nullptr);
|
mRenderer = SDL_CreateRenderer(window, nullptr);
|
||||||
if (!mRenderer) {
|
if (!mRenderer) {
|
||||||
std::string errorMsg = std::string("Neuspešno ustvarjanje rendererja: ") + std::string(SDL_GetError());
|
WARN("Renderer creation failed, attempting software renderer: " << SDL_GetError());
|
||||||
ERROR(errorMsg.c_str());
|
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
||||||
return false;
|
mRenderer = SDL_CreateRenderer(window, nullptr);
|
||||||
|
if (!mRenderer) {
|
||||||
|
std::string errorMsg = std::string("Neuspešno ustvarjanje rendererja: ") + std::string(SDL_GetError());
|
||||||
|
ERROR(errorMsg.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mVSyncEnabled = SDL_SetRenderVSync(mRenderer, 1);
|
mVSyncEnabled = SDL_SetRenderVSync(mRenderer, 1);
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ namespace Game::Renderer {
|
|||||||
|
|
||||||
Texture::Texture(const std::string& path, SDL_Renderer* renderer, std::string id)
|
Texture::Texture(const std::string& path, SDL_Renderer* renderer, std::string id)
|
||||||
: mTex(nullptr), mId(id) {
|
: mTex(nullptr), mId(id) {
|
||||||
|
mPath = path;
|
||||||
|
mIsFromFile = true;
|
||||||
|
|
||||||
SDL_Surface* surf = IMG_Load(path.c_str());
|
SDL_Surface* surf = IMG_Load(path.c_str());
|
||||||
if (!surf) {
|
if (!surf) {
|
||||||
ERROR("Failed to load image at " << path);
|
ERROR("Failed to load image at " << path);
|
||||||
@@ -44,6 +47,34 @@ namespace Game::Renderer {
|
|||||||
LOG("Tekstura '" << mId << "' uničena")
|
LOG("Tekstura '" << mId << "' uničena")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Texture::reload(SDL_Renderer* renderer) {
|
||||||
|
if (!mIsFromFile || mPath.empty()) return false;
|
||||||
|
if (mTex) {
|
||||||
|
SDL_DestroyTexture(mTex);
|
||||||
|
mTex = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Surface* surf = IMG_Load(mPath.c_str());
|
||||||
|
if (!surf) {
|
||||||
|
ERROR("Failed to reload image at " << mPath);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTex = SDL_CreateTextureFromSurface(renderer, surf);
|
||||||
|
SDL_DestroySurface(surf);
|
||||||
|
if (!mTex) {
|
||||||
|
ERROR("Failed to create texture from surface when reloading " << mPath << ": " << SDL_GetError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore scale mode
|
||||||
|
if (!SDL_SetTextureScaleMode(mTex, SDL_SCALEMODE_NEAREST)) {
|
||||||
|
WARN("Failed to set texture scale mode to NEAREST for '" << mId << "' during reload: " << SDL_GetError());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
SDL_Texture* Texture::getSDLTexture() {
|
SDL_Texture* Texture::getSDLTexture() {
|
||||||
return mTex;
|
return mTex;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <window/window.hpp>
|
#include <window/window.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <renderer/texture.hpp>
|
||||||
|
|
||||||
namespace Game::Window {
|
namespace Game::Window {
|
||||||
std::mutex Window::sMutex;
|
std::mutex Window::sMutex;
|
||||||
@@ -113,6 +114,45 @@ namespace Game::Window {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Renderer device/targets reset (GPU device removed) - attempt to re-create renderer and reload textures
|
||||||
|
if (event.type == SDL_EVENT_RENDER_DEVICE_RESET || event.type == SDL_EVENT_RENDER_TARGETS_RESET) {
|
||||||
|
LOG("Renderer device reset event received: attempting to reinitialize renderer and reload textures");
|
||||||
|
|
||||||
|
// Destroy current renderer and try to re-init
|
||||||
|
mRenderer.destroy();
|
||||||
|
bool reinitOk = mRenderer.init(mWindow);
|
||||||
|
|
||||||
|
// If reinit failed, try forcing the software renderer
|
||||||
|
if (!reinitOk) {
|
||||||
|
WARN("Renderer re-init failed, forcing software renderer fallback");
|
||||||
|
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
||||||
|
reinitOk = mRenderer.init(mWindow);
|
||||||
|
if (!reinitOk) {
|
||||||
|
ERROR("Software renderer fallback also failed: " << SDL_GetError());
|
||||||
|
// Unable to recover; stop running to avoid crashes
|
||||||
|
mRunning = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rebuild GPU textures for all entities (fonts and file-based textures)
|
||||||
|
State::GameState::getInstance().withEntitiesLocked([&](auto& entities) {
|
||||||
|
for (auto& [name, entity] : entities) {
|
||||||
|
(void)name;
|
||||||
|
if (entity) {
|
||||||
|
auto tex = entity->getTexture();
|
||||||
|
if (tex) {
|
||||||
|
try {
|
||||||
|
tex->reload(mRenderer.getSDLRenderer());
|
||||||
|
} catch (...) {
|
||||||
|
WARN("Exception while reloading texture for entity: " << entity->getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entity->onWindowResized(mLastWindowWidth, mLastWindowHeight); // ensure layout is correct
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mRenderer.renderFrame();
|
mRenderer.renderFrame();
|
||||||
|
|||||||
Reference in New Issue
Block a user