Ivan Vučica avatar Ivan Vučica committed e59a0ea

Work on getting GL_ARB_texture_from_pixmap to work. Created a simple effect on each window, to demonstrate animation.

Comments (0)

Files changed (6)

FPManagedWindow.h

 
 	BOOL _isMapped;
 
+	float _timeAlive;
+
 	FPWindowManager * _manager; // non-owning reference
 }
 -(id)initWithWindow:(Window)window manager:(FPWindowManager*)manager;

FPManagedWindow.m

 #import "FPEventLoop.h"
 #import "FPWindowManager.h"
 
+#define SAFE_MODE 1
+
+#define USE_GLX1_3 1
+
+#define SWITCH_CONTEXTS 1
+
+#if !SAFE_MODE
+	#define HAVE_GL_COPY_TEX_IMAGE_2D 1
+	#define FORCE_TEXTURE_2D 1
+	#define USE_GLXBINDTEXIMAGE 1
+#else
+	#define HAVE_GL_COPY_TEX_IMAGE_2D 0
+	#define FORCE_TEXTURE_2D 1
+	#define USE_GLXBINDTEXIMAGE 0
+	#undef USE_GLX1_3
+	#define USE_GLX1_3 0
+#endif
 static int DamageNotify = -1;
 static PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT = 0;
+static PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT = 0;
 @implementation FPManagedWindow
 
 -(id)initWithWindow:(Window)window manager:(FPWindowManager*)manager
 	
 	[[FPEventLoop mainLoop] addEventHandler:self];
 
-	// TODO: check if it's better to use what glcompmgr uses: glXCreatePixmap() which uses FBConfig instead of visual info
+#if USE_GLXBINDTEXIMAGE
+	if(glXBindTexImageEXT == 0)
+	{
+		// TODO: initialize once, globally
+		glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte*)"glXBindTexImageEXT");
+		glXReleaseTexImageEXT = (PFNGLXRELEASETEXIMAGEEXTPROC)glXGetProcAddress((GLubyte*)"glXReleaseTexImageEXT");
+	}
+#endif
 
 	[self _collectAttributes];
 	if(!_hasOutput)
 	FPX11Display * mainDisplay = [FPX11Display mainDisplay];
 	Display * display = [mainDisplay display];
 
