Skip to content

Commit 2853b28

Browse files
committed
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
1 parent 8fa5f1f commit 2853b28

File tree

5 files changed

+53
-44
lines changed

5 files changed

+53
-44
lines changed

src/platforms/rcore_android.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ typedef struct {
8484
// Global Variables Definition
8585
//----------------------------------------------------------------------------------
8686
extern CoreData CORE; // Global CORE state context
87-
extern bool isGpuReady; // Flag to note GPU has been initialized successfully
8887
static PlatformData platform = { 0 }; // Platform specific data
8988

9089
//----------------------------------------------------------------------------------
@@ -1042,7 +1041,6 @@ static void AndroidCommandCallback(struct android_app *app, int32_t cmd)
10421041
// Initialize OpenGL context (states and resources)
10431042
// NOTE: CORE.Window.currentFbo.width and CORE.Window.currentFbo.height not used, just stored as globals in rlgl
10441043
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
1045-
isGpuReady = true;
10461044

10471045
// Setup default viewport
10481046
// NOTE: It updated CORE.Window.render.width and CORE.Window.render.height

src/rcore.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -387,11 +387,6 @@ RLAPI const char *raylib_version = RAYLIB_VERSION; // raylib version exported s
387387

388388
CoreData CORE = { 0 }; // Global CORE state context
389389

390-
// Flag to note GPU acceleration is available,
391-
// referenced from other modules to support GPU data loading
392-
// NOTE: Useful to allow Texture, RenderTexture, Font.texture, Mesh.vaoId/vboId, Shader loading
393-
bool isGpuReady = false;
394-
395390
#if defined(SUPPORT_SCREEN_CAPTURE)
396391
static int screenshotCounter = 0; // Screenshots counter
397392
#endif
@@ -697,7 +692,6 @@ void InitWindow(int width, int height, const char *title)
697692
// Initialize rlgl default data (buffers and shaders)
698693
// NOTE: Current fbo size stored as globals in rlgl for convenience
699694
rlglInit(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
700-
isGpuReady = true; // Flag to note GPU has been initialized successfully
701695

702696
// Setup default viewport
703697
SetupViewport(CORE.Window.currentFbo.width, CORE.Window.currentFbo.height);
@@ -1266,7 +1260,14 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
12661260

12671261
shader.id = rlLoadShaderCode(vsCode, fsCode);
12681262

1269-
if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault();
1263+
if (shader.id == 0)
1264+
{
1265+
// Shader could not be loaded but we still load the location points to avoid potential crashes
1266+
// NOTE: All locations set to -1 (no location)
1267+
shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
1268+
for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
1269+
}
1270+
else if (shader.id == rlGetShaderIdDefault()) shader.locs = rlGetShaderLocsDefault();
12701271
else if (shader.id > 0)
12711272
{
12721273
// After custom shader loading, we TRY to set default location names
@@ -1282,9 +1283,9 @@ Shader LoadShaderFromMemory(const char *vsCode, const char *fsCode)
12821283

12831284
// NOTE: If any location is not found, loc point becomes -1
12841285

1286+
// Load shader locations array
1287+
// NOTE: All locations set to -1 (no location)
12851288
shader.locs = (int *)RL_CALLOC(RL_MAX_SHADER_LOCATIONS, sizeof(int));
1286-
1287-
// All locations reset to -1 (no location)
12881289
for (int i = 0; i < RL_MAX_SHADER_LOCATIONS; i++) shader.locs[i] = -1;
12891290

12901291
// Get handles to GLSL input attribute locations

src/rlgl.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,7 @@ static double rlCullDistanceFar = RL_CULL_DISTANCE_FAR;
11531153
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
11541154
static rlglData RLGL = { 0 };
11551155
#endif // GRAPHICS_API_OPENGL_33 || GRAPHICS_API_OPENGL_ES2
1156+
static bool isGpuReady = false;
11561157

11571158
#if defined(GRAPHICS_API_OPENGL_ES2) && !defined(GRAPHICS_API_OPENGL_ES3)
11581159
// NOTE: VAO functionality is exposed through extensions (OES)
@@ -2283,6 +2284,8 @@ static void GLAPIENTRY rlDebugMessageCallback(GLenum source, GLenum type, GLuint
22832284
// Initialize rlgl: OpenGL extensions, default buffers/shaders/textures, OpenGL states
22842285
void rlglInit(int width, int height)
22852286
{
2287+
isGpuReady = true;
2288+
22862289
// Enable OpenGL debug context if required
22872290
#if defined(RLGL_ENABLE_OPENGL_DEBUG_CONTEXT) && defined(GRAPHICS_API_OPENGL_43)
22882291
if ((glDebugMessageCallback != NULL) && (glDebugMessageControl != NULL))
@@ -2395,6 +2398,7 @@ void rlglClose(void)
23952398
#if defined(GRAPHICS_API_OPENGL_11_SOFTWARE)
23962399
swClose(); // Unload sofware renderer resources
23972400
#endif
2401+
isGpuReady = false;
23982402
}
23992403

24002404
// Load OpenGL extensions
@@ -2799,6 +2803,7 @@ int *rlGetShaderLocsDefault(void)
27992803
rlRenderBatch rlLoadRenderBatch(int numBuffers, int bufferElements)
28002804
{
28012805
rlRenderBatch batch = { 0 };
2806+
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return batch; }
28022807

28032808
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
28042809
// Initialize CPU (RAM) vertex buffers (position, texcoord, color data and indexes)
@@ -3253,6 +3258,7 @@ bool rlCheckRenderBatchLimit(int vCount)
32533258
unsigned int rlLoadTexture(const void *data, int width, int height, int format, int mipmapCount)
32543259
{
32553260
unsigned int id = 0;
3261+
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
32563262

32573263
glBindTexture(GL_TEXTURE_2D, 0); // Free any old binding
32583264

@@ -3411,6 +3417,7 @@ unsigned int rlLoadTexture(const void *data, int width, int height, int format,
34113417
unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer)
34123418
{
34133419
unsigned int id = 0;
3420+
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
34143421

34153422
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
34163423
// In case depth textures not supported, we force renderbuffer usage
@@ -3469,6 +3476,7 @@ unsigned int rlLoadTextureDepth(int width, int height, bool useRenderBuffer)
34693476
unsigned int rlLoadTextureCubemap(const void *data, int size, int format, int mipmapCount)
34703477
{
34713478
unsigned int id = 0;
3479+
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
34723480

34733481
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
34743482
int mipSize = size;
@@ -3813,6 +3821,7 @@ unsigned char *rlReadScreenPixels(int width, int height)
38133821
unsigned int rlLoadFramebuffer(void)
38143822
{
38153823
unsigned int fboId = 0;
3824+
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return fboId; }
38163825

38173826
#if (defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)) && defined(RLGL_RENDER_TEXTURES_HINT)
38183827
glGenFramebuffers(1, &fboId); // Create the framebuffer object
@@ -3928,6 +3937,7 @@ void rlUnloadFramebuffer(unsigned int id)
39283937
unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic)
39293938
{
39303939
unsigned int id = 0;
3940+
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
39313941

39323942
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
39333943
glGenBuffers(1, &id);
@@ -3942,6 +3952,7 @@ unsigned int rlLoadVertexBuffer(const void *buffer, int size, bool dynamic)
39423952
unsigned int rlLoadVertexBufferElement(const void *buffer, int size, bool dynamic)
39433953
{
39443954
unsigned int id = 0;
3955+
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
39453956

39463957
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
39473958
glGenBuffers(1, &id);
@@ -4107,12 +4118,12 @@ void rlDisableStatePointer(int vertexAttribType)
41074118
unsigned int rlLoadVertexArray(void)
41084119
{
41094120
unsigned int vaoId = 0;
4121+
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return vaoId; }
4122+
41104123
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
4111-
if (RLGL.ExtSupported.vao)
4112-
{
4113-
glGenVertexArrays(1, &vaoId);
4114-
}
4124+
if (RLGL.ExtSupported.vao) glGenVertexArrays(1, &vaoId);
41154125
#endif
4126+
41164127
return vaoId;
41174128
}
41184129

@@ -4167,6 +4178,7 @@ void rlUnloadVertexBuffer(unsigned int vboId)
41674178
unsigned int rlLoadShaderCode(const char *vsCode, const char *fsCode)
41684179
{
41694180
unsigned int id = 0;
4181+
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return id; }
41704182

41714183
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
41724184
unsigned int vertexShaderId = 0;
@@ -4309,6 +4321,7 @@ unsigned int rlCompileShader(const char *shaderCode, int type)
43094321
unsigned int rlLoadShaderProgram(unsigned int vShaderId, unsigned int fShaderId)
43104322
{
43114323
unsigned int programId = 0;
4324+
if (!isGpuReady) { TRACELOG(RL_LOG_WARNING, "GL: GPU is not ready to load data, trying to load before InitWindow()?"); return programId; }
43124325

43134326
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
43144327
GLint success = 0;

src/rmodels.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,8 @@ void UploadMesh(Mesh *mesh, bool dynamic)
12821282

12831283
#if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
12841284
mesh->vaoId = rlLoadVertexArray();
1285+
if (mesh->vaoId == 0) return;
1286+
12851287
rlEnableVertexArray(mesh->vaoId);
12861288

12871289
// 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)
14701472
// Bind shader program
14711473
rlEnableShader(material.shader.id);
14721474

1475+
if (material.shader.locs == NULL) return;
1476+
14731477
// Send required data to shader (matrices, values)
14741478
//-----------------------------------------------------
14751479
// Upload to shader material.colDiffuse

src/rtext.c

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,12 @@
127127
//----------------------------------------------------------------------------------
128128
// Global variables
129129
//----------------------------------------------------------------------------------
130-
extern bool isGpuReady;
131130
#if defined(SUPPORT_DEFAULT_FONT)
132131
// Default font provided by raylib
133132
// NOTE: Default font is loaded on InitWindow() and disposed on CloseWindow() [module: core]
134133
static Font defaultFont = { 0 };
135134
#endif
136-
static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines)
135+
static int textLineSpacing = 2; // Text vertical line spacing in pixels (between lines)
137136

138137
//----------------------------------------------------------------------------------
139138
// Other Modules Functions Declaration (required by text)
@@ -164,8 +163,8 @@ extern void LoadFontDefault(void)
164163
{
165164
#define BIT_CHECK(a,b) ((a) & (1u << (b)))
166165

167-
// Check to see if we have allready allocated the font for an image, and if we don't need to upload, then just return
168-
if ((defaultFont.glyphs != NULL) && !isGpuReady) return;
166+
// Check to see if we have already allocated the font for an image, and if we don't need to upload, then just return
167+
if (defaultFont.glyphs != NULL) return;
169168

170169
// NOTE: Using UTF-8 encoding table for Unicode U+0000..U+00FF Basic Latin + Latin-1 Supplement
171170
// Ref: http://www.utf8-chartable.de/unicode-utf8-table.pl
@@ -263,17 +262,14 @@ extern void LoadFontDefault(void)
263262
counter++;
264263
}
265264

266-
if (isGpuReady)
267-
{
268-
defaultFont.texture = LoadTextureFromImage(imFont);
265+
defaultFont.texture = LoadTextureFromImage(imFont);
269266

270-
// we have already loaded the font glyph data an image, and the GPU is ready, we are done
271-
// if we don't do this, we will leak memory by reallocating the glyphs and rects
272-
if (defaultFont.glyphs != NULL)
273-
{
274-
UnloadImage(imFont);
275-
return;
276-
}
267+
// we have already loaded the font glyph data an image, and the GPU is ready, we are done
268+
// if we don't do this, we will leak memory by reallocating the glyphs and rects
269+
if (defaultFont.glyphs != NULL)
270+
{
271+
UnloadImage(imFont);
272+
return;
277273
}
278274

279275
// Reconstruct charSet using charsWidth[], charsHeight, charsDivisor, glyphCount
@@ -330,7 +326,7 @@ extern void LoadFontDefault(void)
330326
extern void UnloadFontDefault(void)
331327
{
332328
for (int i = 0; i < defaultFont.glyphCount; i++) UnloadImage(defaultFont.glyphs[i].image);
333-
if (isGpuReady) UnloadTexture(defaultFont.texture);
329+
UnloadTexture(defaultFont.texture);
334330
RL_FREE(defaultFont.glyphs);
335331
RL_FREE(defaultFont.recs);
336332
defaultFont.glyphCount = 0;
@@ -384,17 +380,15 @@ Font LoadFont(const char *fileName)
384380
{
385381
Image image = LoadImage(fileName);
386382
if (image.data != NULL) font = LoadFontFromImage(image, MAGENTA, FONT_TTF_DEFAULT_FIRST_CHAR);
383+
else font = GetFontDefault();
387384
UnloadImage(image);
388385
}
389386

390-
if (isGpuReady)
387+
if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
388+
else
391389
{
392-
if (font.texture.id == 0) TRACELOG(LOG_WARNING, "FONT: [%s] Failed to load font texture -> Using default font", fileName);
393-
else
394-
{
395-
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
396-
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
397-
}
390+
SetTextureFilter(font.texture, TEXTURE_FILTER_POINT); // By default, we set point filter (the best performance)
391+
TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount);
398392
}
399393

400394
return font;
@@ -515,7 +509,7 @@ Font LoadFontFromImage(Image image, Color key, int firstChar)
515509
};
516510

517511
// Set font with all data parsed from image
518-
if (isGpuReady) font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
512+
font.texture = LoadTextureFromImage(fontClear); // Convert processed image to OpenGL texture
519513
font.glyphCount = index;
520514
font.glyphPadding = 0;
521515

@@ -584,7 +578,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int
584578
font.glyphPadding = FONT_TTF_DEFAULT_CHARS_PADDING;
585579

586580
Image atlas = GenImageFontAtlas(font.glyphs, &font.recs, font.glyphCount, font.baseSize, font.glyphPadding, 0);
587-
if (isGpuReady) font.texture = LoadTextureFromImage(atlas);
581+
font.texture = LoadTextureFromImage(atlas);
588582

589583
// Update glyphs[i].image to use alpha, required to be used on ImageDrawText()
590584
for (int i = 0; i < font.glyphCount; i++)
@@ -1008,7 +1002,7 @@ void UnloadFont(Font font)
10081002
if (font.texture.id != GetFontDefault().texture.id)
10091003
{
10101004
UnloadFontData(font.glyphs, font.glyphCount);
1011-
if (isGpuReady) UnloadTexture(font.texture);
1005+
UnloadTexture(font.texture);
10121006
RL_FREE(font.recs);
10131007

10141008
TRACELOGD("FONT: Unloaded font data from RAM and VRAM");
@@ -1339,8 +1333,7 @@ Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing
13391333
{
13401334
Vector2 textSize = { 0 };
13411335

1342-
if ((isGpuReady && (font.texture.id == 0)) ||
1343-
(text == NULL) || (text[0] == '\0')) return textSize; // Security check
1336+
if ((font.texture.id == 0) || (text == NULL) || (text[0] == '\0')) return textSize; // Security check
13441337

13451338
int size = TextLength(text); // Get size in bytes of text
13461339
int tempByteCounter = 0; // Used to count longer text line num chars
@@ -2481,7 +2474,7 @@ static Font LoadBMFont(const char *fileName)
24812474

24822475
RL_FREE(imFonts);
24832476

2484-
if (isGpuReady) font.texture = LoadTextureFromImage(fullFont);
2477+
font.texture = LoadTextureFromImage(fullFont);
24852478

24862479
// Fill font characters info data
24872480
font.baseSize = fontSize;
@@ -2523,7 +2516,7 @@ static Font LoadBMFont(const char *fileName)
25232516
UnloadImage(fullFont);
25242517
UnloadFileText(fileText);
25252518

2526-
if (isGpuReady && (font.texture.id == 0))
2519+
if (font.texture.id == 0)
25272520
{
25282521
UnloadFont(font);
25292522
font = GetFontDefault();

0 commit comments

Comments
 (0)