Refactor GlOffscreen; remove the GLEW dependency.
It was never really needed, since both Linux and OS X, where GlOffscreen is used, guarantee that the API we need is present, on all OS versions we're interested in. Also, reorganize GlOffscreen consistently with the rest of our codebase, and don't use RAII for OpenGL resource management because of its requirement for an active context.
This commit is contained in:
parent
216091a366
commit
7265121b24
@ -4,5 +4,5 @@ sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -q -y \
|
||||
cmake cmake-data libpng12-dev zlib1g-dev libjson0-dev libfontconfig1-dev \
|
||||
libgtkmm-2.4-dev libpangomm-1.4-dev libgl1-mesa-dev libglu-dev libglew-dev \
|
||||
libgtkmm-2.4-dev libpangomm-1.4-dev libgl1-mesa-dev libglu-dev \
|
||||
libfreetype6-dev dpkg-dev gcc-5 g++-5
|
||||
|
@ -196,7 +196,6 @@ else() # Linux and compatible systems
|
||||
pkg_check_modules(PNG REQUIRED libpng)
|
||||
pkg_check_modules(FONTCONFIG REQUIRED fontconfig)
|
||||
pkg_check_modules(JSONC REQUIRED json-c)
|
||||
pkg_check_modules(GLEW REQUIRED glew)
|
||||
pkg_check_modules(FREETYPE REQUIRED freetype2)
|
||||
|
||||
set(HAVE_GTK TRUE)
|
||||
|
@ -31,7 +31,7 @@ On a Debian derivative (e.g. Ubuntu) these can be installed with:
|
||||
|
||||
apt-get install libpng-dev libjson-c-dev libfreetype6-dev \
|
||||
libfontconfig1-dev libgtkmm-2.4-dev libpangomm-1.4-dev \
|
||||
libgl-dev libglu-dev libglew-dev cmake
|
||||
libgl-dev libglu-dev cmake
|
||||
|
||||
Before building, check out the necessary submodules:
|
||||
|
||||
|
2
debian/control
vendored
2
debian/control
vendored
@ -4,7 +4,7 @@ Priority: optional
|
||||
Maintainer: whitequark <whitequark@whitequark.org>
|
||||
Build-Depends: debhelper (>= 9), cmake, libpng-dev, zlib1g-dev, libjson-c-dev,
|
||||
libfontconfig1-dev, libgtkmm-2.4-dev, libpangomm-1.4-dev,
|
||||
libgl-dev, libglu-dev, libglew-dev
|
||||
libgl-dev, libglu-dev
|
||||
Standards-Version: 3.9.5
|
||||
Homepage: http://solvespace.com
|
||||
Vcs-Git: git://github.com/whitequark/solvespace
|
||||
|
@ -89,7 +89,7 @@ elseif(APPLE)
|
||||
|
||||
set(platform_SOURCES
|
||||
platform/cocoamain.mm
|
||||
platform/gloffscreen.cpp)
|
||||
render/rendergl.cpp)
|
||||
|
||||
set(platform_BUNDLED_LIBS
|
||||
${PNG_LIBRARIES}
|
||||
@ -101,30 +101,26 @@ elseif(HAVE_GTK)
|
||||
include_directories(
|
||||
${GTKMM_INCLUDE_DIRS}
|
||||
${JSONC_INCLUDE_DIRS}
|
||||
${FONTCONFIG_INCLUDE_DIRS}
|
||||
${GLEW_INCLUDE_DIRS})
|
||||
${FONTCONFIG_INCLUDE_DIRS})
|
||||
|
||||
link_directories(
|
||||
${GTKMM_LIBRARY_DIRS}
|
||||
${JSONC_LIBRARY_DIRS}
|
||||
${FONTCONFIG_LIBRARY_DIRS}
|
||||
${GLEW_LIBRARY_DIRS})
|
||||
${FONTCONFIG_LIBRARY_DIRS})
|
||||
|
||||
add_definitions(
|
||||
${GTKMM_CFLAGS_OTHER}
|
||||
${JSONC_CFLAGS_OTHER}
|
||||
${FONTCONFIG_CFLAGS_OTHER}
|
||||
${GLEW_CFLAGS_OTHER})
|
||||
${FONTCONFIG_CFLAGS_OTHER})
|
||||
|
||||
set(platform_SOURCES
|
||||
platform/gtkmain.cpp
|
||||
platform/gloffscreen.cpp)
|
||||
render/rendergl.cpp)
|
||||
|
||||
set(platform_LIBRARIES
|
||||
${GTKMM_LIBRARIES}
|
||||
${JSONC_LIBRARIES}
|
||||
${FONTCONFIG_LIBRARIES}
|
||||
${GLEW_LIBRARIES})
|
||||
${FONTCONFIG_LIBRARIES})
|
||||
endif()
|
||||
|
||||
# solvespace executable
|
||||
|
@ -7,9 +7,6 @@
|
||||
// Copyright 2008-2013 Jonathan Westhues.
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "solvespace.h"
|
||||
#ifndef WIN32
|
||||
#include <platform/gloffscreen.h>
|
||||
#endif
|
||||
|
||||
void SolveSpaceUI::ExportSectionTo(const std::string &filename) {
|
||||
Vector gn = (SS.GW.projRight).Cross(SS.GW.projUp);
|
||||
@ -1084,10 +1081,11 @@ void SolveSpaceUI::ExportAsPngTo(const std::string &filename) {
|
||||
bool prevShowToolbar = SS.showToolbar;
|
||||
SS.showToolbar = false;
|
||||
#ifndef WIN32
|
||||
std::unique_ptr<GLOffscreen> gloffscreen(new GLOffscreen);
|
||||
gloffscreen->begin((int)SS.GW.width, (int)SS.GW.height);
|
||||
GlOffscreen offscreen;
|
||||
offscreen.Render((int)SS.GW.width, (int)SS.GW.height, [&] {
|
||||
SS.GW.Paint();
|
||||
});
|
||||
#endif
|
||||
SS.GW.Paint();
|
||||
SS.showToolbar = prevShowToolbar;
|
||||
|
||||
// Somewhat hacky way to invoke glReadPixels without dragging in all OpenGL headers.
|
||||
@ -1100,6 +1098,11 @@ void SolveSpaceUI::ExportAsPngTo(const std::string &filename) {
|
||||
Error("Couldn't write to '%s'", filename.c_str());
|
||||
}
|
||||
if(f) fclose(f);
|
||||
|
||||
#ifndef WIN32
|
||||
offscreen.Clear();
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <map>
|
||||
|
||||
#include "solvespace.h"
|
||||
#include "gloffscreen.h"
|
||||
#include <config.h>
|
||||
|
||||
using SolveSpace::dbp;
|
||||
@ -126,7 +125,7 @@ const bool SolveSpace::FLIP_FRAMEBUFFER = false;
|
||||
|
||||
@implementation GLViewWithEditor
|
||||
{
|
||||
GLOffscreen *offscreen;
|
||||
SolveSpace::GlOffscreen offscreen;
|
||||
NSOpenGLContext *glContext;
|
||||
@protected
|
||||
NSTextField *editor;
|
||||
@ -156,7 +155,7 @@ const bool SolveSpace::FLIP_FRAMEBUFFER = false;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
delete offscreen;
|
||||
offscreen.Clear();
|
||||
}
|
||||
|
||||
#define CONVERT1(name, to_from) \
|
||||
@ -187,19 +186,13 @@ CONVERT(Rect)
|
||||
- (void)drawRect:(NSRect)aRect {
|
||||
[glContext makeCurrentContext];
|
||||
|
||||
if(!offscreen)
|
||||
offscreen = new GLOffscreen;
|
||||
|
||||
NSSize size = [self convertSizeToBacking:[self bounds].size];
|
||||
int width = (int)size.width,
|
||||
height = (int)size.height;
|
||||
offscreen->begin(width, height);
|
||||
offscreen.Render(width, height, [&] { [self drawGL]; });
|
||||
|
||||
[self drawGL];
|
||||
|
||||
uint8_t *pixels = offscreen->end();
|
||||
CGDataProviderRef provider = CGDataProviderCreateWithData(
|
||||
NULL, pixels, width * height * 4, NULL);
|
||||
NULL, &offscreen.data[0], width * height * 4, NULL);
|
||||
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
|
||||
CGImageRef image = CGImageCreate(width, height, 8, 32,
|
||||
width * 4, colorspace, kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst,
|
||||
|
@ -1,74 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Offscreen rendering in OpenGL using framebuffer objects.
|
||||
//
|
||||
// Copyright 2015 <whitequark@whitequark.org>
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef __APPLE__
|
||||
#include <OpenGL/GL.h>
|
||||
#else
|
||||
#include <GL/glew.h>
|
||||
#endif
|
||||
|
||||
#include "gloffscreen.h"
|
||||
#include "solvespace.h"
|
||||
|
||||
GLOffscreen::GLOffscreen() : _pixels(NULL), _width(0), _height(0) {
|
||||
#ifndef __APPLE__
|
||||
ssassert(glewInit() == GLEW_OK, "Unexpected GLEW failure");
|
||||
#endif
|
||||
|
||||
ssassert(GL_EXT_framebuffer_object, "Expected an available FBO extension");
|
||||
|
||||
glGenFramebuffersEXT(1, &_framebuffer);
|
||||
glGenRenderbuffersEXT(1, &_color_renderbuffer);
|
||||
glGenRenderbuffersEXT(1, &_depth_renderbuffer);
|
||||
}
|
||||
|
||||
GLOffscreen::~GLOffscreen() {
|
||||
delete[] _pixels;
|
||||
glDeleteRenderbuffersEXT(1, &_depth_renderbuffer);
|
||||
glDeleteRenderbuffersEXT(1, &_color_renderbuffer);
|
||||
glDeleteFramebuffersEXT(1, &_framebuffer);
|
||||
}
|
||||
|
||||
bool GLOffscreen::begin(int width, int height) {
|
||||
if(_width != width || _height != height) {
|
||||
delete[] _pixels;
|
||||
_pixels = new uint8_t[width * height * 4];
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
}
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _framebuffer);
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _color_renderbuffer);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, _width, _height);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
||||
GL_RENDERBUFFER_EXT, _color_renderbuffer);
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, _depth_renderbuffer);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, _width, _height);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
||||
GL_RENDERBUFFER_EXT, _depth_renderbuffer);
|
||||
|
||||
if(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT)
|
||||
return true;
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *GLOffscreen::end() {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
glReadPixels(0, 0, _width, _height,
|
||||
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, _pixels);
|
||||
#else
|
||||
glReadPixels(0, 0, _width, _height,
|
||||
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, _pixels);
|
||||
#endif
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
return _pixels;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Offscreen rendering in OpenGL using framebuffer objects.
|
||||
//
|
||||
// Copyright 2015 <whitequark@whitequark.org>
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __GLOFFSCREEN_H
|
||||
#define __GLOFFSCREEN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class GLOffscreen {
|
||||
public:
|
||||
/* these allocate and deallocate OpenGL resources.
|
||||
an OpenGL context /must/ be current. */
|
||||
GLOffscreen();
|
||||
~GLOffscreen();
|
||||
|
||||
/* prepare for drawing a frame of specified size.
|
||||
returns true if OpenGL likes our configuration, false
|
||||
otherwise. if it returns false, the OpenGL state is restored. */
|
||||
bool begin(int width, int height);
|
||||
|
||||
/* get pixels out of the frame and restore OpenGL state.
|
||||
the pixel format is ARGB32 with top row at index 0 if
|
||||
flip is true and bottom row at index 0 if flip is false.
|
||||
the returned array is valid until the next call to begin() */
|
||||
uint8_t *end();
|
||||
|
||||
private:
|
||||
unsigned int _framebuffer;
|
||||
unsigned int _color_renderbuffer, _depth_renderbuffer;
|
||||
uint8_t *_pixels;
|
||||
int _width, _height;
|
||||
};
|
||||
|
||||
#endif
|
@ -52,7 +52,6 @@
|
||||
|
||||
#include "solvespace.h"
|
||||
#include "config.h"
|
||||
#include "gloffscreen.h"
|
||||
|
||||
#ifdef HAVE_SPACEWARE
|
||||
# include <spnav.h>
|
||||
@ -228,7 +227,7 @@ const bool FLIP_FRAMEBUFFER = true;
|
||||
|
||||
class GlWidget : public Gtk::DrawingArea {
|
||||
public:
|
||||
GlWidget() : _offscreen(NULL) {
|
||||
GlWidget() {
|
||||
_xdisplay = gdk_x11_get_default_xdisplay();
|
||||
|
||||
int glxmajor, glxminor;
|
||||
@ -297,7 +296,7 @@ public:
|
||||
|
||||
XDestroyWindow(_xdisplay, _xwindow);
|
||||
|
||||
delete _offscreen;
|
||||
_offscreen.Clear();
|
||||
|
||||
glXDestroyContext(_xdisplay, _glcontext);
|
||||
}
|
||||
@ -314,18 +313,16 @@ protected:
|
||||
ssassert(glXMakeCurrent(_xdisplay, _xwindow, _glcontext),
|
||||
"Cannot make OpenGL context current");
|
||||
|
||||
if(!_offscreen)
|
||||
_offscreen = new GLOffscreen;
|
||||
|
||||
Gdk::Rectangle allocation = get_allocation();
|
||||
ssassert(_offscreen->begin(allocation.get_width(), allocation.get_height()),
|
||||
"Cannot allocate offscreen rendering buffer");
|
||||
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");
|
||||
|
||||
on_gl_draw();
|
||||
|
||||
Cairo::RefPtr<Cairo::ImageSurface> surface = Cairo::ImageSurface::create(
|
||||
_offscreen->end(), Cairo::FORMAT_RGB24,
|
||||
allocation.get_width(), allocation.get_height(), allocation.get_width() * 4);
|
||||
Cairo::RefPtr<Cairo::ImageSurface> 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();
|
||||
@ -338,7 +335,7 @@ protected:
|
||||
private:
|
||||
Display *_xdisplay;
|
||||
GLXContext _glcontext;
|
||||
GLOffscreen *_offscreen;
|
||||
GlOffscreen _offscreen;
|
||||
::Window _xwindow;
|
||||
};
|
||||
|
||||
|
@ -204,6 +204,17 @@ public:
|
||||
bool Pick(std::function<void()> drawFn);
|
||||
};
|
||||
|
||||
// An offscreen renderer based on OpenGL framebuffers.
|
||||
class GlOffscreen {
|
||||
public:
|
||||
unsigned int framebuffer;
|
||||
unsigned int colorRenderbuffer, depthRenderbuffer;
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
bool Render(int width, int height, std::function<void()> renderFn);
|
||||
void Clear();
|
||||
};
|
||||
|
||||
// A canvas that uses the core OpenGL profile, for desktop systems.
|
||||
class OpenGl1Renderer : public Canvas {
|
||||
public:
|
||||
|
57
src/render/rendergl.cpp
Normal file
57
src/render/rendergl.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Offscreen rendering in OpenGL using EGL and framebuffer objects.
|
||||
//
|
||||
// Copyright 2015-2016 whitequark
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifdef __APPLE__
|
||||
#include <OpenGL/GL.h>
|
||||
#else
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
#endif
|
||||
|
||||
#include "solvespace.h"
|
||||
|
||||
void GlOffscreen::Clear() {
|
||||
glDeleteRenderbuffersEXT(1, &depthRenderbuffer);
|
||||
glDeleteRenderbuffersEXT(1, &colorRenderbuffer);
|
||||
glDeleteFramebuffersEXT(1, &framebuffer);
|
||||
*this = {};
|
||||
}
|
||||
|
||||
bool GlOffscreen::Render(int width, int height, std::function<void()> renderFn) {
|
||||
data.resize(width * height * 4);
|
||||
|
||||
if(framebuffer == 0) {
|
||||
glGenFramebuffersEXT(1, &framebuffer);
|
||||
glGenRenderbuffersEXT(1, &colorRenderbuffer);
|
||||
glGenRenderbuffersEXT(1, &depthRenderbuffer);
|
||||
}
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, colorRenderbuffer);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, width, height);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
||||
GL_RENDERBUFFER_EXT, colorRenderbuffer);
|
||||
|
||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, depthRenderbuffer);
|
||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);
|
||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
|
||||
GL_RENDERBUFFER_EXT, depthRenderbuffer);
|
||||
|
||||
bool framebufferComplete =
|
||||
glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT;
|
||||
if(framebufferComplete) {
|
||||
renderFn();
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &data[0]);
|
||||
#else
|
||||
glReadPixels(0, 0, width, height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, &data[0]);
|
||||
#endif
|
||||
}
|
||||
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
||||
|
||||
return framebufferComplete;
|
||||
}
|
Loading…
Reference in New Issue
Block a user