Come risolvere il problema di perdita di memoria di Python OpenGL?
Sto cercando di disegnare alcuni traingles e rendere alcuni testi sullo schermo. Ma ho osservato che la memoria (RAM) aumenta gradualmente solo per 6 draw call. Ho 8 GB di RAM. Quando eseguo il programma l'utilizzo della memoria passa da 4.2 a 6 entro 1 minuto. Ecco il codice completo.
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GL import shaders
from shader import *
import glfw
import freetype
import glm
import numpy as np
from PIL import Image
import math
class CharacterSlot:
def __init__(self, texture, glyph):
self.texture = texture
self.textureSize = (glyph.bitmap.width, glyph.bitmap.rows)
if isinstance(glyph, freetype.GlyphSlot):
self.bearing = (glyph.bitmap_left, glyph.bitmap_top)
self.advance = glyph.advance.x
elif isinstance(glyph, freetype.BitmapGlyph):
self.bearing = (glyph.left, glyph.top)
self.advance = None
else:
raise RuntimeError('unknown glyph type')
def _get_rendering_buffer(xpos, ypos, w, h, zfix=0.0):
return np.asarray([
xpos, ypos + h, 0, 0,
xpos, ypos, 0, 1,
xpos + w, ypos, 1, 1,
xpos, ypos + h, 0, 0,
xpos + w, ypos, 1, 1,
xpos + w, ypos + h, 1, 0
], np.float32)
def init_chars(shaderProgram,window_height,window_width,font_size=24,fontfile = "Vera.ttf"):
glUseProgram(shaderProgram)
#get projection
shader_projection = glGetUniformLocation(shaderProgram, "projection")
W = window_width
H = window_height
projection = glm.ortho(-W/2, W/2, -H/2, H/2)
glUniformMatrix4fv(shader_projection, 1, GL_FALSE, glm.value_ptr(projection))
#disable byte-alignment restriction
glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
face = freetype.Face(fontfile)
face.set_char_size(font_size*64 )
#load first 128 characters of ASCII set
Characters = dict()
for i in range(0,128):
face.load_char(chr(i))
glyph = face.glyph
#generate texture
texture = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D, texture)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, glyph.bitmap.width, glyph.bitmap.rows, 0,
GL_RED, GL_UNSIGNED_BYTE, glyph.bitmap.buffer)
#texture options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
#now store character for later use
Characters[chr(i)] = CharacterSlot(texture,glyph)
glBindTexture(GL_TEXTURE_2D, 0)
glUseProgram(0)
return Characters
def render_text(window,shaderProgram,text,x,y,scale,Characters,color=(170,250,255)):
r,g,b = color
glUseProgram(shaderProgram)
#configure VAO/VBO for texture quads
VAO = glGenVertexArrays(1)
glBindVertexArray(VAO)
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, 6 * 4 * 4, None, GL_STATIC_DRAW)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, None)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
glUniform3f(glGetUniformLocation(shaderProgram, "textColor"),r/255,g/255,b/255)
glActiveTexture(GL_TEXTURE0)
glBindVertexArray(VAO)
for c in text:
ch = Characters[c]
w, h = ch.textureSize
w = w*scale
h = h*scale
vertices = _get_rendering_buffer(x,y,w,h)
#render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.texture)
#update content of VBO memory
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.nbytes, vertices)
glBindBuffer(GL_ARRAY_BUFFER, 0)
#render quad
glDrawArrays(GL_TRIANGLES, 0, 6)
#now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.advance>>6)*scale
glBindTexture(GL_TEXTURE_2D, 0);
glUseProgram(0)
#UNBIND and DELETE VAO/VBO
glBindVertexArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glDeleteBuffers(1, id(VBO))
glDeleteBuffers(1, id(VAO))
def triangle(shaderProgram,window,x=0,y=0):
vertices = [-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.0, 0.5, 0.0]
vertices = np.array(vertices, dtype=np.float32)
VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None)
glEnableVertexAttribArray(0)
#use shader program
glUseProgram(shaderProgram)
#accessing ourColor variable from shaderProgram
vertexColorLoc = glGetUniformLocation(shaderProgram, "ourColor")
glUniform4f(vertexColorLoc, 255, 28/255.0, 20/255.0, 0.7);
#transform matrix
transform = glm.mat4(1)
transform = glm.translate(transform,glm.vec3(x,y,0))
MVP = glGetUniformLocation(shaderProgram, "MVP")
glUniformMatrix4fv(MVP, 1, GL_FALSE, glm.value_ptr(transform))
#drawing trangle
glLineWidth(3)
glDrawArrays(GL_TRIANGLES, 0, 3)
glUseProgram(0)
#UNBIND and DELETE VAO/VBO
glBindVertexArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glDeleteBuffers(1, id(VBO))
def main():
glfw.init()
window = glfw.create_window(640, 640,"EXAMPLE PROGRAM",None,None)
glfw.make_context_current(window)
#initliaze shader programs
shaderProgram = get_shaderProgram()
text_shaderProgram = get_text_shaderProgram()
#load characters and VAO/VBO for text rendering
Characters = init_chars(text_shaderProgram,640,640)
#window loop
while not glfw.window_should_close(window):
glfw.poll_events()
#screen
glClearColor(0, 0, 0, 1)
glClear(GL_COLOR_BUFFER_BIT)
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
#draw functions
render_text(window,text_shaderProgram,"TRIANGLE",-50,-200,1,Characters)
render_text(window,text_shaderProgram,"A",0,180,1,Characters)
render_text(window,text_shaderProgram,"B",-160,-180,1,Characters)
render_text(window,text_shaderProgram,"C",150,-180,1,Characters)
triangle(shaderProgram,window)
triangle(shaderProgram,window,x=0.5,y=0.5)
#swap buffers
glfw.swap_buffers(window)
glfw.swap_interval(1)
glfw.terminate()
if __name__ == '__main__':
main()
Il programma shader è qui . Ma penso che il problema sia nell'oggetto buffer. Ho provato a svincolare VAO / VBO ed eliminare i buffer seguendo il codice. Ma non vedo alcun cambiamento.
#UNBIND and DELETE VAO/VBO
glBindVertexArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glDeleteBuffers(1, id(VBO))
glDeleteBuffers(1, id(VAO))
Ecco il problema correlato in cui la risposta accettata ha suggerito che glGenBuffers causa la perdita di memoria. La funzione alternativa glCreateBuffers non è disponibile in pyopengl. Come posso risolvere questo problema?
Risposte
Non vedo alcuna buona ragione per ricreare l'oggetto Array Vertex e l'oggetto Array Buffer ogni volta che vengono chiamati render_textrispettivamente triangle. La specifica del vertice e il numero di vertici non cambia, quindi sarebbe sufficiente aggiornare il contenuto del buffer.
Creare l'oggetto array Vertex e l'oggetto buffer array una volta durante l'inizializzazione:
def init_buffers():
global text_VAO, text_VBO, triangle_VAO, triangle_VBO
text_VAO = glGenVertexArrays(1)
glBindVertexArray(text_VAO)
text_VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, text_VBO)
glBufferData(GL_ARRAY_BUFFER, 6 * 4 * 4, None, GL_STATIC_DRAW)
glEnableVertexAttribArray(0)
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, None)
vertices = [-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.0, 0.5, 0.0]
vertices = np.array(vertices, dtype=np.float32)
triangle_VAO = glGenVertexArrays(1)
glBindVertexArray(triangle_VAO)
triangle_VBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, triangle_VBO)
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None)
glEnableVertexAttribArray(0)
Usa quindi nelle funzioni render_texte triangle:
def render_text(window,shaderProgram,text,x,y,scale,Characters,color=(170,250,255)):
# [...]
glBindVertexArray(text_VAO)
for c in text:
# [...]
glBindBuffer(GL_ARRAY_BUFFER, text_VBO)
glBufferSubData(GL_ARRAY_BUFFER, 0, vertices.nbytes, vertices)
# glDeleteBuffers(1, id(VBO)) <--- DELETE
# glDeleteBuffers(1, id(VAO)) <--- DELETE
def triangle(shaderProgram,window,x=0,y=0):
glBindVertexArray(triangle_VAO)
# [...]
# glDeleteBuffers(1, id(VBO)) <--- DELETE
Invoca init_buffersprima del ciclo dell'applicazione:
def main():
# [...]
init_buffers()
while not glfw.window_should_close(window):
# [...]