代码之家  ›  专栏  ›  技术社区  ›  Purple Ice

窗口最小化时出现OpenGL错误1286

  •  0
  • Purple Ice  · 技术社区  · 6 年前

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

    • 古土豆集成GPU(Intel(R)高清图形家族)
    • 视窗7
    • OpenGL & lt;=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)
    

    当我使用帧缓冲区时,我可能做了一些错误的事情,但我得到了我想要的一切工作方式(渲染到纹理,然后使用纹理作为源在四边形上渲染,也作为将在下一帧渲染的纹理的源,基本上使用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()
    

    我甚至不知道会出什么问题,再说一遍,只有当我把窗户减到最小的时候才会发生这种情况,否则我可以让它运行几个小时,这很好,但当我把窗户减到最小的时候,它就死了……

    我甚至试图补充

    断言(glcheckframebufferstatus(gl_framebuffer)==gl_framebuffer_complete) 断言(glgetError()==gl_no_error)

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

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

    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 回复  |  直到 6 年前
        1
  •  0
  •   Purple Ice    6 年前

    有人指出(但出于任何原因删除了他们的答案/评论),窗口大小在最小化时变为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()