-	[self _freeResources];	
+	[self _freeResources];
 	
 	[[FPEventLoop mainLoop] removeEventHandler:self];
 	[super dealloc];
 {
 	FPX11Display * mainDisplay = [FPX11Display mainDisplay];
 	Display * display = [mainDisplay display];
+	
+	const int pixmap_attribs[] = {
+		GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+		GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT,
+		None
+	};            
+	
 	_pixmap = XCompositeNameWindowPixmap (display, _window);
 	if(!_pixmap)
 		NSLog(@"Failed to make a pixmap");
+#if !USE_GLX1_3
 	_drawable = glXCreateGLXPixmap (display, [_manager visualInfo], _pixmap);
+#else
+	_drawable = glXCreatePixmap (display, [_manager glxFBConfigs][0], _pixmap, pixmap_attribs);
+#endif
 	if(!_drawable)
 		NSLog(@"Failed to make a drawable");
 	_damage = XDamageCreate (display, _window, XDamageReportDeltaRectangles);
+	if(!_texture)
+		glGenTextures (1, &_texture);
+
+	if(glXBindTexImageEXT)
+		glXBindTexImageEXT(display, _drawable, GLX_FRONT_EXT, NULL);
 }
 -(void)_freeResources
 {
 	FPX11Display * mainDisplay = [FPX11Display mainDisplay];
 	Display * display = [mainDisplay display];
+
+	if(glXReleaseTexImageEXT)
+		glXReleaseTexImageEXT(display, _drawable, GLX_FRONT_EXT);
+
 	/*
 	if(_damage)
 		XDamageDestroy(display, _damage);
 	if(_pixmap)
 		XFreePixmap(display, _pixmap);
 	if(_drawable)
+#if USE_GLX1_3
 		glXDestroyGLXPixmap(display, _drawable);
+#else
+		glXDestroyPixmap(display, _drawable);
+#endif
 	if(_texture)
 		glDeleteTextures(1, &_texture);
 }
 		if(event.xexpose.window == _window)
 		{
 			NSLog(@"Managed Window %ld is exposed", _window);
-			if(glXBindTexImageEXT == 0)
-			{
-				// TODO: initialize once, globally
-				glXBindTexImageEXT = (PFNGLXBINDTEXIMAGEEXTPROC)glXGetProcAddress((GLubyte*)"glXBindTexImageEXT");
-			}
+			
 		}
 		break;
 
 /*
 	GSList* list;
 */
+	if(!_isMapped)
+	{
+		NSLog(@"Skipping unmapped window");
+		return;
+	}
 	if(!_drawable)
 	{
 		NSLog(@"Cannot paint window %ld, no drawable", _window);
 		return;
 	}
+
+
+#if !SWITCH_CONTEXTS
+	glXMakeContextCurrent (display, [_manager stage], [_manager stage], [_manager glxContext]);
+#endif
+
 	[self bindTexture];
-
-	NSLog(@"Restoring to actually paint window %ld", _window);
+#if SWITCH_CONTEXTS
 	glXMakeContextCurrent (display, [_manager stage], [_manager stage], [_manager glxContext]);
+#endif
 	glDrawBuffer (GL_BACK);
 
+	glEnable(_textureTarget);
+	//glColor3f((rand() % 100) / 100., (rand() % 100) / 100., (rand() % 100) / 100.);
+	//glColor4f(1,1,1,1);
+	glColor4f(1,1,0.5+sin(_timeAlive*2)/2,1);
+	NSLog(@"%g %g", _timeAlive, 0.5+sin(_timeAlive/5)/2);
+	glBindTexture(_textureTarget, _texture);
+	
 	glMatrixMode(GL_MODELVIEW);
-	glEnable (GL_TEXTURE);
-	glEnable(_textureTarget);
-//	glColor3f((rand() % 100) / 100., (rand() % 100) / 100., (rand() % 100) / 100.);
-	glBindTexture(_textureTarget, _texture);
 	glPushMatrix ();
 		glTranslatef (_x, _y, _z);
 		/*
 		glLineWidth(1);
 
 	glPopMatrix ();
+	
 	glDisable(_textureTarget);
-//	glDisable (GL_TEXTURE_RECTANGLE_ARB);
-  	glDisable (GL_TEXTURE);
-//	glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
+	[self unbindTexture];
 
 	glXWaitGL();
-
+#if SWITCH_CONTEXTS
+	glXMakeContextCurrent (display, [_manager stage], [_manager stage], [_manager glxContext]);
+#endif
 }
+static int grabCount = 0;
 -(void)bindTexture
 {
 	FPX11Display * mainDisplay = [FPX11Display mainDisplay];
 		
 	glXWaitX();
 	XSync(display, None);
-	XGrabServer (display);
-	NSLog(@"Binding for window %ld", _window);
+	grabCount++;
+	NSLog(@"Grabbing server %d", grabCount);
+	//XGrabServer (display);
+
+#if SWITCH_CONTEXTS
+	NSLog(@"Context switch");
 	glXMakeContextCurrent (display, _window, _window, [_manager glxContext]);
+#endif
 
-	glReadBuffer (GL_FRONT);
-	glDrawBuffer (GL_FRONT);
+
 /*
 	if (!_hasAlpha && _opacity < 1.0) {
 		glColorMask (0, 0, 0, 1);
 		glColorMask (1, 1, 1, 1);
 	}
 */
-	glXWaitX();
-	glXWaitGL();
-	
 
-	_textureTarget = GLX_TEXTURE_2D_EXT; //glXQueryDrawable(display, _drawable, GLX_TEXTURE_TARGET_EXT, &_textureTarget);
+#if FORCE_TEXTURE_2D
+	_textureTarget = GLX_TEXTURE_2D_EXT; 
+#else
+	glXQueryDrawable(display, _drawable, GLX_TEXTURE_TARGET_EXT, &_textureTarget);
+#endif
 	switch(_textureTarget)
 	{
 		case GLX_TEXTURE_2D_EXT:
 		_textureTarget = GL_TEXTURE_2D;
 		break;
 		case GLX_TEXTURE_RECTANGLE_EXT:
-		_textureTarget = GL_TEXTURE_RECTANGLE_ARB;
+		_textureTarget = GL_TEXTURE_RECTANGLE;
 		break;
 		default:
 		NSLog(@"Unknown texture target");
 	}
-	glEnable(GL_TEXTURE);
-	glEnable(_textureTarget);
-	if(!_texture)
-		glGenTextures (1, &_texture);
 
 	if(glXBindTexImageEXT)
-		glXBindTexImageEXT(display, _drawable, GLX_FRONT_LEFT_EXT, NULL);
+	{
+#if SWITCH_CONTEXTS
+NSLog(@"Switching context");
+		glXMakeContextCurrent (display, [_manager stage], [_manager stage], [_manager glxContext]);
+#endif
+NSLog(@"Beginning bind");
+		glEnable(_textureTarget);
+		glBindTexture(_textureTarget, _texture);
+NSLog(@"Bound texture, now binding drawable %d", _drawable);
+		glXBindTexImageEXT(display, _drawable, GLX_FRONT_EXT, NULL);
+NSLog(@"Bound drawable");
+	}
 	else
 	{
+		glEnable(_textureTarget);
 		glBindTexture(_textureTarget, _texture);
 
+		glReadBuffer (GL_FRONT);
+		glDrawBuffer (GL_FRONT);
+
 #if HAVE_GL_COPY_TEX_IMAGE_2D
 		// FIXME: we don't actually get any image for some reason
 		// NOTE: using the damage extension we could just glCopyTexSubImage2D()
 #else
 		// FIXME: abysmally slow, and blurry, too
 		GLubyte * img = (GLubyte*)malloc(_width * _height * 4);
-		glReadPixels(0, 0, _width, _height, GL_RGBA, GL_UNSIGNED_BYTE, img);
-		
-		glXWaitX();
-		glXWaitGL();
+		glReadPixels(0, 0, _width, _height, GL_RGBA, GL_UNSIGNED_BYTE, img);	
 		gluBuild2DMipmaps(_textureTarget, GL_RGBA, _width, _height, GL_RGBA, GL_UNSIGNED_BYTE, img);
-		glXWaitGL();
-		glXWaitX();
 		free(img);
 #endif
 	}
 	
-	glDisable(GL_TEXTURE);
+NSLog(@"Bound");
+}
+
+-(void)unbindTexture
+{
+	FPX11Display * mainDisplay = [FPX11Display mainDisplay];
+	Display * display = [mainDisplay display];
+
+	if(!_drawable)
+		return;
+	if(glXReleaseTexImageEXT)
+	{
+		NSLog(@"Releasing tex image");
+#if SWITCH_CONTEXTS
+		glXMakeContextCurrent (display, [_manager stage], [_manager stage], [_manager glxContext]);
+#endif
+		glXReleaseTexImageEXT(display, _drawable, GLX_FRONT_EXT);
+	}
+
+	glBindTexture (_textureTarget, 0);
+#if SWITCH_CONTEXTS
+	glXMakeContextCurrent (display, _window, _window, [_manager glxContext]);
+#endif
 	glDisable(_textureTarget);
-	
-	XUngrabServer (display);
+
+	NSLog(@"Ungrabbing server %d", grabCount);
+	grabCount--;
+	glXWaitX();
+	NSLog(@"Waited gl");
+	XSync(display, None);
+	NSLog(@"Ungrabing");
+	//XUngrabServer (display);
+	NSLog(@"Wiating x");
+	glXWaitX();
+	NSLog(@"Syncing x");
+	XSync(display, None);
+	NSLog(@"Done ungrab");
 
 }
 -(void)updateWithDeltaTime:(float)sec;
 {
+	_timeAlive += sec;
+	NSLog(@"Update %g", sec);
 }
 @end

