1 2/* This is a good test for glXSwapBuffers on non-current windows, 3 * and the glXCopyContext function. Fixed several Mesa/DRI bugs with 4 * this program on 15 June 2002. 5 * 6 * Joe's comments follow: 7 * 8 * I have tried some different approaches for being able to 9 * draw to multiple windows using one context, or a copied 10 * context. Mesa/indirect rendering works to use one context 11 * for multiple windows, but crashes with glXCopyContext. 12 * DRI is badly broken, at least for ATI. 13 * 14 * I also noticed that glXMakeCurrent allows a window and context 15 * from different visuals to be attached (haven't tested recently). 16 * 17 * Joe Krahn <jkrahn@nc.rr.com> 18 */ 19 20#include <GL/glx.h> 21#include <GL/gl.h> 22#include <string.h> 23#include <stdio.h> 24#include <stdlib.h> 25#include <unistd.h> 26#include <math.h> 27 28#ifndef M_PI 29#define M_PI 3.14159 30#endif 31 32#define DEGTOR (M_PI/180.0) 33 34static int AttributeList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None }; 35 36int main(int argc, char **argv) 37{ 38 Window win1, win2; 39 XVisualInfo *vi; 40 XSetWindowAttributes swa; 41 Display *dpy; 42 GLXContext ctx1, ctx2; 43 float angle; 44 int test; 45 46 if (argc < 2) { 47 fprintf(stderr, "This program tests GLX context switching.\n"); 48 fprintf(stderr, "Usage: jkrahntest <n>\n"); 49 fprintf(stderr, "Where n is:\n"); 50 fprintf(stderr, "\t1) Use two contexts and swap only when the context is current (typical case).\n"); 51 fprintf(stderr, "\t2) Use two contexts and swap at the same time.\n"); 52 fprintf(stderr, "\t\t Used to crash Mesa & nVidia, and DRI artifacts. Seems OK now.\n"); 53 fprintf(stderr, "\t3) Use one context, but only swap when a context is current.\n"); 54 fprintf(stderr, "\t\t Serious artifacts for DRI at least with ATI.\n"); 55 fprintf(stderr, "\t4) Use one context, swap both windows at the same time, so the left\n"); 56 fprintf(stderr, "\t\t window has no context at swap time. Severe artifacts for DRI.\n"); 57 fprintf(stderr, "\t5) Use two contexts, copying one to the other when switching windows.\n"); 58 fprintf(stderr, "\t\t DRI gives an error, indirect rendering crashes server.\n"); 59 60 exit(1); 61 } 62 test = atoi(argv[1]); 63 64 /* get a connection */ 65 dpy = XOpenDisplay(NULL); 66 67 /* Get an appropriate visual */ 68 vi = glXChooseVisual(dpy, DefaultScreen(dpy), AttributeList); 69 if (vi == 0) { 70 fprintf(stderr, "No matching visuals found.\n"); 71 exit(-1); 72 } 73 74 /* Create two GLX contexts, with list sharing */ 75 ctx1 = glXCreateContext(dpy, vi, 0, True); 76 ctx2 = glXCreateContext(dpy, vi, ctx1, True); 77 78 /* create a colormap */ 79 swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), 80 vi->visual, AllocNone); 81 swa.border_pixel = 0; 82 83 /* Create two windows */ 84 win1 = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 85 10, 10, 200, 200, 86 0, vi->depth, InputOutput, vi->visual, 87 CWBorderPixel | CWColormap, &swa); 88 XStoreName(dpy, win1, "Test [L]"); 89 XMapWindow(dpy, win1); 90 XMoveWindow(dpy, win1, 10, 10); /* Initial requested x,y may not be honored */ 91 { 92 XSizeHints sizehints; 93 static const char *name = "window"; 94 sizehints.x = 10; 95 sizehints.y = 10; 96 sizehints.width = 200; 97 sizehints.height = 200; 98 sizehints.flags = USSize | USPosition; 99 XSetNormalHints(dpy, win1, &sizehints); 100 XSetStandardProperties(dpy, win1, name, name, 101 None, (char **)NULL, 0, &sizehints); 102 } 103 104 105 win2 = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 106 250, 10, 200, 200, 107 0, vi->depth, InputOutput, vi->visual, 108 CWBorderPixel | CWColormap, &swa); 109 XStoreName(dpy, win1, "Test [R]"); 110 XMapWindow(dpy, win2); 111 XMoveWindow(dpy, win2, 260, 10); 112 { 113 XSizeHints sizehints; 114 static const char *name = "window"; 115 sizehints.x = 10; 116 sizehints.y = 10; 117 sizehints.width = 200; 118 sizehints.height = 200; 119 sizehints.flags = USSize | USPosition; 120 XSetNormalHints(dpy, win2, &sizehints); 121 XSetStandardProperties(dpy, win2, name, name, 122 None, (char **)NULL, 0, &sizehints); 123 } 124 125 126 /* Now draw some spinning things */ 127 for (angle = 0; angle < 360*4; angle += 10.0) { 128 /* Connect the context to window 1 */ 129 glXMakeCurrent(dpy, win1, ctx1); 130 131 /* Clear and draw in window 1 */ 132 glDrawBuffer(GL_BACK); 133 glClearColor(1, 1, 0, 1); 134 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 135 glColor3f(1, 0, 0); 136 glBegin(GL_TRIANGLES); 137 glVertex2f(0, 0); 138 glVertex2f(cos(angle * DEGTOR), sin(angle * DEGTOR)); 139 glVertex2f(cos((angle + 20.0) * DEGTOR), 140 sin((angle + 20.0) * DEGTOR)); 141 glEnd(); 142 glFlush(); 143 144 if (test == 1 || test == 3 || test == 5) 145 glXSwapBuffers(dpy, win1); 146 147 if (test == 5) 148 glXCopyContext(dpy, ctx1, ctx2, GL_ALL_ATTRIB_BITS); 149 /* Connect the context to window 2 */ 150 if (test == 3 || test == 4) { 151 glXMakeCurrent(dpy, win2, ctx1); 152 } else { 153 glXMakeCurrent(dpy, win2, ctx2); 154 } 155 156 /* Clear and draw in window 2 */ 157 glDrawBuffer(GL_BACK); 158 glClearColor(0, 0, 1, 1); 159 glClear(GL_COLOR_BUFFER_BIT); 160 glColor3f(1, 1, 0); 161 glBegin(GL_TRIANGLES); 162 glVertex2f(0, 0); 163 glVertex2f(cos(angle * DEGTOR), sin(angle * DEGTOR)); 164 glVertex2f(cos((angle + 20.0) * DEGTOR), 165 sin((angle + 20.0) * DEGTOR)); 166 glEnd(); 167 glFlush(); 168 169 /* Swap buffers */ 170 if (test == 2 || test == 4) 171 glXSwapBuffers(dpy, win1); 172 glXSwapBuffers(dpy, win2); 173 174 /* wait a while */ 175 glXWaitX(); 176 usleep(20000); 177 } 178 179 return 0; 180} 181