Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Free leaked allocations from render objects when using rlgl with OpenGL 3.3 #1302

Merged
merged 1 commit into from
Jul 9, 2020

Conversation

terrehbyte
Copy link
Sponsor Contributor

Related issues

This may be related to #1301, but this PR addresses problems found in 3.1, unlike the issue, which appears to be centered around 3.0.

Summary

Two leaks come from any RenderBatch objects and default Shader resources that are created.

Default RenderBatch

The allocations occur here:

raylib/src/rlgl.h

Lines 4088 to 4094 in 00fda3b

batch.vertexBuffer[i].vertices = (float *)RL_MALLOC(bufferElements*3*4*sizeof(float)); // 3 float by vertex, 4 vertex by quad
batch.vertexBuffer[i].texcoords = (float *)RL_MALLOC(bufferElements*2*4*sizeof(float)); // 2 float by texcoord, 4 texcoord by quad
batch.vertexBuffer[i].colors = (unsigned char *)RL_MALLOC(bufferElements*4*4*sizeof(unsigned char)); // 4 float by color, 4 colors by quad
#if defined(GRAPHICS_API_OPENGL_33)
batch.vertexBuffer[i].indices = (unsigned int *)RL_MALLOC(bufferElements*6*sizeof(unsigned int)); // 6 int by quad (indices)
#elif defined(GRAPHICS_API_OPENGL_ES2)
batch.vertexBuffer[i].indices = (unsigned short *)RL_MALLOC(bufferElements*6*sizeof(unsigned short)); // 6 int by quad (indices)

The default RenderBatch created by rlglInit() (and seemingly any other RenderBatch) does not record the number of buffers that it has created, which prevents its buffers (and the memory allocated for them) from getting cleaned up when it's passed to UnloadRenderBatch.

This is resolved by adding the assignment to the buffersCount which is evaluated by the UnloadRenderBatch function during clean-up.

Default Shader

The allocation occurs here on rlgl.h(3937).

raylib/src/rlgl.h

Lines 3934 to 3938 in 00fda3b

static Shader LoadShaderDefault(void)
{
Shader shader = { 0 };
shader.locs = (int *)RL_CALLOC(MAX_SHADER_LOCATIONS, sizeof(int));

The locs is cleaned up for normal shaders...

raylib/src/rlgl.h

Lines 3100 to 3110 in 00fda3b

// Unload shader from GPU memory (VRAM)
void UnloadShader(Shader shader)
{
if (shader.id > 0)
{
rlDeleteShader(shader.id);
TRACELOG(LOG_INFO, "SHADER: [ID %i] Unloaded shader program data from VRAM (GPU)", shader.id);
}
RL_FREE(shader.locs);
}

...but since the default shader goes through a special path, this gets missed.

raylib/src/rlgl.h

Lines 4062 to 4073 in 00fda3b

// Unload default shader
static void UnloadShaderDefault(void)
{
glUseProgram(0);
glDetachShader(RLGL.State.defaultShader.id, RLGL.State.defaultVShaderId);
glDetachShader(RLGL.State.defaultShader.id, RLGL.State.defaultFShaderId);
glDeleteShader(RLGL.State.defaultVShaderId);
glDeleteShader(RLGL.State.defaultFShaderId);
glDeleteProgram(RLGL.State.defaultShader.id);
}

Adding an RL_FREE to handle the allocation stored in locs from the default shader for its clean-up routine appears to handle things.

Quick note: I'm not a regular contributor to Raylib, so any guidance on whether the clean-up logic for the default shader should be consolidated into the normal free function for shaders would be appreciated.

Other Leaks - GLFW?

Visual Studio reports that two additional leaks remain, but appears to be attributed to GLFW: one leak stemming from the creation of the window on Windows while the other is from creating some buffer for retrieving joysticks.

Raylib's logic for initializing and de-initializing GLFW seems fine on the surface, so I thought it'd be out of scope.

System Environment

Here's a print-out of my environment, which reflects that I'm working with OpenGL 3.3.

INFO: Initializing raylib 3.1-dev
INFO: DISPLAY: Device initialized successfully
INFO:     > Display size: 1920 x 1080
INFO:     > Render size:  800 x 450
INFO:     > Screen size:  800 x 450
INFO:     > Viewport offsets: 0, 0
INFO: GLAD: OpenGL extensions loaded successfully
INFO: GL: OpenGL 3.3 Core profile supported
INFO: GL: OpenGL device information:
INFO:     > Vendor:   NVIDIA Corporation
INFO:     > Renderer: GeForce RTX 2080/PCIe/SSE2
INFO:     > Version:  3.3.0 NVIDIA 446.14
INFO:     > GLSL:     3.30 NVIDIA via Cg compiler
INFO: GL: Supported extensions count: 397
INFO: GL: DXT compressed textures supported
INFO: GL: ETC2/EAC compressed textures supported
INFO: GL: Anisotropic textures filtering supported (max: 16X)
INFO: GL: Mirror clamp wrap texture mode supported
INFO: TEXTURE: [ID 1] Texture created successfully (1x1 - 1 mipmaps)
INFO: TEXTURE: [ID 1] Default texture loaded successfully
INFO: SHADER: [ID 1] Compiled successfully
INFO: SHADER: [ID 2] Compiled successfully
INFO: SHADER: [ID 3] Program loaded successfully
INFO: SHADER: [ID 3] Default shader loaded successfully
INFO: RLGL: Internal vertex buffers initialized successfully in RAM (CPU)
INFO: RLGL: Render batch vertex buffers loaded successfully
INFO: RLGL: Default state initialized successfully
INFO: TEXTURE: [ID 2] Texture created successfully (128x128 - 1 mipmaps)
INFO: FONT: Default font loaded successfully

Test Code

Since the issue seemed localized to OpenGL, it seemed reasonable to simply start and stop
an OpenGL context in order to reproduce the problem. To that endeavor, only InitWindow
and CloseWindow are called.

#include "raylib.h"

int main(void)
{
    // Initialization
    //--------------------------------------------------------------------------------------
    const int screenWidth = 800;
    const int screenHeight = 450;

    InitWindow(screenWidth, screenHeight, "raylib");

    // De-Initialization
    //--------------------------------------------------------------------------------------
    CloseWindow();        // Close window and OpenGL context
    //--------------------------------------------------------------------------------------

	// All memory allocated by raylib should be deallocated by this point in execution
    return 0;
}

The leak was identified using the CRT Debug Library available in MSVC as well as the Visual Studio 2019 Memory Usage profiler.

@raysan5 raysan5 merged commit 871cd1a into raysan5:master Jul 9, 2020
@raysan5
Copy link
Owner

raysan5 commented Jul 9, 2020

@terrehbyte Thank you very much for the review! :D

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants