libui icon indicating copy to clipboard operation
libui copied to clipboard

OpenGL control

Open mkeeter opened this issue 8 years ago • 37 comments

Are there any plans to add an OpenGL control?

GLFW is great for making a bare window and OpenGL context across platforms, but doesn't have the sweet cross-platform UI support that libui seems to offer.

mkeeter avatar May 20 '16 20:05 mkeeter

Yes. Unfortunately, GTK+ only added OpenGL support in 3.16, so if I want to use that I'll need to make it a separate library until I can bump my version numbers up (2018) or use the X11-only tegtkgl until then (possibly with Wayland once I formally drop 3.4-3.8 sometime this weekend or next week).

andlabs avatar May 20 '16 20:05 andlabs

This would potentially be really interesting for https://github.com/servo/servo/. +1 here :)

pcwalton avatar May 20 '16 22:05 pcwalton

@andlabs If you're willing to provide a sketch of the API you're looking for, I could start on implementing this in my spare time.

pcwalton avatar May 21 '16 21:05 pcwalton

I'd have to evaluate what APIs I can provide; that would mean going through wgl, GtkGLArea, and NSOpenGLView to see how they work and how to do OpenGL with them.

andlabs avatar May 21 '16 21:05 andlabs

If you haven't seen it yet, a good place to start is looking at GLFW's window attributes (as windows are 1:1 with GL contexts). This set of attributes is supported across WGL, GtkGLArea, and NSOpenGLView. Another place to look is the GL attributes for the Rust glutin library (which I've done a good bit of work on): these are supported across all three backends as well.

Those, along with a MakeCurrent() (wglMakeCurrent()/CGLSetCurrentContext()/gtk_gl_area_make_current()) API and a rendering callback (that calls wglSwapBuffers() on Windows and CGLFlushDrawable() on Mac), would be enough to get started for our purposes :)

pcwalton avatar May 21 '16 21:05 pcwalton

Besides all of the above, which helps a lot (thanks!), there's also realization/unrealization and context creation, which I'm also not fully sure about. There's also minimum OpenGL versions and required extensions, which have hit some programmers using GtkGLArea before.

Should OpenGL areas be scrollable? I want the uiOpenGLArea to be as orthogonal to uiArea as possible, even using much of the same code.

andlabs avatar May 22 '16 02:05 andlabs

As far as realization/unrealization, if I'm understanding you correctly, I believe all you need to do is call the platform specific version of MakeCurrent() before the rendering callback. Note that lots of games (and us) will want to be able to call MakeCurrent() outside of the rendering callback and do our rendering outside of the main loop—obviously this requires a "step" kind of function like the one in #21.

For context creation, WGL and NSOpenGLView both support the full set of attributes; you use wglCreateContext() for WGL, and for NSOpenGLView you use -[NSOpenGLView initWithFrame:pixelFormat:]. Note that for me it was actually easier to not use NSOpenGLView and to just use a plain old NSView with a CGL context; NSOpenGLView really doesn't provide much if you're not using Interface Builder.

From a glance, it doesn't look like the GTK stuff provides all of the pixel format attributes that GLX does, which is a nuisance. I guess we'll have to either just omit unsupported pixel formats or drop down to GLX directly.

I personally don't care whether the OpenGL area is scrollable (Servo implements scrolling itself), but if it makes it easier for you I think all UI systems support it.

pcwalton avatar May 22 '16 03:05 pcwalton

I suppose having backend-specific OpenGL code for Unix is fine; we'd really only need to support the backends that GTK+ itself supports that aren't Windows and OS X (and possibly also Broadway). Waiting a week for me to switch to 3.10 will help here, but it's not necessary. We can build on tegtkgl or one of its forks (but some are GPL, so we can't use those), or build it from scratch? Whatever you think is best, I suppose :) I'm not fully familiar with OpenGL in desktop applications yet myself.

By realization/unrealization I meant for allocating and deallocating context-specific resources like shaders. I assume on OS X and Windows the context will never change, right?

andlabs avatar May 22 '16 06:05 andlabs

I'm not actually sure how the GTK GL view deals with realization and unrealization. In general, if you use the GLX API (or something that wraps it) then you can assume your context will stay put, just as on Windows and Mac it will.

pcwalton avatar May 22 '16 19:05 pcwalton

The GTK+ GL API ties a GL context to a GdkWindow; if something causes a widget's GdkWindow to change (for instance, moving a widget from one GtkWindow to another) then the context will need to be re-realized. If using GLX directly makes this unnecessary then I suppose we can just go ahead and implement it ourselves. Still curious about how Wayland will work...

I guess you can get started now if you'd like :) I'll probably merge in uiMainStep() or similar later today.

andlabs avatar May 22 '16 19:05 andlabs

Does what I said sound fine? I added uiMainStep() in the meantime.

