Skip to content

Merging OpenGLRaw and gl

Sven Panne edited this page Sep 13, 2015 · 26 revisions

Motivation

Currently there are 2 similar, but different Haskell packages available for the raw access to OpenGL, OpenGLRaw and gl. While competition is good and healthy, especially in the Open Source world, the situation is a bit confusing for users: Which package should they use? And why should 2 different teams duplicate their effort for something functionally equivalent? To improve the situation, this proposal aims to merge those packages, basically making it possible to deprecate gl afterwards. The result will be a new version of OpenGLRaw containing "the best of both worlds", at the cost of not being backwards-compatible with neither OpenGLRaw nor gl. This is a price one has to pay to get a clean slate after a long time, and it's a small one considering the fact that previous versions are still available on Hackage.

Differences and how to resolve them

Haskell API

  • OpenGLRaw exposes OpenGL tokens as plain old Haskell values, e.g. gl_LINES = 0x0001 while gl uses bidirectional pattern synonyms, e.g. pattern GL_LINES = 0x0001. While it is a tiny bit more convenient to use and visually resembles the original OpenGL C API slightly more, the PatternSynonyms extension is only available in GHC >= 7.8.1 (released April 2014). Proposal: This is a tough call, it’s basically backwards compatibility vs. ease of use. Perhaps we should use pattern synonyms?
  • The types of the OpenGL tokes are slightly different, too: OpenGLRaw uses the more exact types from the OpenGL registry, i.e. one of GLbitfield, GLenum, GLubyte, GLuint, or GLuint64, while gl always uses (Num a, Eq a) => a. Proposal: Use the more exact types, any kind of conversions should be explicit.
  • OpenGLRaw has types per OpenGL version (see e.g. Core45), gl always exposes all of them (see Types). OpenGLRaw’s approach is following the spec more closely, e.g. GLsizeiptr is only mentioned in OpenGL >= 1.5. Proposal: Use OpenGLRaw’s approach.
  • The gl package exposes OpenGL ES APIs, too, but this is wrong for several reasons (Proposal: Do not expose OpenGL ES stuff, this should live in a separate package):
    • The token values can be API-dependent, and there is actually one example of this: GL_ACTIVE_PROGRAM_EXT has the value 0x8259 under OpenGL ES 2, while it has the value 0x8B8D under OpenGL. While this was actually a specification glitch, it is out in the wild now and ignoring it doesn’t it make go away.
    • OpenGL versions of extensions can be completely unrelated to their OpenGL ES versions, see e.g. GL_EXT_separate_shader_objects.
    • API entry points for OpenGL ES have to be retrieved via EGL, while OpenGL entry points must be retrieved via GLX/WGL/…, i.e. window-system-specific ways. Perhaps in some bright future EGL will be the one and only way (see e.g. the EGL_KHR_create_context) extension, but this is not the case at the moment.
  • Extensions in OpenGLRaw come in 2 versions when needed (core and compatibility, see e.g. VertexType2101010RevCore and VertexType2101010RevCompatibility), while gl ignores that distinction. Proposal: Do it like OpenGLRaw, the OpenGL registry clearly makes it explicit that extensions are profile-dependent in general.
  • OpenGLRaw exposes GLhalf as a synonym for CUShort, while gl depends on the half package’s Half type. This is very handy, but it will add another dependency. Nevertheless, it’s only a small package with few common language extensions. Proposal: Use Half.
  • gl exposes extensions and various related values like gl_EXT_cull_vertex. The problem is that the set of supported extensions is context-dependent in general, so their types are wrong: They must live in the IO monad. The OpenGLRaw package doesn’t have this functionality exposed directly, but the OpenGL package has, see StringQueries. Proposal: Expose the list of extensions and a query for a specific extension with the right type directly in the raw layer.

Module names

  • The module prefix used by OpenGLRaw is Graphics.Rendering.OpenGL.Raw, while gl uses the shorter Graphics.GL. OpenGLRaw’s prefix is overly long and dates back many years, to a time when there was consensus that this might be a good idea. Nowadays gl’s choice looks much saner. Nevertheless, it’s desirable to distinguish the raw binding from any higher-level packages building on it, like OpenGL. Proposal: Use Graphics.GL.Raw as the prefix.
  • gl uses an additional Ext level below Graphics.GL for modules containing extensions, but this is superfluous and only makes things more verbose. The extensions are already grouped by their vendor IDs, which form their own sub-namespaces. Proposal: Simply drop Ext.
  • OpenGLRaw uses the module name VersionXY for OpenGL versions without profiles, while gl uses StandardXY. Proposal: Use VersionXY, it’s more consistent with the OpenGL CPP defines. (no strong preference, though)
  • Although formally OpenGL 3.2 introduced the notion of profiles, the OpenGL registry already does it for 3.0 and 3.1, too. OpenGLRaw follows the registry, while gl does not. The differences are small, though, only GL_INDEX, GL_TEXTURE_LUMINANCE_TYPE, and GL_TEXTURE_INTENSITY_TYPE. Proposal: Follow the registry.

Haddock Documentation

  • OpenGLRaw links to all possible man page versions of an API entry, while gl only links to the latest one, compare e.g. the documentation for glCreateProgram in OpenGLRaw and in gl. Note that the latest man page might document stuff which is not supported in previous versions and therefore it can be quite misleading. The documentation for an entity is always the same, regardless of the version. This is caused by the fact that the various modules basically consist of re-exports only, which is necessary to mix versions and extensions. Proposal: Use OpenGLRaw’s man page links, so the user can choose the right one.
  • OpenGLRaw documents each parameter directly in the signature, while gl does it in a more separated way, compare e.g. the documentation for glGetDebugMessageLog in OpenGLRaw and in gl. The former way avoids the mental matching of parameters and their corresponding documentation and is more direct. Proposal: Use OpenGLRaw’s way of parameter documentation.
  • gl repeatedly expands enumerant groups in the documentation, while OpenGLRaw just mentions the group names, compare e.g. the documentation for glGetTexLevelParameterfv in [gl] (https://hackage.haskell.org/package/gl-0.7.7/docs/Graphics-GL-Core32.html#v:glGetTexLevelParameterfv) and in OpenGLRaw. The problem with enumerant groups in the registry is that they are highly incomplete, and much more importantly: They should better depend on the OpenGL version, which they don’t, so mentioning the individual enumerants is wrong and misleading in general (OpenGL versions both remove and add tokens/functions). Proposal: Mention only the group names, just like OpenGLRaw, the information in the OpenGL registry is relatively useless and broken.

Internals

The differences are not really relevant for users of the package, they are just here for reference.

  • Both OpenGLRaw and gl generate most of the binding from the XML API description from the OpenGL registry. OpenGLRaw has the resulting Haskell files checked in, while gl dynamically generates them during build time. Having the generated files checked in removes the need to build various XML-related packages, so it’s more convenient and faster for people just wanting to use OpenGL. Furthermore, when the OpenGL registry has changed, one has to look at the generated files anyway: The cabal file needs an update, perhaps needing some kind of version bump. Proposal: Continue to check in the generated files.
  • OpenGLRaw uses a git submodule for an OpenGL registry mirror to get gl.xml, while gl uses a checked-in version. Proposal: Use a git submodule, it’s a bit more explicit.

Acknowledgement

Thanks to Edward Kmett and Gabríel Arthúr Pétursson for their work on gl, thereby urging me to do things I would have been too lazy to do otherwise... 😉

Clone this wiki locally