1/*
2 * Test sharing of texture objects by two rendering contexts.
3 * In particular, test that changing a texture object in one context
4 * effects the texture in the second context.
5 *
6 * Brian Paul
7 * 30 Apr 2008
8 *
9 * Copyright (C) 2008  Brian Paul   All Rights Reserved.
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
25 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29
30#include <GL/gl.h>
31#include <GL/glx.h>
32#include <assert.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <unistd.h>
37#include <X11/keysym.h>
38
39
40#define MAX_CONTEXTS 2
41
42#define TEX_SIZE 32
43
44static const char *DisplayName = NULL;
45static Display *Dpy;
46static XVisualInfo *VisInfo;
47static Window Win;
48static GLXContext Contexts[MAX_CONTEXTS];
49static int WinWidth = 300, WinHeight = 300;
50
51static int DrawContext = 0, TexContext = 1;
52
53static GLuint TexObj = 0;
54static GLboolean NewTexture = GL_FALSE;
55
56
57static void
58Error(const char *msg)
59{
60   fprintf(stderr, "sharedtex error: %s\n", msg);
61   exit(1);
62}
63
64
65static void
66CreateWindow(const char *name)
67{
68   int attrib[] = { GLX_RGBA,
69		    GLX_RED_SIZE, 1,
70		    GLX_GREEN_SIZE, 1,
71		    GLX_BLUE_SIZE, 1,
72		    GLX_DOUBLEBUFFER,
73		    None };
74   int scrnum;
75   XSetWindowAttributes attr;
76   unsigned long mask;
77   Window root;
78   int xpos = 0, ypos = 0;
79   static int n = 0;
80
81   scrnum = DefaultScreen(Dpy);
82   root = RootWindow(Dpy, scrnum);
83
84   VisInfo = glXChooseVisual(Dpy, scrnum, attrib);
85   if (!VisInfo) {
86      Error("Unable to find RGB, double-buffered visual");
87   }
88
89   /* window attributes */
90   xpos = (n % 10) * 100;
91   ypos = (n / 10) * 100;
92   n++;
93
94   attr.background_pixel = 0;
95   attr.border_pixel = 0;
96   attr.colormap = XCreateColormap(Dpy, root, VisInfo->visual, AllocNone);
97   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
98   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
99
100   Win = XCreateWindow(Dpy, root, xpos, ypos, WinWidth, WinHeight,
101		        0, VisInfo->depth, InputOutput,
102		        VisInfo->visual, mask, &attr);
103   if (!Win) {
104      Error("Couldn't create window");
105   }
106
107   {
108      XSizeHints sizehints;
109      sizehints.x = xpos;
110      sizehints.y = ypos;
111      sizehints.width  = WinWidth;
112      sizehints.height = WinHeight;
113      sizehints.flags = USSize | USPosition;
114      XSetNormalHints(Dpy, Win, &sizehints);
115      XSetStandardProperties(Dpy, Win, name, name,
116                              None, (char **)NULL, 0, &sizehints);
117   }
118
119   XMapWindow(Dpy, Win);
120}
121
122
123/**
124 * Change texture image, using TexContext
125 */
126static void
127ModifyTexture(void)
128{
129   GLuint tex[TEX_SIZE][TEX_SIZE];
130   GLuint c0, c1;
131   int i, j;
132
133   if (Win && !glXMakeCurrent(Dpy, Win, Contexts[TexContext])) {
134      Error("glXMakeCurrent failed");
135   }
136
137   /* choose two random colors */
138   c0 = rand() & 0xffffffff;
139   c1 = rand() & 0xffffffff;
140
141   for (i = 0; i < TEX_SIZE; i++) {
142      for (j = 0; j < TEX_SIZE; j++) {
143         if (((i / 4) ^ (j / 4)) & 1) {
144            tex[i][j] = c0;
145         }
146         else {
147            tex[i][j] = c1;
148         }
149      }
150   }
151
152   glBindTexture(GL_TEXTURE_2D, TexObj);
153   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0,
154                GL_RGBA, GL_UNSIGNED_BYTE, tex);
155
156   NewTexture = GL_TRUE;
157}
158
159
160static void
161InitContext(void)
162{
163   glGenTextures(1, &TexObj);
164   assert(TexObj);
165   glBindTexture(GL_TEXTURE_2D, TexObj);
166   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
167   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
168   glEnable(GL_TEXTURE_2D);
169
170   printf("GL_RENDERER = %s\n", (char*) glGetString(GL_RENDERER));
171}
172
173
174static void
175Setup(void)
176{
177   int i;
178
179   Dpy = XOpenDisplay(DisplayName);
180   if (!Dpy) {
181      Error("Unable to open display");
182   }
183
184   CreateWindow("sharedtex");
185
186   for (i = 0; i < MAX_CONTEXTS; i++) {
187      GLXContext share = i > 0 ? Contexts[0] : 0;
188
189      Contexts[i] = glXCreateContext(Dpy, VisInfo, share, True);
190      if (!Contexts[i]) {
191         Error("Unable to create GLX context");
192      }
193
194      if (!glXMakeCurrent(Dpy, Win, Contexts[i])) {
195         Error("glXMakeCurrent failed");
196      }
197
198      InitContext();
199   }
200
201   ModifyTexture();
202}
203
204
205/**
206 * Redraw window, using DrawContext
207 */
208static void
209Redraw(void)
210{
211   static float rot = 0.0;
212   float ar;
213
214   rot += 1.0;
215
216   if (Win && !glXMakeCurrent(Dpy, Win, Contexts[DrawContext])) {
217      Error("glXMakeCurrent failed");
218   }
219
220   glViewport(0, 0, WinWidth, WinHeight);
221   ar = (float) WinWidth / (float) WinHeight;
222   glMatrixMode(GL_PROJECTION);
223   glLoadIdentity();
224   glOrtho(-ar, ar, -1.0, 1.0, -1.0, 1.0);
225   glMatrixMode(GL_MODELVIEW);
226
227   glShadeModel(GL_FLAT);
228   glClearColor(0.5, 0.5, 0.5, 1.0);
229   glClear(GL_COLOR_BUFFER_BIT);
230
231   glPushMatrix();
232   glRotatef(rot, 0, 0, 1);
233   glScalef(0.7, 0.7, 0.7);
234
235   if (NewTexture) {
236      /* rebind to get new contents */
237      glBindTexture(GL_TEXTURE_2D, TexObj);
238      NewTexture = GL_FALSE;
239   }
240
241   /* draw textured quad */
242   glBegin(GL_POLYGON);
243   glTexCoord2f( 0.0, 0.0 );   glVertex2f( -1.0, -1.0 );
244   glTexCoord2f( 1.0, 0.0 );   glVertex2f(  1.0, -1.0 );
245   glTexCoord2f( 1.0, 1.0 );   glVertex2f(  1.0,  1.0 );
246   glTexCoord2f( 0.0, 1.0 );   glVertex2f( -1.0,  1.0 );
247   glEnd();
248
249   glPopMatrix();
250
251   if (Win)
252      glXSwapBuffers(Dpy, Win);
253}
254
255
256static void
257EventLoop(void)
258{
259   while (1) {
260      while (XPending(Dpy) > 0) {
261         XEvent event;
262         XNextEvent(Dpy, &event);
263
264         switch (event.type) {
265         case Expose:
266            Redraw();
267            break;
268         case ConfigureNotify:
269            WinWidth = event.xconfigure.width;
270            WinHeight = event.xconfigure.height;
271            break;
272         case KeyPress:
273            {
274               char buf[100];
275               KeySym keySym;
276               XComposeStatus stat;
277               XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
278               switch (keySym) {
279               case XK_Escape:
280                  exit(0);
281                  break;
282               case XK_t:
283               case XK_T:
284                  ModifyTexture();
285                  break;
286               default:
287                  ;
288               }
289            }
290            Redraw();
291            break;
292         default:
293            /*no-op*/ ;
294         }
295      }
296
297      Redraw();
298      usleep(10000);
299   }
300}
301
302
303
304
305int
306main(int argc, char *argv[])
307{
308   int i;
309
310   for (i = 1; i < argc; i++) {
311      if (strcmp(argv[i], "-display") == 0 && i < argc) {
312         DisplayName = argv[i+1];
313         i++;
314      }
315   }
316
317   Setup();
318
319   printf("Press 't' to change texture image/colors\n");
320
321   EventLoop();
322
323   return 0;
324}
325