当窗口最小化时,OpenGL错误1286

时间:2018-10-21 15:00:53

标签: python-3.x glfw pyopengl

有关我正在使用的内容的一些信息:

  • Ancient Potato集成GPU(英特尔(R)HD图形家族)
  • Windows 7
  • OpenGL <= 3.1
  • Python 3.7.0

我只是在最小化窗口的同时立即得到的错误:

$ python main.py
Traceback (most recent call last):
  File "main.py", line 71, in <module>
    main()
  File "main.py", line 60, in main
    renderer.render(mesh)
  File "...\myproject\renderer.py", line 22, in render
    glDrawElements(GL_TRIANGLES, mesh.indices, GL_UNSIGNED_INT, ctypes.c_void_p(0))
  File "...\OpenGL\latebind.py", line 41, in __call__
    return self._finalCall( *args, **named )
  File "...\OpenGL\wrapper.py", line 854, in wrapperCall
    raise err
  File "...\OpenGL\wrapper.py", line 847, in wrapperCall
    result = wrappedOperation( *cArguments )
  File "...\OpenGL\error.py", line 232, in glCheckError
    baseOperation = baseOperation,
OpenGL.error.GLError: GLError(
        err = 1286,
        baseOperation = glDrawElements,
        pyArgs = (
                GL_TRIANGLES,
                6,
                GL_UNSIGNED_INT,
                c_void_p(None),
        ),
        cArgs = (
                GL_TRIANGLES,
                6,
                GL_UNSIGNED_INT,
                c_void_p(None),
        ),
        cArguments = (
                GL_TRIANGLES,
                6,
                GL_UNSIGNED_INT,
                c_void_p(None),
        )
)

当我搜索OpenGL errorcode 1286时,我发现这在OpenGL上下文中发生,当Framebuffer出现问题时。那真的对我没有任何意义...

# renderer.py
class Renderer:
    def __init__(self, colour=(0.0, 0.0, 0.0)):
        self.colour = colour

    @property
    def colour(self):
        return self._colour

    @colour.setter
    def colour(self, new_colour):
        glClearColor(*new_colour, 1.0)
        self._colour = new_colour

    def render(self, mesh):
        glBindVertexArray(mesh.vao_id)
        glBindTexture(GL_TEXTURE_2D, mesh.texture)
        glDrawElements(GL_TRIANGLES, mesh.indices, GL_UNSIGNED_INT, ctypes.c_void_p(0))

    def clear(self):
        glClear(GL_COLOR_BUFFER_BIT)

当我使用帧缓冲区时,我可能做错了什么,但是我可以按照我想要的方式进行所有工作(渲染到纹理,然后将纹理用作在quad上渲染的源,也用作纹理源将在下一帧渲染,基本上使用GPU来处理任意数据的网格),如果代码不清楚,我可以通过交换FBO而不是交换纹理来实现:

# bufferedtexture.py (The place where I use Frame Buffer)
class BufferedTexture:
    def __init__(self, width, height):
        self._width = width
        self._height = height
        self._textures = glGenTextures(2)
        self._buffers = glGenFramebuffers(2)
        self._previous_buffer = 0
        self._current_buffer = 1

        self.init_buffer(0)
        self.init_buffer(1)

    @property
    def width(self):
        return self._width

    @property
    def height(self):
        return self._height

    @property
    def buffer(self):
        return self._buffers[self._current_buffer]

    @property
    def texture(self):
        return self._textures[self._previous_buffer]

    def init_buffer(self, index):
        glBindFramebuffer(GL_FRAMEBUFFER, self._buffers[index])
        glBindTexture(GL_TEXTURE_2D, self._textures[index])
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.width, self.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, ctypes.c_void_p(0))
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self._textures[index], 0)

    def set_texture_data(self, image_data):
        glBindTexture(GL_TEXTURE_2D, self.texture)
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, self.width, self.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data)

    def swap_buffers(self):
        self._previous_buffer = self._current_buffer
        self._current_buffer = (self._current_buffer + 1) % 2

    def enable(self):
        glBindFramebuffer(GL_FRAMEBUFFER, self.buffer)

    def disable(self):
        glBindFramebuffer(GL_FRAMEBUFFER, 0)

    def destroy(self):
        glDeleteFramebuffers(self._buffers)
        glDeleteTextures(self._textures)

