PDA

View Full Version : Memory leak during shadow mapping pass is driving me insane!



Yasha-
05-25-2017, 02:46 AM
Hello everyone and thanks for opening this thread, because I could definitely use some help.

I've been working on an OpenGL project that involves two elements - a large terrain mesh generated with noise and a large cube that revolves around it. All that has already been implemented, and the last step was to implement shadow mapping to allow the revolving cube to cast a shadow over the terrain, as the light source is positioned above it.

Using guides from multiple sources (mainly opengl-tutorial.org and the OpenGL cookbook) I managed to actually get the shadow map into my render function, and upon running the program it is in fact working correctly...however within seconds my system (not video) memory loads to the max and the program crashes. I'm using OpenGL 4.3 on Visual Studio 2015.

Here is a quick run down of my render function. There are two sets of shaders, one for each pass, first one generates the depth texture and the other renders the scene using the depth texture as an input into the fragment shader. Assume any undeclared stuff to be declared elsewhere or provided as an argument (none of it was added while doing shadow maps anyway).




{
.
.
(Poll events, call a function that moves the camera)
.
.
.
glUseProgram(program2); // Vertex and Fragment shaders for the first pass


GLuint depthTexture;
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 1600, 900, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);


GLuint shadowBuffer = 0;
glGenFramebuffers(1, &shadowBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, shadowBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);


GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER); //framebuffer test
if (Status != GL_FRAMEBUFFER_COMPLETE) {
printf("FB error, status: 0x%x\n", Status);
return false;
}


glClear(GL_DEPTH_BUFFER_BIT);

glm::mat4 depthProjectionMatrix = glm::ortho<float>(-1000, 1000, -1000, 1000, -1000, 2000);
glm::mat4 depthViewMatrix = glm::lookAt(lightPos, glm::vec3(0, 0, 0), glm::vec3(0, 1, 0));
glm::mat4 depthModelMatrix = glm::mat4(1.0);
glm::mat4 depthMVP = depthProjectionMatrix * depthViewMatrix * depthModelMatrix;


GLint depthMatrixLoc = glGetUniformLocation(program2, "depthMVP");
glUniformMatrix4fv(depthMatrixLoc, 1, GL_FALSE, &depthMVP[0][0]);



glEnableVertexAttribArray(0); //Vertex array for the revolving cube already bound between pollevents and useprogram at the start
glDrawArrays(GL_TRIANGLES, 0, model2.getVertexCount());
glDisableVertexAttribArray(0);
glBindVertexArray(0);

glBindVertexArray(model.getVaoID());//Vertex array for the terrain, both were supplied to the function
glEnableVertexAttribArray(0);
glDrawElements(GL_TRIANGLES, model.getVertexCount(), GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glBindVertexArray(0);

glBindFramebuffer(GL_FRAMEBUFFER, 0);

//End of first pass. Begin second pass that renders the scene normally.


glClearColor(0.527, 0.805, 0.977, 1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glUseProgram(program);

GLuint textureOUT = textureIN;


GLint lightColorLoc = glGetUniformLocation(program, "lightColor");
GLint lightPosLoc = glGetUniformLocation(program, "lightPos");
GLint viewPosLoc = glGetUniformLocation(program, "viewPos");

glUniform3f(lightColorLoc, 1.0f, 1.0f, 0.8f);
glUniform3f(lightPosLoc, lightPos.x, lightPos.y, lightPos.z);
glUniform3f(viewPosLoc, camera.GetPosition().x, camera.GetPosition().y, camera.GetPosition().z);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureOUT);
glUniform1i(glGetUniformLocation(program, "ourTexture"), 0);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glUniform1i(glGetUniformLocation(program, "shadowMap"), 1);

projection = glm::perspective(camera.GetZoom(), (GLfloat)scwidth / (GLfloat)scheight, 0.1f, 20000.0f);

glm::mat4 modelmat;
glm::mat4 viewmat;

viewmat = camera.GetViewMatrix();
viewmat = glm::translate(viewmat, glm::vec3(0.0f, -1.0f, 0.0f));

glm::mat4 biasMatrix(
0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0
);
glm::mat4 depthBiasMVP = biasMatrix*depthMVP;

GLint modelLoc = glGetUniformLocation(program, "model");
GLint viewLoc = glGetUniformLocation(program, "view");
GLint projLoc = glGetUniformLocation(program, "projection");
GLint depthBiasMVPLoc = glGetUniformLocation(program, "depthBiasMVP");

glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelmat));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewmat));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
glUniformMatrix4fv(depthBiasMVPLoc, 1, GL_FALSE, &depthBiasMVP[0][0]);

