1 /* === S Y N F I G ========================================================= */
2 /*!	\file synfig/rendering/opengl/internal/context.cpp
3 **	\brief Context
4 **
5 **	$Id$
6 **
7 **	\legal
8 **	......... ... 2015 Ivan Mahonin
9 **
10 **	This package is free software; you can redistribute it and/or
11 **	modify it under the terms of the GNU General Public License as
12 **	published by the Free Software Foundation; either version 2 of
13 **	the License, or (at your option) any later version.
14 **
15 **	This package is distributed in the hope that it will be useful,
16 **	but WITHOUT ANY WARRANTY; without even the implied warranty of
17 **	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 **	General Public License for more details.
19 **	\endlegal
20 */
21 /* ========================================================================= */
22 
23 /* === H E A D E R S ======================================================= */
24 
25 #ifdef USING_PCH
26 #	include "pch.h"
27 #else
28 #ifdef HAVE_CONFIG_H
29 #	include <config.h>
30 #endif
31 
32 #ifndef _WIN32
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <signal.h>
36 #endif
37 
38 #include <synfig/general.h>
39 #include <synfig/localization.h>
40 
41 #include "context.h"
42 
43 #endif
44 
45 using namespace synfig;
46 using namespace rendering;
47 
48 /* === M A C R O S ========================================================= */
49 
50 #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
51 #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
52 
53 /* === G L O B A L S ======================================================= */
54 
55 typedef GLXContext (*GLXCREATECONTEXTATTRIBSARBPROC)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
56 
57 /* === P R O C E D U R E S ================================================= */
58 
59 /* === M E T H O D S ======================================================= */
60 
61 #define ADD_ENUM(x) std::pair<GLenum, const char *>(x, #x)
62 std::pair<GLenum, const char*> gl::Context::enum_strings[] = {
63 	// errors
64 	ADD_ENUM(GL_INVALID_ENUM),
65 	ADD_ENUM(GL_INVALID_VALUE),
66 	ADD_ENUM(GL_INVALID_OPERATION),
67 	ADD_ENUM(GL_INVALID_FRAMEBUFFER_OPERATION),
68 	ADD_ENUM(GL_STACK_OVERFLOW),
69 	ADD_ENUM(GL_STACK_UNDERFLOW),
70 	ADD_ENUM(GL_OUT_OF_MEMORY),
71 	// framebuffer statuses
72 	ADD_ENUM(GL_FRAMEBUFFER_COMPLETE),
73 	ADD_ENUM(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
74 	ADD_ENUM(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
75 	ADD_ENUM(GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER),
76 	ADD_ENUM(GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER),
77 	ADD_ENUM(GL_FRAMEBUFFER_UNSUPPORTED),
78 	// end
79 	ADD_ENUM(GL_NONE) };
80 
81 
82 
83 void
make_current() const84 gl::Context::ContextInfo::make_current() const
85 {
86 	glXMakeContextCurrent(display, drawable, read_drawable, context);
87 	assert(*this == get_current(display));
88 }
89 
90 gl::Context::ContextInfo
get_current(Display * default_display)91 gl::Context::ContextInfo::get_current(Display *default_display)
92 {
93 	ContextInfo ci;
94 	ci.display = glXGetCurrentDisplay();
95 	if (!ci.display) ci.display = default_display;
96 	ci.drawable = glXGetCurrentDrawable();
97 	ci.read_drawable = glXGetCurrentReadDrawable();
98 	ci.context = glXGetCurrentContext();
99 	return ci;
100 }
101 
Context()102 gl::Context::Context():
103 	display(NULL),
104 	config(None),
105 	pbuffer(None),
106 	context(NULL)
107 {
108 	// open display (we will use default display and screen 0)
109 	display = XOpenDisplay(NULL);
110 	context_info.display = display;
111 
112 	// choose config
113 	assert(display);
114 	if (display)
115 	{
116 		int config_attribs[] = {
117 			//GLX_DOUBLEBUFFER,      False,
118 			GLX_RED_SIZE,          8,
119 			GLX_GREEN_SIZE,        8,
120 			GLX_BLUE_SIZE,         8,
121 			GLX_ALPHA_SIZE,        8,
122 			//GLX_DEPTH_SIZE,        24,
123 			//GLX_STENCIL_SIZE,      8,
124 			//GLX_ACCUM_RED_SIZE,    8,
125 			//GLX_ACCUM_GREEN_SIZE,  8,
126 			//GLX_ACCUM_BLUE_SIZE,   8,
127 			//GLX_ACCUM_ALPHA_SIZE,  8,
128 			GLX_DRAWABLE_TYPE,     GLX_PBUFFER_BIT,
129 			None };
130 		int nelements = 0;
131 		GLXFBConfig *configs = glXChooseFBConfig(display, 0, config_attribs, &nelements);
132 		if (configs != NULL && nelements > 0)
133 			config = configs[0];
134 	}
135 
136 	// create pbuffer
137 	assert(config);
138 	if (config)
139 	{
140 		int pbuffer_attribs[] = {
141 			GLX_PBUFFER_WIDTH, 256,
142 			GLX_PBUFFER_HEIGHT, 256,
143 			None };
144 		pbuffer = glXCreatePbuffer(display, config, pbuffer_attribs);
145 		context_info.drawable = pbuffer;
146 		context_info.read_drawable = pbuffer;
147 	}
148 
149 	// create context
150 	assert(pbuffer);
151 	if (pbuffer)
152 	{
153 		int context_attribs[] = {
154 			GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
155 			GLX_CONTEXT_MINOR_VERSION_ARB, 3,
156 			None };
157 		GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddress((const GLubyte*)"glXCreateContextAttribsARB");
158 		context = glXCreateContextAttribsARB(display, config, NULL, True, context_attribs);
159 		context_info.context = context;
160 	}
161 
162 	assert(context);
163 	use();
164 	check();
165 	unuse();
166 }
167 
~Context()168 gl::Context::~Context()
169 {
170 	if (context)
171 		glXDestroyContext(display, context);
172 	context = NULL;
173 	context_info.context = NULL;
174 	if (pbuffer)
175 		glXDestroyPbuffer(display, pbuffer);
176 	pbuffer = None;
177 	context_info.drawable = None;
178 	context_info.read_drawable = None;
179 	config = None;
180 	if (display)
181 		XCloseDisplay(display);
182 	display = NULL;
183 	context_info.display = None;
184 }
185 
186 bool
is_current() const187 gl::Context::is_current() const
188 {
189 	return is_valid()
190 		&& context_info == ContextInfo::get_current(display);
191 }
192 
193 void
use()194 gl::Context::use()
195 {
196 	if (is_valid()) {
197 		rec_mutex.lock();
198 		context_stack.push_back(ContextInfo::get_current(display));
199 		if (context_info != context_stack.back())
200 			context_info.make_current();
201 		check("gl::Context::use");
202 	}
203 }
204 
205 void
unuse()206 gl::Context::unuse()
207 {
208 	assert(is_current());
209 	if (is_valid()) {
210 		assert(!context_stack.empty());
211 		check("gl::Context::unuse");
212 		if (context_stack.back() != context_info)
213 		{
214 			glFinish();
215 			context_stack.back().make_current();
216 		}
217 		context_stack.pop_back();
218 		rec_mutex.unlock();
219 	}
220 }
221 
222 void
check(const char * s)223 gl::Context::check(const char *s)
224 {
225 	if (GLenum error = glGetError())
226 		warning("%s GL error: 0x%x %s", s, error, get_enum_string(error));
227 }
228 
229 const char *
get_enum_string(GLenum x)230 gl::Context::get_enum_string(GLenum x)
231 {
232 	for(int i = 0; i < (int)sizeof(enum_strings)/(int)sizeof(enum_strings[0]); ++i)
233 		if (enum_strings[i].first == x)
234 			return enum_strings[i].second;
235 	return "";
236 }
237 
238 /* === E N T R Y P O I N T ================================================= */
239