I'll try to clarify a few points below since I didn't do a good job the
first time, sorry for that.
On 11-04-04 07:10 PM, DRC wrote:
On 4/4/11 12:15 PM, Nathan Kidd wrote:
b) M7 copies a GLXPixmap to only part of a destination window. This
gives wrong results; you'll get black pixels from the freshly
initialized pbuffer overwriting areas of the window not included in the
copy, because current XCopyArea only knows how to push a full window.
The PutImage path is also used to fix this case.
I don't understand why. The glCopyPixels() command in XCopyArea()
should be copying only the range of pixels specified by src_x, src_y,
dst_x, dst_y, w, and h.
glXMakeCurrent creates a pbuffer the size of the destination window,
glCopyPixels only writes to part of that pbuffer, but the glFinish
pushes the whole pbuffer down to the window, including parts of the
pbuffer that weren't touched by the glCopyPixels. You end up with black
(uninitialized) pbuffer bits in the area of the window that shouldn't
have been touched by the XCopyArea.
When run with VGL the attached glxpixmappartial.c demonstrates.
c) M7 does MakeCurrent(0,0) before calling XCopyArea, also not supported
by the current XCopyArea hook. This is worked around by creating a new
temporary context if necessary.
This should really be implemented by using (possibly extending) the
tempctx class, IMO.
Yes, I looked at it briefly and IIRC it needs just a few modifications
to fit. In fact the PutImage path is roughly mirroring what fbx does.
However, I didn't try to integrate them because by the time I was ready
to polish the proof-of-concept I was sold on pushing the GLXPixmap to 2D
Xserver, the meaning of which I'll try to explain better below.
Since this is the middle of the X stream I can imagine that this change
exposes us to potential problems with multi-threaded apps wanting to
have a context current in a different thread. Of course there's always
this risk when interposing, but when tmpctx is used currently it is
directly from a GL call, not an X call.
d) M7 destroys the GLXPixmap before calling XCopyArea on the associated
> Pixmap; a questionable practice probably left over from the days when
> you could do 2D X drawing over a GLX drawable without problem. This is
> worked around by deferring GLXPixmap deletion till Pixmap deletion. (My
> NVIDIA driver + X.org gives a race when trying to do the XCopyArea, a
> race that M7 always seems to win when run on the console but my test app
> can occasionally loose, and VGL always seems to lose.)
You probably understand this better than me; do we risk "leaking" video
memory with this approach? If the app calls glXDestroyPixmap but never
calls XFreePixmap how will libGL know the pbuffer isn't needed any more?
Of course we could just say "Bad app, don't do that", but I can
imagine this case being common because the app really isn't that bad;
the Pixmap will be implicitly freed when you close the X connection (but
we can't hook that implicit free).
That's the context for the following patches. However, I'm mostly
posting them for discussion. I don't really like how ugly XCopyArea is
getting. I think it is better, cleaner, and at least as performant to
just push GLXPixmaps to the 2D X server. (In fact, I think it should
generally be faster, especially since PutImage will be slow for those
not using an X Proxy that compresses.) Also XCopyArea and XCopyPlane
will just work without intervention. As it is we don't support
XCopyPlane at all.
Comments and discussion most welcome. If there are no issues I've
missed, I plan to start down the push-glxpixmap-to-2d-xserver path soon.
Regardless of how ugly XCopyArea() may or may not be, I don't know of
another way to implement it and still support X servers that lack GLX.
Sorry, by "push GLXPixmaps to the 2D X server" I mean push the rendered
pixels, just like we do for a GLX Window. In other words _doGLreadback
won't just check winh.findpb(drawable, pbw) but also check if the
current drawable is a GLXPixmap. This requires a few modifications to
pbwin and to fbx which currently only know how to push a window to the
desktop, but I believe the code change will be smaller and introduce
less risk than the current bunch of patches.
My real question is what was the rationale behind the decision to not
push GLXPixmaps to the 2D X server? Is there more than the idea "hey,
they can only be seen by XCopyArea/XCopyPlane, if we hook those
functions we don't need to bother doing readback on them?".
What I mean about "it should be generally faster" is if GLXPixmap pixels
get pushed via the pbwin readback path then the pixels will be pushed
efficiently for every transport type. A direct PutImage is only
efficient for X Proxies that compress PutImage anyway (e.g. VGL
transport will be slower with PutImage).
I'm not thinking about push-glxpixmap-pixels-to-2d-xserver from a "fix
the general case for all apps" standpoint (I *did* read your earlier
mails :) but rather from a "fix this specific app with least risk to
other apps" perspective.
And yes, as you said, in this day and age apps have no business using
GLXPixmaps for rendering; yet here we are in 2011 and the latest version
of a popular app is doing just that. *shrug*
I realize that your company doesn't care about TurboVNC, but that's
still the most popular X server on which VirtualGL runs, so I cannot
accept any solution that removes functionality from that environment.
I certainly hope OpenText never looses sight of the fact that is it not
just politic but also the right thing to work for what's good for everyone.
As far as rrfakerut, it is what it is. I don't think it's fair to call
it "half baked". It does require a bit of expertise to use, but it is
the only way I currently have to try to guarantee that a new patch
doesn't break something else.
Sorry, I meant *my changes* to rrfakerut were half-baked. Mathematica 7
is available as an eval if you ask, but tied to a specific machine.
I'll try to finish up unit tests for each of these issues.
-Nathan
/*
* A demonstration of what happens when you XCopyArea to less than the
* full destination window.
*
* [email protected] April 2011
*/
#include <GL/gl.h>
#define GLX_GLXEXT_PROTOTYPES
#include <GL/glx.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static GLXContext ctx;
static XVisualInfo *visinfo;
static GC gc;
static Window make_rgb_window( Display *dpy,
unsigned int width, unsigned int height )
{
const int sbAttrib[] = { GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
None };
const int dbAttrib[] = { GLX_RGBA,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DOUBLEBUFFER,
None };
int scrnum;
XSetWindowAttributes attr;
unsigned long mask;
Window root;
Window win;
scrnum = DefaultScreen( dpy );
root = RootWindow( dpy, scrnum );
visinfo = glXChooseVisual( dpy, scrnum, (int *) sbAttrib );
if (!visinfo) {
visinfo = glXChooseVisual( dpy, scrnum, (int *) dbAttrib );
if (!visinfo) {
printf("Error: couldn't get an RGB visual\n");
exit(1);
}
}
/* window attributes */
attr.background_pixel = WhitePixel(dpy,scrnum);
attr.border_pixel = WhitePixel(dpy,scrnum);
/* TODO: share root colormap if possible */
attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
attr.event_mask = StructureNotifyMask | ExposureMask;
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
win = XCreateWindow( dpy, root, 0, 0, width, height,
0, visinfo->depth, InputOutput,
visinfo->visual, mask, &attr );
/* make an X GC so we can do XCopyArea later */
gc = XCreateGC( dpy, win, 0, NULL );
/* need indirect context */
ctx = glXCreateContext( dpy, visinfo, NULL, False );
if (!ctx) {
printf("Error: glXCreateContext failed\n");
exit(-1);
}
printf("Direct rendering: %s\n", glXIsDirect(dpy, ctx) ? "Yes" : "No");
return win;
}
static GLXPixmap make_pixmap( Display *dpy, Window win,
unsigned int width, unsigned int height,
Pixmap *pixmap)
{
Pixmap pm, pm2;
GLXPixmap glxpm;
XWindowAttributes attr;
pm = XCreatePixmap( dpy, win, width, height, visinfo->depth );
pm2 = XCreatePixmap( dpy, win, width, height, visinfo->depth );
if (!pm | !pm2) {
printf("Error: XCreatePixmap failed\n");
exit(-1);
}
XGetWindowAttributes( dpy, win, &attr );
/*
* IMPORTANT:
* Use the glXCreateGLXPixmapMESA funtion when using Mesa because
* Mesa needs to know the colormap associated with a pixmap in order
* to render correctly. This is because Mesa allows RGB rendering
* into any kind of visual, not just TrueColor or DirectColor.
*/
#ifdef GLX_MESA_pixmap_colormap
if (strstr(glXQueryExtensionsString(dpy, 0), "GLX_MESA_pixmap_colormap")) {
/* stand-alone Mesa, specify the colormap */
PFNGLXCREATEGLXPIXMAPMESAPROC glXCreateGLXPixmapMESA_func =
(PFNGLXCREATEGLXPIXMAPMESAPROC)
glXGetProcAddressARB((GLubyte *) "glXCreateGLXPixmapMESA");
glxpm = glXCreateGLXPixmapMESA_func( dpy, visinfo, pm, attr.colormap );
}
else {
glxpm = glXCreateGLXPixmap( dpy, visinfo, pm );
}
#else
/* This will work with Mesa too if the visual is TrueColor or DirectColor */
glxpm = glXCreateGLXPixmap( dpy, visinfo, pm );
#endif
if (!glxpm) {
printf("Error: GLXCreateGLXPixmap failed\n");
exit(-1);
}
pixmap[0] = pm;
pixmap[1] = pm2;
return glxpm;
}
int main( int argc, char *argv[] )
{
Display *dpy;
Window win;
Pixmap pm[2];
GLXPixmap glxpm;
XTextProperty windowname;
char *windowtext = "Dest Window";
XStringListToTextProperty(&windowtext, 1, &windowname);
dpy = XOpenDisplay(NULL);
win = make_rgb_window( dpy, 300, 300 );
glxpm = make_pixmap( dpy, win, 300, 300, &pm );
XSync(dpy, False);
XMapWindow( dpy, win );
XSetWMName(dpy, win, &windowname);
glXMakeCurrent( dpy, glxpm, ctx );
printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
/* Render an image into the pixmap */
glShadeModel( GL_FLAT );
glClearColor( 0.5, 0.5, 0.5, 1.0 );
glClear( GL_COLOR_BUFFER_BIT );
glViewport( 0, 0, 300, 300 );
glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
glColor3f( 0.0, 1.0, 1.0 );
glRectf( -0.75, -0.75, 0.75, 0.75 );
glFlush();
glXWaitGL();
XSync(dpy, False);
printf("we see plain white window\n");
sleep(5);
XCopyArea( dpy, pm[0], win, gc, 0, 0, 200, 200, 50, 50 );
printf("parts that shouldn't be affected are now black\n");
XSync(dpy, False);
printf("done\n");
fflush(stdout);
while (1) { sleep(1);}
return 0;
}
------------------------------------------------------------------------------
Xperia(TM) PLAY
It's a major breakthrough. An authentic gaming
smartphone on the nation's most reliable network.
And it wants your games.
http://p.sf.net/sfu/verizon-sfdev
_______________________________________________
VirtualGL-Users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/virtualgl-users