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