Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

glEnd called twice by renderPrimitive (on Windows) #87

Open
trbauer opened this issue Aug 25, 2017 · 3 comments
Open

glEnd called twice by renderPrimitive (on Windows) #87

trbauer opened this issue Aug 25, 2017 · 3 comments

Comments

@trbauer
Copy link

trbauer commented Aug 25, 2017

The following minimal program calls glEnd twice within renderPrimitive. This is on Windows 32b package version OpenGL 3.0.0.2.

import Graphics.UI.GLUT

main :: IO ()
main = do
  (_progName, _args) <- getArgsAndInitialize
  _window <- createWindow "Hello World"
  displayCallback $= display
  mainLoop

display :: DisplayCallback
display = do
  let vertex3f x y z = vertex (Vertex3 x y (z :: Float))
  clear [ ColorBuffer ]
  renderPrimitive Points $ do
    vertex3f 0 0 0
    putStrLn "rendering point"
    get errors >>= print -- no error
  putStrLn "after renderPrimitive" -- error here
  get errors >>= print
  flush

I've reproduced with GHC 8.0.1 and GHC 8.0.2. This pollutes the error state for programs.
OpenGL 2.9.0.2 on a Mac with GHC 7.8.3 does not exhibit the problem.

@svenpanne
Copy link
Member

I suspect that you have a problem with picking the right OpenGL context. This depends quite a bit on your platform/driver. There are a few things to consider here:

  • First of all, calling get errors within renderPrimitive Points will set the error state to GL_INVALID_OPERATION, because within a glBegin/glEnd only very few OpenGL calls are allowed, and glGetError is not one of them, see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glBegin.xml

  • To use renderPrimitive, you have to make sure that you are using a compatibility context, otherwise glBegin and glEnd are not allowed. You can check this via get contextProfile and/or get (extensionSupported "GL_ARB_compatibility"). You can request the right context via initialContextVersion and initialContextProfile.

  • To debug such things, MESA_DEBUG=1 can help (if you are using Mesa). Starting with OpenGL 4.3, OpenGL's own debug output API is highly recommended. You can immediately get a callback when something goes wrong. A code snippet for this:

initialContextFlags $= [ DebugContext ]
debugMessageCallback $=
  Just (\(DebugMessage _source _typ _ident _severity message) -> putStrLn message)
debugOutputSynchronous $= Enabled
  • Printing information about the implementation can give some hints, too:
flip mapM_ [ ("VENDOR", vendor),
             ("VERSION", glVersion),
             ("RENDERER", renderer) ] $ \(name, var) -> do
    val <- get var
    putStrLn (name ++ ": " ++ val)
  • Why do you think that glEnd is called twice? Does the behavior change when you replace renderPrimitve with OpenGLRaw's glBegin/glEnd calls?

I've tried your program (without the incorrect get errors) under Linux and Mesa 17.07. It works fine if I use a compatibility context and complains as expected when I use a forward-compatible context. I can try this later on a Windows box, but I suspect that the result will stay the same.

@svenpanne
Copy link
Member

After some research and epic debugging sessions, it seems that on Windows we are a victim of the problem described in https://cgit.freedesktop.org/mesa/mesa/commit/?id=c7f0755caa1c39d5433e37c53242ef251aa4fc3a:

... The basic problem is Microsoft's opengl32.dll calls glFlush from wglGetProcAddress() ...

😱 Just like in the test mentioned in the commit above, a glFlush is implicty happening while a glBegin/glEnd pair is open, which is an OpenGL error. Using OpenGL's debug API introduced in 4.3 one gets the following information:

source: SOURCE_API
type: TYPE_ERROR
id: 1282
severity: SEVERITY_HIGH
message (length 136): GL_INVALID_OPERATION error generated. Calling glFlush from the current immediate mode state is invalid. Check glBegin() / glEnd() pairs.

The good thing: This explains why this is a Windows-only problem. The bad thing: Without totally changing the way OpenGLRaw accesses OpenGL entry points, I see no way around that problem. I need to think about this and look at other dynamic OpenGL loaders. One sledgehammer would be: Load all entry points at once (but still lazily, so we have the right context), which might be a big performance hit during startup.

Thanks for a great bug report, it's a miracle why this was not reported earlier.

@trbauer
Copy link
Author

trbauer commented Sep 11, 2017 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants