mirror of
https://github.com/raysan5/raylib.git
synced 2025-12-20 05:15:37 +00:00
REVIEWED: Avoid program crash if GPU data is tried to be loaded before InitWindow() #4751
Following raylib design, a warning log message is shown and program can continue execution. Some early return checks have been added on most critical functions. [rtext] Previous implementation checking `isGpuReady` cross-module variable is not needed any more, resulting in a more decoupled code, load failure is managed at rlgl level
This commit is contained in:
@@ -84,7 +84,6 @@ typedef struct {
|
||||
// Global Variables Definition
|
||||
//----------------------------------------------------------------------------------
|
||||
extern CoreData CORE; // Global CORE state context
|
||||
extern bool isGpuReady; // Flag to note GPU has been initialized successfully
|
||||
static PlatformData platform = { 0 }; // Platform specific data
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
@@ -1042,7 +1041,6 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
|
||||
// Initialize OpenGL context (states and resources)
|
||||
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
|
||||
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
|
||||
isGpuReady = true;
|
||||
|
||||
// Setup default viewport
|
||||
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height
|
||||
|
||||
19
src/rcore.c
19
src/rcore.c
@@ -387,11 +387,6 @@ RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported s
|
||||
|
||||
CoreData CORE = { 0 }; // Global CORE state context
|
||||
|
||||
// Flag to note GPU acceleration is available,
|
||||
// referenced from other modules to support GPU data loading
|
||||
// NOTE: Useful to allow Texture, RenderTexture, Font.texture, Mesh.vaoId/vboId, Shader loading
|
||||
bool isGpuReady = false;
|
||||
|
||||
#if defined(SUPPORT_SCREEN_CAPTURE)
|
||||
static int screenshotCounter = 0; // Screenshots counter
|
||||
#endif
|
||||
@@ -697,7 +692,6 @@ void InitWindow(int width, int height, const char *title)
|
||||
// Initialize rlgl default data (buffers and shaders)
|
||||
// NOTE: Current fbo size stored as globals in rlgl for convenience
|
||||
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
|
||||
isGpuReady = true; // Flag to note GPU has been initialized successfully
|
||||
|
||||
// Setup default viewport
|
||||
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
|
||||
@@ -1266,7 +1260,14 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
|
||||
|
||||
shader.id = rlLoadShaderCode(vsCode, fsCode);
|
||||
|
||||
if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault();
|
||||
if (shader.id == 0)
|
||||
{
|
||||
// Shader could not be loaded but we still load the location points to avoid potential crashes
|
||||
// NOTE: All locations set to -1 (no location)
|
||||
shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
|
||||
for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
|
||||
}
|
||||
else if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault();
|
||||
else if (shader.id > 0)
|
||||
{
|
||||
// After custom shader loading, we TRY to set default location names
|
||||
@@ -1282,9 +1283,9 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
|
||||
|
||||
// NOTE: If any location is not found, loc point becomes -1
|
||||
|
||||
// Load shader locations array
|
||||
// NOTE: All locations set to -1 (no location)
|
||||
shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
|
||||
|
||||
// All locations reset to -1 (no location)
|
||||
for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
|
||||
|
||||
// Get handles to GLSL input attribute locations
|
||||
|
||||
21
src/rlgl.h
21
src/rlgl.h
@@ -1153,6 +1153,7 @@ static double rlCullDistanceFar = RL_CULL_DISTANCE_FAR;
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
static rlglData RLGL = { 0 };
|
||||
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
|
||||
static bool isGpuReady = false;
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_ES2) && !defined(GRAPHICS_API_OPENGL_ES3)
|
||||
// NOTE: VAO functionality is exposed through extensions (OES)
|
||||
@@ -2283,6 +2284,8 @@ static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint
|
||||
// Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states
|
||||
void rlglInit(int width, int height)
|
||||
{
|
||||
isGpuReady = true;
|
||||
|
||||
// Enable OpenGL debug context if required
|
||||
#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43)
|
||||
if ((glDebugMessageCallback != NULL) && (glDebugMessageControl != NULL))
|
||||
@@ -2395,6 +2398,7 @@ void rlglClose(void)
|
||||
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
|
||||
swClose(); // Unload sofware renderer resources
|
||||
#endif
|
||||
isGpuReady = false;
|
||||
}
|
||||
|
||||
// Load OpenGL extensions
|
||||
@@ -2799,6 +2803,7 @@ int *rlGetShaderLocsDefault(void)
|
||||
rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
|
||||
{
|
||||
rlRenderBatch batch = { 0 };
|
||||
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return batch; }
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes)
|
||||
@@ -3253,6 +3258,7 @@ bool rlCheckRenderBatchLimit(int vCount)
|
||||
unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipmapCount)
|
||||
{
|
||||
unsigned int id = 0;
|
||||
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding
|
||||
|
||||
@@ -3411,6 +3417,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
|
||||
unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer)
|
||||
{
|
||||
unsigned int id = 0;
|
||||
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
// In case depth textures not supported, we force renderbuffer usage
|
||||
@@ -3469,6 +3476,7 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer)
|
||||
unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mipmapCount)
|
||||
{
|
||||
unsigned int id = 0;
|
||||
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
int mipSize = size;
|
||||
@@ -3813,6 +3821,7 @@ unsigned char *rlReadScreenPixels(int width, int height)
|
||||
unsigned int rlLoadFramebuffer(void)
|
||||
{
|
||||
unsigned int fboId = 0;
|
||||
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return fboId; }
|
||||
|
||||
#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT)
|
||||
glGenFramebuffers(1, &fboId); // Create the framebuffer object
|
||||
@@ -3928,6 +3937,7 @@ void rlUnloadFramebuffer(unsigned int id)
|
||||
unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic)
|
||||
{
|
||||
unsigned int id = 0;
|
||||
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
glGenBuffers(1, &id);
|
||||
@@ -3942,6 +3952,7 @@ unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic)
|
||||
unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic)
|
||||
{
|
||||
unsigned int id = 0;
|
||||
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
glGenBuffers(1, &id);
|
||||
@@ -4107,12 +4118,12 @@ void rlDisableStatePointer(int vertexAttribType)
|
||||
unsigned int rlLoadVertexArray(void)
|
||||
{
|
||||
unsigned int vaoId = 0;
|
||||
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return vaoId; }
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
if (RLGL.ExtSupported.vao)
|
||||
{
|
||||
glGenVertexArrays(1, &vaoId);
|
||||
}
|
||||
if (RLGL.ExtSupported.vao) glGenVertexArrays(1, &vaoId);
|
||||
#endif
|
||||
|
||||
return vaoId;
|
||||
}
|
||||
|
||||
@@ -4167,6 +4178,7 @@ void rlUnloadVertexBuffer(unsigned int vboId)
|
||||
unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
|
||||
{
|
||||
unsigned int id = 0;
|
||||
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
unsigned int vertexShaderId = 0;
|
||||
@@ -4309,6 +4321,7 @@ unsigned int rlCompileShader(const char *shaderCode, int type)
|
||||
unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
|
||||
{
|
||||
unsigned int programId = 0;
|
||||
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return programId; }
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
GLint success = 0;
|
||||
|
||||
@@ -1282,6 +1282,8 @@ void UploadMesh(Mesh *mesh, bool dynamic)
|
||||
|
||||
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
|
||||
mesh->vaoId = rlLoadVertexArray();
|
||||
if (mesh->vaoId == 0) return;
|
||||
|
||||
rlEnableVertexArray(mesh->vaoId);
|
||||
|
||||
// NOTE: Vertex attributes must be uploaded considering default locations points and available vertex data
|
||||
@@ -1470,6 +1472,8 @@ void DrawMesh(Mesh mesh, Material material, Matrix transform)
|
||||
// Bind shader program
|
||||
rlEnableShader(material.shader.id);
|
||||
|
||||
if (material.shader.locs == NULL) return;
|
||||
|
||||
// Send required data to shader (matrices, values)
|
||||
//-----------------------------------------------------
|
||||
// Upload to shader material.colDiffuse
|
||||
|
||||
51
src/rtext.c
51
src/rtext.c
@@ -127,13 +127,12 @@
|
||||
//----------------------------------------------------------------------------------
|
||||
// Global variables
|
||||
//----------------------------------------------------------------------------------
|
||||
extern bool isGpuReady;
|
||||
#if defined(SUPPORT_DEFAULT_FONT)
|
||||
// Default font provided by raylib
|
||||
// NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
|
||||
static Font defaultFont = { 0 };
|
||||
#endif
|
||||
static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines)
|
||||
static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines)
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// Other Modules Functions Declaration (required by text)
|
||||
@@ -164,8 +163,8 @@ extern void LoadFontDefault(void)
|
||||
{
|
||||
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
|
||||
|
||||
// Check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return
|
||||
if ((defaultFont.glyphs != NULL) && !isGpuReady) return;
|
||||
// Check to see if we have already allocated the font for an image, and if we don't need to upload, then just return
|
||||
if (defaultFont.glyphs != NULL) return;
|
||||
|
||||
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
|
||||
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
|
||||
@@ -263,17 +262,14 @@ extern void LoadFontDefault(void)
|
||||
counter++;
|
||||
}
|
||||
|
||||
if (isGpuReady)
|
||||
{
|
||||
defaultFont.texture = LoadTextureFromImage(imFont);
|
||||
defaultFont.texture = LoadTextureFromImage(imFont);
|
||||
|
||||
// we have already loaded the font glyph data an image, and the GPU is ready, we are done
|
||||
// if we don't do this, we will leak memory by reallocating the glyphs and rects
|
||||
if (defaultFont.glyphs != NULL)
|
||||
{
|
||||
UnloadImage(imFont);
|
||||
return;
|
||||
}
|
||||
// we have already loaded the font glyph data an image, and the GPU is ready, we are done
|
||||
// if we don't do this, we will leak memory by reallocating the glyphs and rects
|
||||
if (defaultFont.glyphs != NULL)
|
||||
{
|
||||
UnloadImage(imFont);
|
||||
return;
|
||||
}
|
||||
|
||||
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
|
||||
@@ -330,7 +326,7 @@ extern void LoadFontDefault(void)
|
||||
extern void UnloadFontDefault(void)
|
||||
{
|
||||
for (int i = 0; i < defaultFont.glyphCount; i++) UnloadImage(defaultFont.glyphs[i].image);
|
||||
if (isGpuReady) UnloadTexture(defaultFont.texture);
|
||||
UnloadTexture(defaultFont.texture);
|
||||
RL_FREE(defaultFont.glyphs);
|
||||
RL_FREE(defaultFont.recs);
|
||||
defaultFont.glyphCount = 0;
|
||||
@@ -384,17 +380,15 @@ Font LoadFont(const char *fileName)
|
||||
{
|
||||
Image image = LoadImage(fileName);
|
||||
if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, FONT_TTF_DEFAULT_FIRST_CHAR);
|
||||
else font = GetFontDefault();
|
||||
UnloadImage(image);
|
||||
}
|
||||
|
||||
if (isGpuReady)
|
||||
if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
|
||||
else
|
||||
{
|
||||
if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
|
||||
else
|
||||
{
|
||||
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
|
||||
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
|
||||
}
|
||||
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
|
||||
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
|
||||
}
|
||||
|
||||
return font;
|
||||
@@ -515,7 +509,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
|
||||
};
|
||||
|
||||
// Set font with all data parsed from image
|
||||
if (isGpuReady) font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
|
||||
font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
|
||||
font.glyphCount = index;
|
||||
font.glyphPadding = 0;
|
||||
|
||||
@@ -584,7 +578,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
|
||||
font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING;
|
||||
|
||||
Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0);
|
||||
if (isGpuReady) font.texture = LoadTextureFromImage(atlas);
|
||||
font.texture = LoadTextureFromImage(atlas);
|
||||
|
||||
// Update glyphs[i].image to use alpha, required to be used on ImageDrawText()
|
||||
for (int i = 0; i < font.glyphCount; i++)
|
||||
@@ -1008,7 +1002,7 @@ void UnloadFont(Font font)
|
||||
if (font.texture.id != GetFontDefault().texture.id)
|
||||
{
|
||||
UnloadFontData(font.glyphs, font.glyphCount);
|
||||
if (isGpuReady) UnloadTexture(font.texture);
|
||||
UnloadTexture(font.texture);
|
||||
RL_FREE(font.recs);
|
||||
|
||||
TRACELOGD("FONT: Unloaded font data from RAM and VRAM");
|
||||
@@ -1339,8 +1333,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
|
||||
{
|
||||
Vector2 textSize = { 0 };
|
||||
|
||||
if ((isGpuReady && (font.texture.id == 0)) ||
|
||||
(text == NULL) || (text[0] == '\0')) return textSize; // Security check
|
||||
if ((font.texture.id == 0) || (text == NULL) || (text[0] == '\0')) return textSize; // Security check
|
||||
|
||||
int size = TextLength(text); // Get size in bytes of text
|
||||
int tempByteCounter = 0; // Used to count longer text line num chars
|
||||
@@ -2481,7 +2474,7 @@ static Font LoadBMFont(const char *fileName)
|
||||
|
||||
RL_FREE(imFonts);
|
||||
|
||||
if (isGpuReady) font.texture = LoadTextureFromImage(fullFont);
|
||||
font.texture = LoadTextureFromImage(fullFont);
|
||||
|
||||
// Fill font characters info data
|
||||
font.baseSize = fontSize;
|
||||
@@ -2523,7 +2516,7 @@ static Font LoadBMFont(const char *fileName)
|
||||
UnloadImage(fullFont);
|
||||
UnloadFileText(fileText);
|
||||
|
||||
if (isGpuReady && (font.texture.id == 0))
|
||||
if (font.texture.id == 0)
|
||||
{
|
||||
UnloadFont(font);
|
||||
font = GetFontDefault();
|
||||
|
||||
Reference in New Issue
Block a user