panda3d / panda3d

Powerful, mature open-source cross-platform game engine for Python and C++, developed by Disney and CMU
https://www.panda3d.org/
Other
4.53k stars 785 forks source link

Opengl reports errors with certain depth buffer/stencil specifications. #1142

Closed Clockwork-Muse closed 3 years ago

Clockwork-Muse commented 3 years ago

Description

Some of this may be misunderstanding what, exactly, needs to be specified when creating offscreen buffers.

Case 1

from direct.showbase.ShowBase import ShowBase
from panda3d.core import FrameBufferProperties, GraphicsOutput, GraphicsPipe, Texture, WindowProperties, loadPrcFileData

class MyApp(ShowBase):
    def __init__(self):
        super().__init__(self)

        props = FrameBufferProperties()
        props.set_rgba_bits(8, 8, 8, 0)

        wp = WindowProperties()
        wp.setSize(1024, 1024)

        flags = GraphicsPipe.BFRefuseWindow

        buffer = self.graphicsEngine.make_output(
            self.pipe, "some buffer", -2, props, wp, flags, self.win.get_gsg(), self.win)
        self.texture = Texture()
        buffer.add_render_texture(
            tex=self.texture, mode=GraphicsOutput.RTMCopyRam, bitplane=GraphicsOutput.RTPColor)
        self.depth_texture = Texture()
        buffer.add_render_texture(
            tex=self.depth_texture, mode=GraphicsOutput.RTMCopyRam, bitplane=GraphicsOutput.RTPDepthStencil)

def generate_synth():
    loadPrcFileData("",
    """
        gl-debug #t
        window-type offscreen
        aux-display p3headlessgl
    """)

    base = MyApp()
    base.run()

generate_synth()

This ends up generating lines filled with :display:gsg:glgsg(error): GL_INVALID_OPERATION error generated. Drawable does not have depth buffer..

The errors can be fixed by:

OR

Adding both yields a single line with :display:gsg:glgsg(warning): Framebuffer unsupported. Framebuffer object some buffer is unsupported because the depth and stencil attachments are mismatched.

Case 2

from direct.showbase.ShowBase import ShowBase
from panda3d.core import FrameBufferProperties, GraphicsOutput, GraphicsPipe, Texture, WindowProperties, loadPrcFileData

class MyApp(ShowBase):
    def __init__(self):
        super().__init__(self)

        props = FrameBufferProperties()
        props.set_rgba_bits(8, 8, 8, 0)
        props.set_depth_bits(24)
        props.set_stencil_bits(8)
        props.set_float_depth(True)

        wp = WindowProperties()
        wp.setSize(1024, 1024)

        flags = GraphicsPipe.BFRefuseWindow

        buffer = self.graphicsEngine.make_output(
            self.pipe, "some buffer", -2, props, wp, flags, self.win.get_gsg(), self.win)
        self.texture = Texture()
        buffer.add_render_texture(
            tex=self.texture, mode=GraphicsOutput.RTMCopyRam, bitplane=GraphicsOutput.RTPColor)
        self.depth_texture = Texture()
        buffer.add_render_texture(
            tex=self.depth_texture, mode=GraphicsOutput.RTMCopyRam, bitplane=GraphicsOutput.RTPDepthStencil)

def generate_synth():
    loadPrcFileData("",
    """
        gl-debug #t
        window-type offscreen
        aux-display p3headlessgl
    """)

    base = MyApp()
    base.run()

generate_synth()

This will generate lines of :display:gsg:glgsg(error): GL_INVALID_ENUM error generated. <type> enum is invalid.

This can be fixed by setting props.set_float_depth(True) to props.set_float_depth(False)

Environment

Clockwork-Muse commented 3 years ago

My actual use-case only needs RTMBindOrCopy for the depth texture, it just accidentally ended up being RTMCopyRam as I was writing stuff.

rdb commented 3 years ago

Thanks for the high-quality bug report as always.

In case 1 the problem is that you're trying to tell OpenGL to copy the depth buffer to a texture while the framebuffer doesn't actually have a depth buffer. As you've seen, the solution is to request depth bits. Panda ought to be catching this and displaying a more appropriate error. The reason that it doesn't happen with RTMBindOrCopy is that you're providing a depth buffer to render into in that mode (ie. the texture).

I'm afraid I'm not replicating the warning message.

In case 2 the problem is that Panda doesn't currently support storing a combined 32-bit float depth + 8-bit stencil image (which is a bit of an odd and recent feature) in RAM, so it tries to just download the depth component—but because you've bound to RTPDepthStencil instead of just RTPDepth, OpenGL displays an error that it can't stuff the entire depth-stencil buffer into just a 32-bit float texture. I think we need to silently change RTPDepthStencil to RTPDepth until we support this feature.

Fixed builds available here.

Clockwork-Muse commented 3 years ago

@rdb - Perhaps it's because I'm running this in EGL, and you may have run this with normal OpenGL?

rdb commented 3 years ago

You mean that I'm not replicating the warning? I doubt it, I just added load-display p3headlessgl to force EGL and I still don't get a warning.

But, I just realised, you actually meant "making both changes", whereas I understood you meant "adding both set_depth_bits and set_stencil_bits". I still can't reproduce it then on my laptop, but I can reproduce it on my desktop which has an NVIDIA card.

It is a mystery to me why though. I can see in the GL trace produced by apitrace that it's passing the same GL_DEPTH_STENCIL texture to both depth and stencil attachments.