FPWindowManager.h

 	BOOL _isVisualDoubleBuffered;
 	GLXContext _glxContext;
 	XVisualInfo * _visualInfo; // for glx
+	GLXFBConfig * _glxFBConfigs;
 
 	Window _overlay;
 	
 }
 -(void)stopManagingWindow:(FPManagedWindow*)window;
 -(XVisualInfo*)visualInfo;
+-(GLXFBConfig*)glxFBConfigs;
 -(GLXContext)glxContext;
 -(Window)stage;
 @end

FPWindowManager.m

 #import "FPX11Display.h"
 #import "FPManagedWindow.h"
 
+#define VBOXCOMPAT 1 // virtualbox compatibility
+
 static int attrListSgl[] = {
     GLX_RGBA, GLX_RED_SIZE, 4,
     GLX_GREEN_SIZE, 4,
     GLX_DEPTH_SIZE, 16,
     None };
 
+static const int fbconfig[] = {
+    GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
+#if !VBOXCOMPAT
+    GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
+#endif
+    GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
+    GLX_Y_INVERTED_EXT, GLX_DONT_CARE,
+    None
+};
+
 @implementation FPWindowManager
 -(id)init
 {
 	FPX11Display * mainDisplay = [FPX11Display mainDisplay];	
 	Display * display = [mainDisplay display];
 
+	XFree(_glxFBConfigs);
+	glXMakeCurrent(display, None, NULL);
 	glXDestroyContext(display, _glxContext);
 	XDestroyWindow(display, _stage);
 	XCompositeReleaseOverlayWindow(display, _overlay);
 	[_managedWindows release];
 
-	glXMakeCurrent([[FPX11Display mainDisplay] display], None, NULL);
-	glXDestroyContext([[FPX11Display mainDisplay] display], _glxContext);
-
 	[[FPEventLoop mainLoop] removeEventHandler:self];
 	[super dealloc];
 }
 		StructureNotifyMask | FocusChangeMask | PointerMotionMask
                   | KeyPressMask | KeyReleaseMask | ButtonPressMask
                   | ButtonReleaseMask | PropertyChangeMask | ExposureMask;