andlabs avatar May 25 '16 02:05 andlabs

Yup, sounds good :) I'm not sure how much time I'll have to work on this in the near term, so feel free to take it if you'd like.

pcwalton avatar May 25 '16 18:05 pcwalton

I've started on this: http://github.com/pcwalton/libui/tree/gl

Tasks:

  • [x] Declare the basic interface.
  • [x] Write an example.
  • [x] Implement basic functionality on Mac.
  • [x] Implement basic functionality on Linux.
  • [ ] Implement basic functionality on Windows.
  • [x] Unify the interface with uiArea to allow for event handling, etc.
  • [x] Unify the interface per above on Mac.
  • [x] Unify the interface per above on Linux.
  • [ ] Unify the interface per above on Windows.
  • [x] Add support for an InitGL callback per request on Mac.
  • [x] Add support for an InitGL callback per request on Linux.
  • [ ] Improve the example to show animation, etc.

pcwalton avatar May 30 '16 18:05 pcwalton

For unification, I was thinking of having a uiAreaEventHandler with just the event handler interface, that both uiAreaHandler and uiOpenGLAreaHandler (if that one is needed) derive from in the same COM-like way uiDarwinControl derives from uiControl.

On the backend, the area event handling code would be split and a uiAreaEventState object would be used to handle events. These would be accessible via functions on GTK+, a BOOL handlmessage(HWND, UINT, WPARAM, LPARAM, LRESULT *) type thing on Windows, and an Objective-C class that implements the requisite methods on OS X. Each uiArea would have one of these and delegate their input handling work to that helper object.

andlabs avatar May 31 '16 16:05 andlabs

Excellent, that sounds totally doable.

pcwalton avatar May 31 '16 16:05 pcwalton

What branch is this on again? I forgot already.

andlabs avatar Jun 06 '16 01:06 andlabs

The gl branch.

pcwalton avatar Jun 06 '16 12:06 pcwalton

Looks good to me so far :) If you want to merge it now, all that would need to be changed is the build system setup. Unless you want to wait for the Windows support?

andlabs avatar Jun 06 '16 13:06 andlabs

I'm working on Windows right now.

pcwalton avatar Jun 06 '16 14:06 pcwalton

I have Windows support via WGL drafted and am debugging it now.

pcwalton avatar Jun 12 '16 01:06 pcwalton

Cool. I'm working on the uiGrid layout control; I can start merging other things once I finish that up.

andlabs avatar Jun 12 '16 01:06 andlabs

Great work so far, I have been following the progress closely, because OpenGL support would be mandatory, if I wanted to replace the current GUI system with libui to support other platforms. One question that has arisen though is, whether rendering in a background thread is possible? I noticed MakeCurrent is exposed, so in theory everything is in place, but are there any known limitations in regards to threading?

trevex avatar Jun 12 '16 20:06 trevex

On OS X CVDisplayLink I believe is the recommended way to use OpenGL, and that runs in a separate thread.

kainjow avatar Jun 12 '16 21:06 kainjow

I don't like CVDisplayLink much: it doesn't synchronize to the vertical retrace, only to the vertical retrace interval. It's the equivalent of setting a kernel timer for 60 Hz—in fact, that's what it does (assuming your monitor refresh rate is 60 Hz). The result is that CVDisplayLink doesn't relieve you of the need to set an appropriate swap interval and enable vsync. And if you do set an appropriate swap interval and block in CGLFlushDrawable, then there's usually no need to use CVDisplayLink.

pcwalton avatar Jun 12 '16 23:06 pcwalton

To reiterate somehow: Sorry, if I didn't made myself clear. I meant users being able to use rendering threads with libui rather than libui using a rendering thread. As I mentioned MakeCurrent is there and basically all you need, but I wanted to know whether there are any limitations regarding threading and safety of libui and/or specific GUI backends, e.g. is SwapBuffers thread-safe?

trevex avatar Jun 13 '16 06:06 trevex

uiOpenGLAreaMakeCurrent is guaranteed to be thread-safe in that it can be called from a thread other than the thread you created the area on, but a context can only belong to one thread at a time. I believe you can also call uiOpenGLAreaSwapBuffers from any thread that the context is current for, though I would need to double-check this.

pcwalton avatar Jun 13 '16 09:06 pcwalton

Quick updates:

  • uiArea scrolling sizes are now int
  • uiMouseEvent Down, Up, and Count are also now int

(as per #25)

andlabs avatar Jun 14 '16 01:06 andlabs

Any progress? :)

andlabs avatar Jun 29 '16 18:06 andlabs

Sorry, haven't had a lot of time for this lately…

pcwalton avatar Jul 26 '16 00:07 pcwalton

Any update?

dgellow avatar Jan 01 '17 21:01 dgellow