Ticket #2649: util-opengl.cpp

File util-opengl.cpp, 16.0 KB (added by anonymous, 20 years ago)
Line 
1// N.B. Any locking should be handled by the parent.
2
3using namespace std;
4
5// MythTV General headers
6#include "mythcontext.h"
7
8// MythTV videout headers
9#include "util-opengl.h"
10#include "util-x11.h"
11
12#define LOC QString("OpenglCtx: ")
13#define LOC_ERR QString("OpenglCtx Error: ")
14
15#ifndef GL_TEXTURE_RECTANGLE_ARB
16#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
17#endif
18
19#ifndef GL_TEXTURE_RECTANGLE_EXT
20#define GL_TEXTURE_RECTANGLE_EXT 0x84F5
21#endif
22
23#ifndef GL_TEXTURE_RECTANGLE_NV
24#define GL_TEXTURE_RECTANGLE_NV 0x84F5
25#endif
26
27OpenglContext::OpenglContext() :
28 m_texture( GL_TEXTURE_2D ),
29 m_display(NULL), m_screen_num(0),
30 m_window(0), m_visual(NULL),
31 m_context(NULL), m_visible(true),
32 m_supported(SUPP_NONE), m_max_tex_size(0),
33 m_textures_enabled(FALSE)
34{
35}
36
37OpenglContext::~OpenglContext()
38{
39 if (m_context && m_window)
40 {
41 DeletePrograms();
42 DeleteTextures();
43 DeleteFrameBuffers();
44 }
45 if (m_context)
46 glXDestroyContext(m_display, m_context);
47 if (m_window)
48 XDestroyWindow(m_display, m_window);
49 if (m_visual)
50 XFree(m_visual);
51}
52
53bool OpenglContext::Create(Window window, int width, int height, bool visible)
54{
55 m_visible = visible;
56 m_display = MythXOpenDisplay();
57 if (!m_display)
58 {
59 VERBOSE(VB_PLAYBACK, LOC_ERR + "Failed to open display.");
60 return false;
61 }
62 m_screen_num = DefaultScreen(m_display);
63 if (!CheckGlx() ||
64 !GetVisual() ||
65 !CreateWindow(window, width, height) ||
66 !CreateContext())
67 return false;
68
69 VERBOSE(VB_PLAYBACK, LOC + QString("Created window%1 and context.")
70 .arg(m_visible ? "" : " (Offscreen)"));
71 return true;
72}
73
74void OpenglContext::Init(void)
75{
76 MakeCurrent(true);
77 m_extensions= reinterpret_cast<const char *>(glGetString( GL_EXTENSIONS ));
78 glGetIntegerv( GL_MAX_TEXTURE_SIZE, &m_max_tex_size );
79 MakeCurrent(false);
80 if (m_max_tex_size == 0)
81 m_max_tex_size = 512;
82 VERBOSE(VB_PLAYBACK, LOC +
83 QString("Maximum supported texture size: %1 x %2")
84 .arg(m_max_tex_size).arg(m_max_tex_size));
85 m_supported += EnableFrameBufs();
86 m_supported += EnableFragProgs();
87 m_supported += EnableTextureRects();
88}
89
90void OpenglContext::MakeCurrent(bool current)
91{
92 if (current)
93 {
94 bool yes = glXMakeCurrent( m_display, m_window, m_context );
95 if (!yes)
96 VERBOSE(VB_PLAYBACK, LOC + "Could not make context current.");
97 }
98 else
99 glXMakeCurrent( m_display, None, NULL );
100}
101
102void OpenglContext::SwapBuffers(void)
103{
104 if (!m_visible)
105 return;
106 MakeCurrent(true);
107 glXSwapBuffers(m_display, m_window);
108 MakeCurrent(false);
109}
110
111void OpenglContext::EnableTextures(void)
112{
113 if (m_textures_enabled)
114 return;
115 m_textures_enabled = true;
116 MakeCurrent(true);
117 glEnable( m_texture );
118 MakeCurrent(false);
119}
120
121int OpenglContext::EnableTextureRects(void)
122{
123 if (m_extensions.contains("GL_NV_texture_rectangle"))
124 {
125 VERBOSE(VB_PLAYBACK, LOC + "Using NV NPOT texture extension.");
126 m_texture = GL_TEXTURE_RECTANGLE_NV;
127 }
128 else if (m_extensions.contains("GL_ARB_texture_rectangle"))
129 {
130 VERBOSE(VB_PLAYBACK, LOC + "Using ARB NPOT texture extension.");
131 m_texture = GL_TEXTURE_RECTANGLE_ARB;
132 }
133 else if (m_extensions.contains("GL_EXT_texture_rectangle"))
134 {
135 VERBOSE(VB_PLAYBACK, LOC + "Using EXT NPOT texture extension.");
136 m_texture = GL_TEXTURE_RECTANGLE_EXT;
137 }
138 else
139 {
140 VERBOSE(VB_PLAYBACK, LOC + "NPOT textures not available.");
141 return 0;
142 }
143
144 return SUPP_RECT;
145}
146
147int OpenglContext::EnableFragProgs(void)
148{
149 if (!m_extensions.contains("GL_ARB_fragment_program"))
150 {
151 VERBOSE(VB_PLAYBACK, LOC + "GL_ARB_fragment_program unavailable.");
152 return 0;
153 }
154 m_glGenProgramsARB = (PFNGLGENPROGRAMSARBPROC)
155 glXGetProcAddress("glGenProgramsARB");
156 m_glBindProgramARB = (PFNGLBINDPROGRAMARBPROC)
157 glXGetProcAddress("glBindProgramARB");
158 m_glProgramStringARB = (PFNGLPROGRAMSTRINGARBPROC)
159 glXGetProcAddress("glProgramStringARB");
160 m_glProgramEnvParameter4fARB = (PFNGLPROGRAMENVPARAMETER4FARBPROC)
161 glXGetProcAddress("glProgramEnvParameter4fARB");
162 m_glDeleteProgramsARB = (PFNGLDELETEPROGRAMSARBPROC)
163 glXGetProcAddress("glDeleteProgramsARB");
164 m_glGetProgramivARB = (PFNGLGETPROGRAMIVARBPROC)
165 glXGetProcAddress("glGetProgramivARB");
166
167 if (!m_glGenProgramsARB ||
168 !m_glBindProgramARB ||
169 !m_glProgramStringARB ||
170 !m_glDeleteProgramsARB ||
171 !m_glGetProgramivARB ||
172 !m_glProgramEnvParameter4fARB)
173 {
174 VERBOSE(VB_PLAYBACK, LOC + "Couldn't get proc address");
175 return 0;
176 }
177 VERBOSE(VB_PLAYBACK, LOC + "Fragment programs supported.");
178 return SUPP_PROG;
179}
180
181int OpenglContext::EnableFrameBufs(void)
182{
183 if (!m_extensions.contains("GL_EXT_framebuffer_object"))
184 {
185 VERBOSE(VB_PLAYBACK, LOC + "GL_EXT_framebuffer_object unavailable.");
186 return 0;
187 }
188 m_glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)
189 glXGetProcAddress("glGenFramebuffersEXT");
190 m_glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)
191 glXGetProcAddress("glBindFramebufferEXT");
192 m_glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
193 glXGetProcAddress("glFramebufferTexture2DEXT");
194 m_glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
195 glXGetProcAddress("glCheckFramebufferStatusEXT");
196 m_glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
197 glXGetProcAddress("glDeleteFramebuffersEXT");
198
199 if (!m_glGenFramebuffersEXT ||
200 !m_glBindFramebufferEXT ||
201 !m_glFramebufferTexture2DEXT ||
202 !m_glDeleteFramebuffersEXT ||
203 !m_glCheckFramebufferStatusEXT)
204 {
205 VERBOSE(VB_PLAYBACK, LOC + "Couldn't get proc address");
206 return 0;
207 }
208 VERBOSE(VB_PLAYBACK, LOC + "Frame Buffer Objects supported.");
209 return SUPP_FBUF;
210}
211
212void OpenglContext::CreateTexture(GLuint *tex)
213{
214 MakeCurrent(true);
215 glGenTextures( 1, tex );
216 SetupTextureFilters(tex, GL_LINEAR);
217 textures.push_back(*tex);
218 MakeCurrent(false);
219}
220
221bool OpenglContext::SetupTexture(QSize size, GLuint *tex, int filt)
222{
223 scratchspace = new unsigned char[(size.width()
224 * size.height() * 4) + 4];
225 memset(scratchspace, 0 , size.width() * size.height() * 4);
226
227 GLint check;
228 MakeCurrent(true);
229
230 SetupTextureFilters(tex, filt);
231 glTexImage2D( m_texture, 0, GL_RGBA8,
232 size.width(), size.height(),
233 0, GL_RGB , GL_UNSIGNED_BYTE, scratchspace );
234 glGetTexLevelParameteriv(m_texture, 0, GL_TEXTURE_WIDTH, &check);
235 MakeCurrent(false);
236 delete scratchspace;
237 if (check !=size.width())
238 return false;
239 return true;
240}
241
242void OpenglContext::SetupTextureFilters(GLuint *tex, int filt)
243{
244 glBindTexture( m_texture, *tex );
245 glTexParameteri (m_texture, GL_TEXTURE_MIN_FILTER, filt);
246 glTexParameteri (m_texture, GL_TEXTURE_MAG_FILTER, filt);
247 glTexParameteri (m_texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
248 glTexParameteri (m_texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
249}
250
251void OpenglContext::DeleteTexture(GLuint *tex)
252{
253 MakeCurrent(true);
254 vector<GLuint>::iterator it;
255 for (it = textures.begin(); it !=textures.end(); it++)
256 {
257 if (*(it) == *tex)
258 {
259 glDeleteTextures( 1, tex);
260 textures.erase(it);
261 break;
262 }
263 }
264 MakeCurrent(false);
265}
266
267void OpenglContext::DeleteTextures(void)
268{
269 MakeCurrent(true);
270 vector<GLuint>::iterator it;
271 for (it = textures.begin(); it !=textures.end(); it++)
272 glDeleteTextures( 1, &(*(it)));
273 textures.clear();
274 MakeCurrent(false);
275}
276
277bool OpenglContext::CreateProgram(QString *program, GLuint *prog)
278{
279 bool success = true;
280 GLint error;
281 MakeCurrent(true);
282 m_glGenProgramsARB ( 1, prog );
283 m_glBindProgramARB ( GL_FRAGMENT_PROGRAM_ARB, *prog );
284 m_glProgramStringARB ( GL_FRAGMENT_PROGRAM_ARB,
285 GL_PROGRAM_FORMAT_ASCII_ARB,
286 program->length(), program->latin1() );
287
288 glGetIntegerv ( GL_PROGRAM_ERROR_POSITION_ARB, &error );
289 if (error != -1)
290 {
291 VERBOSE(VB_PLAYBACK, LOC_ERR +
292 QString("Fragment Program compile error: position %1:'%2'")
293 .arg(error).arg(program->mid(error)));
294 success = false;
295 }
296 m_glGetProgramivARB( GL_FRAGMENT_PROGRAM_ARB,
297 GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &error );
298 if (error != 1)
299 {
300 VERBOSE(VB_PLAYBACK, LOC_ERR +
301 QString("Fragment program exceeds hardware capabilities."));
302 success = false;
303 }
304
305 if (success)
306 programs.push_back(*prog);
307 else
308 m_glDeleteProgramsARB( 1, prog );
309 MakeCurrent(false);
310 return success;
311}
312
313void OpenglContext::DeleteProgram(GLuint *prog)
314{
315 MakeCurrent(true);
316 vector<GLuint>::iterator it;
317 for (it = programs.begin(); it !=programs.end(); it++)
318 {
319 if (*(it) == *prog)
320 {
321 m_glDeleteProgramsARB( 1, prog);
322 programs.erase(it);
323 break;
324 }
325 }
326 MakeCurrent(false);
327}
328
329
330void OpenglContext::DeletePrograms(void)
331{
332 MakeCurrent(true);
333 vector<GLuint>::iterator it;
334 for (it = programs.begin(); it !=programs.end(); it++)
335 m_glDeleteProgramsARB( 1, &(*(it)));
336 MakeCurrent(false);
337 programs.clear();
338}
339
340bool OpenglContext::CreateFrameBuffer(GLuint *buf, GLuint *tex,
341 int width, int height)
342{
343 SetupTextureFilters(tex, GL_LINEAR);
344 MakeCurrent(true);
345 glPushAttrib (GL_VIEWPORT_BIT);
346 glViewport( 0, 0, width, height);
347 m_glGenFramebuffersEXT( 1, buf );
348 m_glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, *buf );
349 glBindTexture( m_texture, *tex );
350 glTexImage2D( m_texture, 0, GL_RGBA8,
351 (GLint)width,
352 (GLint)height, 0,
353 GL_RGB, GL_UNSIGNED_BYTE, NULL);
354 m_glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT,
355 GL_COLOR_ATTACHMENT0_EXT, m_texture, *tex, 0 );
356 GLenum status;
357 status = m_glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
358 m_glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
359 glPopAttrib ();
360 bool success = false;
361 switch(status)
362 {
363 case GL_FRAMEBUFFER_COMPLETE_EXT:
364 VERBOSE(VB_PLAYBACK, LOC +
365 QString("Created frame buffer object (%1x%2).")
366 .arg(width).arg(height));
367 success = true;
368 break;
369 case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
370 VERBOSE(VB_PLAYBACK, LOC + "Frame buffer incomplete_ATTACHMENT");
371 break;
372 case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
373 VERBOSE(VB_PLAYBACK, LOC +
374 "Frame buffer incomplete_MISSING_ATTACHMENT");
375 break;
376 case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT_EXT:
377 VERBOSE(VB_PLAYBACK, LOC +
378 "Frame buffer incomplete_DUPLICATE_ATTACHMENT");
379 break;
380 case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
381 VERBOSE(VB_PLAYBACK, LOC +
382 "Frame buffer incomplete_DIMENSIONS_EXT");
383 break;
384 case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
385 VERBOSE(VB_PLAYBACK, LOC +
386 "Frame buffer incomplete_FORMATS_EXT");
387 break;
388 case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
389 VERBOSE(VB_PLAYBACK, LOC +
390 "Frame buffer incomplete_DRAW_BUFFER_EXT");
391 break;
392 case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
393 VERBOSE(VB_PLAYBACK, LOC +
394 "Frame buffer incomplete_READ_BUFFER_EXT");
395 break;
396 case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
397 VERBOSE(VB_PLAYBACK, LOC + "Frame buffer unsupported.");
398 break;
399 default:
400 VERBOSE(VB_PLAYBACK, LOC +
401 QString("Unknown frame buffer error %1.").arg(status));
402 }
403 if (success)
404 framebuffers.push_back(*buf);
405 else
406 m_glDeleteFramebuffersEXT( 1, buf );
407 MakeCurrent(false);
408 return success;
409}
410
411void OpenglContext::DeleteFrameBuffer(GLuint *buf)
412{
413 MakeCurrent(true);
414 vector<GLuint>::iterator it;
415 for (it = framebuffers.begin(); it !=framebuffers.end(); it++)
416 {
417 if (*(it) == *buf)
418 {
419 m_glDeleteFramebuffersEXT( 1, buf);
420 framebuffers.erase(it);
421 break;
422 }
423 }
424 MakeCurrent(false);
425}
426
427void OpenglContext::DeleteFrameBuffers(void)
428{
429 MakeCurrent(true);
430 vector<GLuint>::iterator it;
431 for (it = framebuffers.begin(); it !=framebuffers.end(); it++)
432 m_glDeleteFramebuffersEXT( 1, &(*(it)));
433 framebuffers.clear();
434 MakeCurrent(false);
435}
436
437bool OpenglContext::CheckGlx(void)
438{
439 int ndummy;
440 if (!glXQueryExtension(m_display, &ndummy, &ndummy))
441 {
442 VERBOSE(VB_PLAYBACK, LOC_ERR + "OpenGL extension not present.");
443 return false;
444 }
445 return true;
446}
447
448bool OpenglContext::GetVisual(void)
449{
450 int attribList[] = {GLX_RGBA, GLX_DEPTH_SIZE, 0, GLX_DOUBLEBUFFER, 1,
451 GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
452 GLX_BLUE_SIZE, 1, None};
453 m_visual = glXChooseVisual(m_display, m_screen_num, attribList);
454 if (m_visual == NULL)
455 {
456 // see if we can can get a visual WITH depth buffer
457 int withdepth[] = {GLX_RGBA,
458 GLX_DOUBLEBUFFER, 1, GLX_RED_SIZE, 1,
459 GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, None};
460 m_visual = glXChooseVisual(m_display, m_screen_num, withdepth);
461 if (m_visual == NULL)
462 {
463 VERBOSE(VB_PLAYBACK, LOC_ERR + "No appropriate visual found");
464 return false;
465 }
466 }
467 return true;
468}
469
470bool OpenglContext::CreateWindow( Window winid, int width, int height)
471{
472 XSetWindowAttributes swa;
473 swa.colormap = XCreateColormap(m_display,
474 RootWindow(m_display, m_visual->screen),
475 m_visual->visual, AllocNone);
476 if (swa.colormap == 0)
477 {
478 VERBOSE(VB_PLAYBACK, LOC_ERR + "Failed to create colormap");
479 return false;
480 }
481 m_window = XCreateWindow(m_display, winid, 0, 0,
482 m_visible ? width : 1, m_visible ? height : 1,
483 0, m_visual->depth,
484 InputOutput, m_visual->visual, CWColormap, &swa);
485 if (m_window == 0)
486 {
487 VERBOSE(VB_PLAYBACK, LOC_ERR + "Failed to create window");
488 return false;
489 }
490 if (m_visible)
491 XMapWindow(m_display, m_window);
492 return true;
493}
494
495bool OpenglContext::CreateContext(void)
496{
497 m_context = glXCreateContext(m_display, m_visual, None, GL_TRUE);
498 if (m_context == NULL)
499 {
500 VERBOSE(VB_PLAYBACK, LOC_ERR + "Failed to create Glx context");
501 return false;
502 }
503
504 if (!glXMakeCurrent(m_display, m_window, m_context))
505 {
506 VERBOSE(VB_PLAYBACK, LOC_ERR + "Failed to make Glx context current.");
507 return false;
508 }
509 glXMakeCurrent(m_display, None, NULL);
510 return true;
511}
512
513__GLXextFuncPtr OpenglContext::glXGetProcAddress(const char * const procName)
514{
515 __GLXextFuncPtr ret = glXGetProcAddressARB((const GLubyte *) procName);
516 if (!ret)
517 {
518 VERBOSE(VB_PLAYBACK,
519 QString("Error: glXGetProcAddressARB unable to find %1")
520 .arg(procName));
521 }
522 return ret;
523}