我使用这样的一切:

# main loop
while not window.should_close: # glfwWindowShouldClose(self.hwnd)
    shader.enable() # glUseProgram(self._program)

    buff.enable() # BufferedTexture object, source above
    renderer.clear() # Renderer object, source above
    renderer.render(mesh) # By the way, mesh is just a Quad, nothing fancy
    buff.disable() # Tells driver that we will be drawing to screen again

    buff.swap_buffers()
    mesh.texture = buff.texture # give quad the texture that was rendered off-screen
    renderer.clear()
    renderer.render(mesh)

    window.swap_buffers() # glfwSwapBuffers(self.hwnd)
    window.poll_events() # glfwPollEvents()

我什至不知道出什么问题了,再次,这只会在我最小化窗口时发生,否则我可以让它运行几个小时,这很好,但是当我最小化窗口消失时…… >

我什至试图添加

assert(glCheckFramebufferStatus(GL_FRAMEBUFFER)== GL_FRAMEBUFFER_COMPLETE) assert(glGetError()== GL_NO_ERROR)

在BufferedTexture.init_buffer的末尾快速检查FBO本身是否有问题,但是...

$ python main.py
<no assertion errors to be found>
<same error once I minimise>

TL; DR

  1. 一切都能按预期正确呈现;
  2. 在性能方面没有发现任何问题,没有错误 初始化glfw和openGL时抛出或吞下的东西,我 当PyOpenGL完全可以解决某些错误(由于某种原因)而又没有捕获到它时,我自己提出RuntimeError;
  3. 程序在OpenGL中崩溃:1286当我最小化窗口时,失去焦点只会在我最小化窗口时什么都不做...

发送帮助。

编辑:

mesh = Mesh(indices, vertices, uvs)

buff = BufferedTexture(800, 600)

with Image.open("cat.jpg") as image:
    w, h = image.size # the image is 800x600
    img_data = np.asarray(image.convert("RGBA"), np.uint8)
    buff.set_texture_data(img_data[::-1])
    buff.swap_buffers()
    buff.set_texture_data(img_data[::-1])

mesh.texture = buff.texture # this is just GL_TEXTURE_2D object ID
buff.disable()
while not window.should_close:
    shader.enable()

    #buff.enable()
    #renderer.clear()
    #renderer.render(mesh)
    #buff.disable()

    #buff.swap_buffers()
    #mesh.texture = buff.texture
    renderer.clear()
    renderer.render(mesh)

    window.swap_buffers()
    window.poll_events()

一旦我完全停止使用缓冲区,它就会按预期工作。我希望我的代码有问题。

1 个答案:

答案 0 :(得分:0)

有人指出(但是出于某种原因删除了他们的答案/评论),窗口大小变为0时,窗口最小化为0,确实如此,以防止窗口最小化时崩溃和资源浪费,我这样做了:

创建并注册一个用于调整窗口大小的回调函数,这非常容易,因为我仅使用一个窗口,并且已经将其设置为单个窗口,该回调函数仅告诉窗口是否应该休眠。

def callback(window, width, height):
    Window.instance.sleeping = width == 0 or height == 0

(显然)为我自己的窗口注册了回调:

glfwSetFramebufferSizeCallback(self.handle, callback)

当窗口“处于睡眠状态”时,除了轮询事件之外,我什么也没做:

while not window.should_close:
    window.poll_events()
    if window.sleeping:
        time.sleep(0.01)
        continue

    shader.enable()

    buff.enable()
    renderer.clear()
    renderer.render(mesh)
    buff.disable()

    buff.swap_buffers()
    mesh.texture = buff.texture
    renderer.clear()
    renderer.render(mesh)

    window.swap_buffers()