+	attr.override_redirect = true;
 
 	_glxContext = glXCreateContext(display, glxVisualInfo, 0, GL_TRUE);
 
 
 	glXMakeCurrent(display, _stage, _glxContext);
 	
+	///////////
+		
+	int c = 0;
+	_glxFBConfigs = glXChooseFBConfig(display, screen, fbconfig, &c);
+	if(!_glxFBConfigs)
+	{
+		// TODO: throw exception or return nil instead of exiting
+		NSLog(@"No FBConfigs");
+		exit(1);
+	}
+	
+	///////////
+	
 	XGetGeometry(
 		display, 
 		_stage, 
 	glXMakeContextCurrent ([[FPX11Display mainDisplay] display], _stage, _stage, _glxContext);
 	XSync([[FPX11Display mainDisplay] display], False);
 	glViewport(0, 0, _width, _height);
-	glClearColor(0.2,0.2,0.2,1);
+	glClearColor(0.2,0.2,0.4,1);
 	glClear(GL_COLOR_BUFFER_BIT);
 
 	glMatrixMode(GL_PROJECTION);
 	glLoadIdentity();
 	glOrtho(0, _width, _height, 0, 0, 1);
-	NSLog(@"Ortho %d x %d", _width, _height);
 	glMatrixMode(GL_MODELVIEW);
 	glLoadIdentity();
 
 		[managedWindow drawWindow];		
 	}
 
+#if 0
+	glLoadIdentity();
+	glDisable(GL_TEXTURE_2D);
+	glPointSize(10);
+	glColor3f(1,0,0);
+	glBegin(GL_POINTS);
+	glVertex3f(rand()%640, rand()%480, 0);	
+	glEnd();
+#endif	
+
 	if(_isVisualDoubleBuffered)
 	{
 		glXSwapBuffers([[FPX11Display mainDisplay] display], _stage);
 {
 	return _visualInfo;
 }
+-(GLXFBConfig*)glxFBConfigs
+{
+	return _glxFBConfigs;
+}
 -(GLXContext)glxContext
 {
 	return _glxContext;
 	NSAutoreleasePool * pool = [NSAutoreleasePool new];
 	FPWindowManager * t = [FPWindowManager new];
 	[[FPEventLoop mainLoop] run];
+	[[FPEventLoop mainLoop] release];
 	[pool release];
 	return 0;
 }
 
 make
-LIBGL_ALWAYS_INDIRECT=1 ./run-xephyr /usr/GNUstep/System/Tools/openapp ./Fireplace.app
+#LIBGL_ALWAYS_INDIRECT=1 ./run-xephyr /usr/GNUstep/System/Tools/openapp ./Fireplace.app
+./run-xephyr /usr/GNUstep/System/Tools/openapp ./Fireplace.app
+
 #./run-xephyr &
 #DISPLAY=:3 /usr/bin/gdb ./Fireplace.app/Fireplace
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.