From 6bb73a162c612307c27cc2472d65065165cc55a7 Mon Sep 17 00:00:00 2001 From: whitequark Date: Mon, 2 Jan 2017 16:21:05 +0000 Subject: [PATCH] GTK: remove GlWidget, use standard Gtk::GLArea. This removes a large number of hacks from the codebase, speeds up the rendering, and removes tearing when dragging entities. --- src/platform/cocoamain.mm | 2 - src/platform/gtkmain.cpp | 142 +++++--------------------------------- src/platform/headless.cpp | 2 - src/platform/w32main.cpp | 2 - src/render/render.h | 2 +- src/render/rendergl1.cpp | 17 ++--- src/render/rendergl2.cpp | 17 ++--- src/solvespace.h | 2 - src/textwin.cpp | 4 ++ 9 files changed, 33 insertions(+), 157 deletions(-) diff --git a/src/platform/cocoamain.mm b/src/platform/cocoamain.mm index f699ad05..eb03df75 100644 --- a/src/platform/cocoamain.mm +++ b/src/platform/cocoamain.mm @@ -104,8 +104,6 @@ void SolveSpace::ScheduleLater() { /* OpenGL view */ -const bool SolveSpace::FLIP_FRAMEBUFFER = false; - @interface GLViewWithEditor : NSView - (void)drawGL; diff --git a/src/platform/gtkmain.cpp b/src/platform/gtkmain.cpp index 4337ce7a..3486158d 100644 --- a/src/platform/gtkmain.cpp +++ b/src/platform/gtkmain.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -33,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -213,121 +213,6 @@ void ScheduleLater() { Glib::signal_idle().connect(&LaterCallback); } -/* GL wrapper */ - -const bool FLIP_FRAMEBUFFER = true; - -class GlWidget : public Gtk::DrawingArea { -public: - GlWidget() : _offscreen() { - _xdisplay = gdk_x11_get_default_xdisplay(); - - int glxmajor, glxminor; - ssassert(glXQueryVersion(_xdisplay, &glxmajor, &glxminor), - "Expected OpenGL to be available"); - - ssassert(glxmajor > 1 || (glxmajor == 1 && glxminor >= 3), - "Expected GLX >= 1.3"); - - static int fbconfig_attrs[] = { - GLX_RENDER_TYPE, GLX_RGBA_BIT, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_DEPTH_SIZE, 24, - None - }; - int fbconfig_num = 0; - GLXFBConfig *fbconfigs = glXChooseFBConfig(_xdisplay, DefaultScreen(_xdisplay), - fbconfig_attrs, &fbconfig_num); - ssassert(fbconfigs && fbconfig_num > 0, - "Expected an available framebuffer configuration"); - - /* prefer FBConfigs with depth of 32; - * Mesa software rasterizer explodes with a BadMatch without this; - * without this, Intel on Mesa flickers horribly for some reason. - this does not seem to affect other rasterizers (ie NVidia). - - see this Mesa bug: - http://lists.freedesktop.org/archives/mesa-dev/2015-January/074693.html */ - GLXFBConfig fbconfig = fbconfigs[0]; - for(int i = 0; i < fbconfig_num; i++) { - XVisualInfo *visual_info = glXGetVisualFromFBConfig(_xdisplay, fbconfigs[i]); - /* some GL visuals, notably on Chromium GL, do not have an associated - X visual; this is not an obstacle as we always render offscreen. */ - if(!visual_info) continue; - int depth = visual_info->depth; - XFree(visual_info); - - if(depth == 32) { - fbconfig = fbconfigs[i]; - break; - } - } - - _glcontext = glXCreateNewContext(_xdisplay, - fbconfig, GLX_RGBA_TYPE, 0, True); - ssassert(_glcontext != NULL, "Cannot create an OpenGL context"); - - XFree(fbconfigs); - - /* create a dummy X window to create a rendering context against. - we could use a Pbuffer, but some implementations (Chromium GL) - don't support these. we could use an existing window, but - some implementations (Chromium GL... do you see a pattern?) - do really strange things, i.e. draw a black rectangle on - the very front of the desktop if you do this. */ - _xwindow = XCreateSimpleWindow(_xdisplay, - XRootWindow(_xdisplay, gdk_x11_get_default_screen()), - /*x*/ 0, /*y*/ 0, /*width*/ 1, /*height*/ 1, - /*border_width*/ 0, /*border*/ 0, /*background*/ 0); - } - - ~GlWidget() { - glXMakeCurrent(_xdisplay, None, NULL); - - XDestroyWindow(_xdisplay, _xwindow); - - _offscreen.Clear(); - - glXDestroyContext(_xdisplay, _glcontext); - } - -protected: - /* Draw on a GLX framebuffer object, then read pixels out and draw them on - the Cairo context. Slower, but you get to overlay nice widgets. */ - bool on_draw(const Cairo::RefPtr &cr) override { - ssassert(glXMakeCurrent(_xdisplay, _xwindow, _glcontext), - "Cannot make OpenGL context current"); - - Gdk::Rectangle allocation = get_allocation(); - bool success = _offscreen.Render( - allocation.get_width(), allocation.get_height(), - sigc::mem_fun(this, &GlWidget::on_gl_draw)); - ssassert(success, "Cannot allocate offscreen rendering buffer"); - - Cairo::RefPtr surface = - Cairo::ImageSurface::create(&_offscreen.data[0], Cairo::FORMAT_RGB24, - allocation.get_width(), allocation.get_height(), - allocation.get_width() * 4); - cr->set_source(surface, 0, 0); - cr->paint(); - surface->finish(); - - glXSwapBuffers(_xdisplay, _xwindow); - - return true; - } - - virtual void on_gl_draw() = 0; - -private: - Display *_xdisplay; - GLXContext _glcontext; - GlOffscreen _offscreen; - ::Window _xwindow; -}; - /* Editor overlay */ class EditorOverlay : public Gtk::Fixed { @@ -441,26 +326,27 @@ double DeltaYOfScrollEvent(GdkEventScroll *event) { return delta_y; } -class GraphicsWidget : public GlWidget { +class GraphicsWidget : public Gtk::GLArea { public: GraphicsWidget() { set_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::SCROLL_MASK | Gdk::LEAVE_NOTIFY_MASK); - set_double_buffered(true); + set_has_alpha(true); + set_has_depth_buffer(true); + set_use_es(true); } protected: - bool on_configure_event(GdkEventConfigure *event) override { - _w = event->width; - _h = event->height; - - return GlWidget::on_configure_event(event);; + void on_resize(int width, int height) override { + _w = width; + _h = height; } - void on_gl_draw() override { + bool on_render(const Glib::RefPtr &context) override { SS.GW.Paint(); + return true; } bool on_motion_notify_event(GdkEventMotion *event) override { @@ -1196,11 +1082,14 @@ DialogChoice LocateImportedFileYesNoCancel(const std::string &filename, /* Text window */ -class TextWidget : public GlWidget { +class TextWidget : public Gtk::GLArea { public: TextWidget(Glib::RefPtr adjustment) : _adjustment(adjustment) { set_events(Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::SCROLL_MASK | Gdk::LEAVE_NOTIFY_MASK); + set_has_alpha(true); + set_has_depth_buffer(true); + set_use_es(true); } void set_cursor_hand(bool is_hand) { @@ -1212,8 +1101,9 @@ public: } protected: - void on_gl_draw() override { + bool on_render(const Glib::RefPtr &context) override { SS.TW.Paint(); + return true; } bool on_motion_notify_event(GdkEventMotion *event) override { diff --git a/src/platform/headless.cpp b/src/platform/headless.cpp index 845eeb0a..99f7bd5c 100644 --- a/src/platform/headless.cpp +++ b/src/platform/headless.cpp @@ -93,8 +93,6 @@ void ScheduleLater() { // Rendering //----------------------------------------------------------------------------- -const bool FLIP_FRAMEBUFFER = false; - std::shared_ptr CreateRenderer() { return NULL; } diff --git a/src/platform/w32main.cpp b/src/platform/w32main.cpp index 065dc959..e2ec91a7 100644 --- a/src/platform/w32main.cpp +++ b/src/platform/w32main.cpp @@ -757,8 +757,6 @@ void SolveSpace::ShowTextWindow(bool visible) ShowWindow(TextWnd, visible ? SW_SHOWNOACTIVATE : SW_HIDE); } -const bool SolveSpace::FLIP_FRAMEBUFFER = false; - #if HAVE_OPENGL == 2 static void CreateGlContext(HWND hwnd, EGLDisplay *eglDisplay, EGLSurface *eglSurface, EGLContext *eglContext) { diff --git a/src/render/render.h b/src/render/render.h index 1717f832..1423c5e5 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -172,7 +172,7 @@ public: // An interface for view-dependent visualization. class ViewportCanvas : public Canvas { public: - virtual void SetCamera(const Camera &camera, bool filp = FLIP_FRAMEBUFFER) = 0; + virtual void SetCamera(const Camera &camera) = 0; virtual void SetLighting(const Lighting &lighting) = 0; virtual void NewFrame() = 0; diff --git a/src/render/rendergl1.cpp b/src/render/rendergl1.cpp index f977dafb..96b3297c 100644 --- a/src/render/rendergl1.cpp +++ b/src/render/rendergl1.cpp @@ -215,8 +215,8 @@ public: void DoPoint(Vector p, double radius); void DoStippledLine(const Vector &a, const Vector &b, hStroke hcs, double phase = 0.0); - void UpdateProjection(bool flip = FLIP_FRAMEBUFFER); - void SetCamera(const Camera &camera, bool filp = FLIP_FRAMEBUFFER) override; + void UpdateProjection(); + void SetCamera(const Camera &camera) override; void SetLighting(const Lighting &lighting) override; void NewFrame() override; @@ -702,7 +702,7 @@ void OpenGl1Renderer::InvalidatePixmap(std::shared_ptr pm) { } } -void OpenGl1Renderer::UpdateProjection(bool flip) { +void OpenGl1Renderer::UpdateProjection() { UnSelectPrimitive(); glViewport(0, 0, camera.width, camera.height); @@ -717,17 +717,12 @@ void OpenGl1Renderer::UpdateProjection(bool flip) { double mat[16]; // Last thing before display is to apply the perspective double clp = camera.tangent * camera.scale; - double sy = flip ? -1.0 : 1.0; MakeMatrix(mat, 1, 0, 0, 0, - 0, sy, 0, 0, + 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, clp, 1); glMultMatrixd(mat); - // If we flip the framebuffer, then we also flip the handedness - // of the coordinate system, and so the face winding order. - glFrontFace(flip ? GL_CW : GL_CCW); - // Before that, we apply the rotation Vector projRight = camera.projRight, projUp = camera.projUp, @@ -829,9 +824,9 @@ void OpenGl1Renderer::GetIdent(const char **vendor, const char **renderer, const *version = (const char *)glGetString(GL_VERSION); } -void OpenGl1Renderer::SetCamera(const Camera &c, bool flip) { +void OpenGl1Renderer::SetCamera(const Camera &c) { camera = c; - UpdateProjection(flip); + UpdateProjection(); } void OpenGl1Renderer::SetLighting(const Lighting &l) { diff --git a/src/render/rendergl2.cpp b/src/render/rendergl2.cpp index 00ab2b5e..20a78161 100644 --- a/src/render/rendergl2.cpp +++ b/src/render/rendergl2.cpp @@ -129,8 +129,8 @@ public: void DoPoint(Vector p, hStroke hs); void DoStippledLine(const Vector &a, const Vector &b, hStroke hcs); - void UpdateProjection(bool flip = FLIP_FRAMEBUFFER); - void SetCamera(const Camera &c, bool flip) override; + void UpdateProjection(); + void SetCamera(const Camera &c) override; void SetLighting(const Lighting &l) override; void NewFrame() override; @@ -528,7 +528,7 @@ void OpenGl2Renderer::DrawPixmap(std::shared_ptr pm, mli->mesh.AddPixmap(o, u, v, ta, tb); } -void OpenGl2Renderer::UpdateProjection(bool flip) { +void OpenGl2Renderer::UpdateProjection() { glViewport(0, 0, camera.width, camera.height); double mat1[16]; @@ -547,18 +547,13 @@ void OpenGl2Renderer::UpdateProjection(bool flip) { // Last thing before display is to apply the perspective double clp = camera.tangent * camera.scale; - double fy = flip ? -1.0 : 1.0; MakeMatrix(mat2, 1, 0, 0, 0, - 0, fy, 0, 0, + 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, clp, 1 ); - // If we flip the framebuffer, then we also flip the handedness - // of the coordinate system, and so the face winding order. - glFrontFace(flip ? GL_CW : GL_CCW); - double projection[16]; MultMatrix(mat1, mat2, projection); @@ -668,9 +663,9 @@ void OpenGl2Renderer::GetIdent(const char **vendor, const char **renderer, const *version = (const char *)glGetString(GL_VERSION); } -void OpenGl2Renderer::SetCamera(const Camera &c, bool flip) { +void OpenGl2Renderer::SetCamera(const Camera &c) { camera = c; - UpdateProjection(flip); + UpdateProjection(); } void OpenGl2Renderer::SetLighting(const Lighting &l) { diff --git a/src/solvespace.h b/src/solvespace.h index f914136b..d4b70edd 100644 --- a/src/solvespace.h +++ b/src/solvespace.h @@ -149,8 +149,6 @@ enum class ContextCommand : uint32_t; #define PATH_SEP "/" #endif -extern const bool FLIP_FRAMEBUFFER; - bool PathEqual(const std::string &a, const std::string &b); std::string PathSepPlatformToUnix(const std::string &filename); std::string PathSepUnixToPlatform(const std::string &filename); diff --git a/src/textwin.cpp b/src/textwin.cpp index 78fafafe..2b9ace99 100644 --- a/src/textwin.cpp +++ b/src/textwin.cpp @@ -865,8 +865,12 @@ void TextWindow::Paint() { camera.offset.x = -(double)camera.width / 2.0; camera.offset.y = -(double)camera.height / 2.0; + Lighting lighting = {}; + lighting.backgroundColor = RGBi(0, 0, 0); + canvas->NewFrame(); canvas->SetCamera(camera); + canvas->SetLighting(lighting); UiCanvas uiCanvas = {}; uiCanvas.canvas = canvas;