glBindVertexArray(model.getVaoID());
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glDrawElements(GL_TRIANGLES, model.getVertexCount(), GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindVertexArray(0);


textureOUT = textureIN2;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureOUT);
glUniform1i(glGetUniformLocation(program, "ourTexture2"), 0);

glBindVertexArray(model2.getVaoID());

glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLES, 0, model2.getVertexCount());
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindVertexArray(0);

glDeleteBuffers(1, &SatVert);
}


Does anything seem out of place? Something that would cause a leak? Note that all VAO/VBOs are deleted using other utility functions in my main loop, besides the fact that they weren't causing issues before adding the shadows feature.


Thanks.

Dark Photon
05-25-2017, 06:06 AM
Does anything seem out of place? Something that would cause a leak?

Anytime this happens, look for anything you are creating every frame (or at least frequently). Nothing should be created or deleted steady state.

In your case, it search for glGen*. You'll find several candidates. Note that the glGen* apis only allocate the handles, not the storage behind the handles, but often these are followed by the calls that allocate the storage, as in your case.

Nokturnis
05-25-2017, 06:08 AM
So... are you creating a depth texture and fbo EVERY frame and not deleting them?
That could be a problem.

edit Dark Photon was faster.

mhagain
05-25-2017, 07:13 AM
Also note that glDelete* calls are only specified to make object names available for reuse; the GL implementation itself may handle actual deletion of the underlying objects at some arbitrary later point in time.

Yasha-
05-25-2017, 10:10 AM
Wow...rookie mistake. I kept it in the render function because that's how I interpreted the tutorial(s). Moved the framebuffer setup outside and it's fixed! Thanks!


I have another question though...in my scene's fragment shader, I am using "float visibility = textureProj(shadowMap, ShadowCoord);" and then " vec3 diffuse = diff * lightColor * visibility;", "vec3 specular = specularStrength * spec * lightColor * visibility;" (the shader is quite simple ADS with shadow map taken into account). This yields in a shadow...but a very weak one. I rendered the scene using the "visibility" as color output and the shadow area doesn't have visibility as 0, it's some gray tone.


Trying to use the comparison "if ( texture( shadowMap, ShadowCoord.xy ).z < ShadowCoord.z)" yields an overload error while compiling the shader (errors #202 and 216). My shadowMap is taken as a sampler2DShadow.

GClements
05-25-2017, 05:42 PM
Trying to use the comparison "if ( texture( shadowMap, ShadowCoord.xy ).z < ShadowCoord.z)" yields an overload error while compiling the shader (errors #202 and 216). My shadowMap is taken as a sampler2DShadow.
Shadow samplers perform the comparison as part of the lookup. For a 2D shadow sampler, you have to pass 3D coordinates; the X and Y coordinates are used to perform a lookup, the result of which is then compared against the Z component.

The implementation may perform the comparison for multiple texels and return a value between 0 and 1 depending upon how many texels pass and by what margin, to give shadows a softer edge.

Also, the texture identified by a shadow sampler uniform must be a depth-format texture with GL_TEXTURE_COMPARE_MODE set to GL_COMPARE_REF_TO_TEXTURE. Similarly, a non-shadow sampler uniform must not refer to such a texture.