1 // Copyright (C)2004 Landmark Graphics Corporation
2 // Copyright (C)2005, 2006 Sun Microsystems, Inc.
3 // Copyright (C)2009-2015, 2017-2021 D. R. Commander
4 //
5 // This library is free software and may be redistributed and/or modified under
6 // the terms of the wxWindows Library License, Version 3.1 or (at your option)
7 // any later version. The full license is in the LICENSE.txt file included
8 // with this distribution.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // wxWindows Library License for more details.
14
15 #include "VirtualWin.h"
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include "fakerconfig.h"
20 #include "glxvisual.h"
21 #include "vglutil.h"
22
23 using namespace vglutil;
24 using namespace vglcommon;
25 using namespace vglfaker;
26 using namespace vglserver;
27
28
29 static const int trans2pf[RRTRANS_FORMATOPT] =
30 {
31 PF_RGB, PF_RGBX, PF_BGR, PF_BGRX, PF_XBGR, PF_XRGB
32 };
33
34
35 #define LEYE(buf) \
36 (buf == GL_BACK ? GL_BACK_LEFT : (buf == GL_FRONT ? GL_FRONT_LEFT : buf))
37 #define REYE(buf) \
38 (buf == GL_BACK ? GL_BACK_RIGHT : (buf == GL_FRONT ? GL_FRONT_RIGHT : buf))
39 #define IS_ANAGLYPHIC(mode) \
40 (mode >= RRSTEREO_REDCYAN && mode <= RRSTEREO_BLUEYELLOW)
41 #define IS_PASSIVE(mode) \
42 (mode >= RRSTEREO_INTERLEAVED && mode <= RRSTEREO_SIDEBYSIDE)
43
44
45 // This class encapsulates the 3D off-screen drawable, its most recent
46 // ancestor, and information specific to its corresponding X window
47
VirtualWin(Display * dpy_,Window win)48 VirtualWin::VirtualWin(Display *dpy_, Window win) :
49 VirtualDrawable(dpy_, win)
50 {
51 eventdpy = NULL;
52 oldDraw = NULL; newWidth = newHeight = -1;
53 x11trans = NULL;
54 #ifdef USEXV
55 xvtrans = NULL;
56 #endif
57 vglconn = NULL;
58 profGamma.setName("Gamma ");
59 profAnaglyph.setName("Anaglyph ");
60 profPassive.setName("Stereo Gen");
61 syncdpy = false;
62 dirty = false;
63 rdirty = false;
64 fconfig_setdefaultsfromdpy(dpy);
65 plugin = NULL;
66 doWMDelete = false;
67 doVGLWMDelete = false;
68 newConfig = false;
69 swapInterval = 0;
70 alreadyWarnedPluginRenderMode = false;
71 XWindowAttributes xwa;
72 if(!XGetWindowAttributes(dpy, win, &xwa) || !xwa.visual)
73 throw(Error(__FUNCTION__, "Invalid window", -1));
74 if(!fconfig.wm && !(xwa.your_event_mask & StructureNotifyMask))
75 {
76 if(!(eventdpy = _XOpenDisplay(DisplayString(dpy))))
77 THROW("Could not clone X display connection");
78 XSelectInput(eventdpy, win, StructureNotifyMask);
79 if(fconfig.verbose)
80 vglout.println("[VGL] Selecting structure notify events in window 0x%.8x",
81 win);
82 }
83 stereoVisual = glxvisual::visAttrib(dpy, DefaultScreen(dpy),
84 xwa.visual->visualid, GLX_STEREO);
85 }
86
87
~VirtualWin(void)88 VirtualWin::~VirtualWin(void)
89 {
90 mutex.lock(false);
91 delete oldDraw; oldDraw = NULL;
92 delete x11trans; x11trans = NULL;
93 delete vglconn; vglconn = NULL;
94 #ifdef USEXV
95 delete xvtrans; xvtrans = NULL;
96 #endif
97 if(plugin)
98 {
99 try
100 {
101 delete plugin; plugin = NULL;
102 }
103 catch(std::exception &e)
104 {
105 if(fconfig.verbose)
106 vglout.println("[VGL] WARNING: %s", e.what());
107 }
108 }
109 if(eventdpy) { _XCloseDisplay(eventdpy); eventdpy = NULL; }
110 mutex.unlock(false);
111 }
112
113
init(int w,int h,VGLFBConfig config_)114 int VirtualWin::init(int w, int h, VGLFBConfig config_)
115 {
116 CriticalSection::SafeLock l(mutex);
117 if(doWMDelete) THROW("Window has been deleted by window manager");
118 return VirtualDrawable::init(w, h, config_);
119 }
120
121
122 // The resize doesn't actually occur until the next time updatedrawable() is
123 // called
124
resize(int width,int height)125 void VirtualWin::resize(int width, int height)
126 {
127 CriticalSection::SafeLock l(mutex);
128 if(doWMDelete) THROW("Window has been deleted by window manager");
129 if(width == 0 && oglDraw) width = oglDraw->getWidth();
130 if(height == 0 && oglDraw) height = oglDraw->getHeight();
131 if(oglDraw && oglDraw->getWidth() == width && oglDraw->getHeight() == height)
132 {
133 newWidth = newHeight = -1;
134 return;
135 }
136 newWidth = width; newHeight = height;
137 }
138
139
140 // The FB config change doesn't actually occur until the next time
141 // updatedrawable() is called
142
checkConfig(VGLFBConfig config_)143 void VirtualWin::checkConfig(VGLFBConfig config_)
144 {
145 CriticalSection::SafeLock l(mutex);
146 if(doWMDelete) THROW("Window has been deleted by window manager");
147 if(FBCID(config_) != FBCID(config))
148 {
149 config = config_; newConfig = true;
150 }
151 }
152
153
clear(void)154 void VirtualWin::clear(void)
155 {
156 CriticalSection::SafeLock l(mutex);
157 if(doWMDelete) THROW("Window has been deleted by window manager");
158 VirtualDrawable::clear();
159 }
160
161
cleanup(void)162 void VirtualWin::cleanup(void)
163 {
164 CriticalSection::SafeLock l(mutex);
165 if(doWMDelete) THROW("Window has been deleted by window manager");
166 delete oldDraw; oldDraw = NULL;
167 }
168
169
initFromWindow(VGLFBConfig config_)170 void VirtualWin::initFromWindow(VGLFBConfig config_)
171 {
172 XSync(dpy, False);
173 XWindowAttributes xwa;
174 XGetWindowAttributes(dpy, x11Draw, &xwa);
175 init(xwa.width, xwa.height, config_);
176 }
177
178
179 // Get the current 3D off-screen drawable
180
getGLXDrawable(void)181 GLXDrawable VirtualWin::getGLXDrawable(void)
182 {
183 CriticalSection::SafeLock l(mutex);
184 if(doWMDelete) THROW("Window has been deleted by window manager");
185 return VirtualDrawable::getGLXDrawable();
186 }
187
188
checkResize(void)189 void VirtualWin::checkResize(void)
190 {
191 if(eventdpy)
192 {
193 XSync(dpy, False);
194 while(XPending(eventdpy) > 0)
195 {
196 XEvent event;
197 _XNextEvent(eventdpy, &event);
198 if(event.type == ConfigureNotify && event.xconfigure.window == x11Draw
199 && event.xconfigure.width > 0 && event.xconfigure.height > 0)
200 resize(event.xconfigure.width, event.xconfigure.height);
201 }
202 }
203 }
204
205
206 // Get the current 3D off-screen drawable, but resize the drawable (or change
207 // its FB config) first if necessary
208
updateGLXDrawable(void)209 GLXDrawable VirtualWin::updateGLXDrawable(void)
210 {
211 GLXDrawable retval = 0;
212 CriticalSection::SafeLock l(mutex);
213 if(doWMDelete) THROW("Window has been deleted by window manager");
214 if(newConfig)
215 {
216 if(newWidth <= 0 && oglDraw) newWidth = oglDraw->getWidth();
217 if(newHeight <= 0 && oglDraw) newHeight = oglDraw->getHeight();
218 newConfig = false;
219 }
220 if(newWidth > 0 && newHeight > 0)
221 {
222 OGLDrawable *draw = oglDraw;
223 if(init(newWidth, newHeight, config)) oldDraw = draw;
224 newWidth = newHeight = -1;
225 }
226 retval = oglDraw->getGLXDrawable();
227 return retval;
228 }
229
230
swapBuffers(void)231 void VirtualWin::swapBuffers(void)
232 {
233 CriticalSection::SafeLock l(mutex);
234 if(doWMDelete) THROW("Window has been deleted by window manager");
235 if(oglDraw)
236 {
237 if(fconfig.amdgpuHack)
238 copyPixels(0, 0, oglDraw->getWidth(), oglDraw->getHeight(), 0, 0,
239 getGLXDrawable(), GL_BACK, GL_FRONT);
240 else
241 oglDraw->swap();
242 }
243 }
244
245
wmDelete(void)246 void VirtualWin::wmDelete(void)
247 {
248 CriticalSection::SafeLock l(mutex);
249 doWMDelete = doVGLWMDelete;
250 }
251
252
vglWMDelete(void)253 void VirtualWin::vglWMDelete(void)
254 {
255 CriticalSection::SafeLock l(mutex);
256 doVGLWMDelete = true;
257 }
258
259
readback(GLint drawBuf,bool spoilLast,bool sync)260 void VirtualWin::readback(GLint drawBuf, bool spoilLast, bool sync)
261 {
262 fconfig_reloadenv();
263 bool doStereo = false; int stereoMode = fconfig.stereo;
264
265 if(fconfig.readback == RRREAD_NONE || !checkRenderMode())
266 return;
267
268 CriticalSection::SafeLock l(mutex);
269 if(doWMDelete) THROW("Window has been deleted by window manager");
270
271 dirty = false;
272
273 int compress = fconfig.compress;
274 if(sync && strlen(fconfig.transport) == 0) compress = RRCOMP_PROXY;
275
276 if(isStereo() && stereoMode != RRSTEREO_LEYE && stereoMode != RRSTEREO_REYE)
277 {
278 if(DrawingToRight() || rdirty) doStereo = true;
279 rdirty = false;
280 if(doStereo && compress == RRCOMP_YUV && strlen(fconfig.transport) == 0)
281 {
282 static bool message3 = false;
283 if(!message3)
284 {
285 vglout.println("[VGL] NOTICE: Quad-buffered stereo cannot be used with YUV encoding.");
286 vglout.println("[VGL] Using anaglyphic stereo instead.");
287 message3 = true;
288 }
289 stereoMode = RRSTEREO_REDCYAN;
290 }
291 else if(doStereo && _Trans[compress] != RRTRANS_VGL
292 && stereoMode == RRSTEREO_QUADBUF && strlen(fconfig.transport) == 0)
293 {
294 static bool message = false;
295 if(!message)
296 {
297 vglout.println("[VGL] NOTICE: Quad-buffered stereo requires the VGL Transport.");
298 vglout.println("[VGL] Using anaglyphic stereo instead.");
299 message = true;
300 }
301 stereoMode = RRSTEREO_REDCYAN;
302 }
303 else if(doStereo && !stereoVisual && stereoMode == RRSTEREO_QUADBUF
304 && strlen(fconfig.transport) == 0)
305 {
306 static bool message2 = false;
307 if(!message2)
308 {
309 vglout.println("[VGL] NOTICE: Cannot use quad-buffered stereo because no stereo visuals are");
310 vglout.println("[VGL] available on the 2D X server. Using anaglyphic stereo instead.");
311 message2 = true;
312 }
313 stereoMode = RRSTEREO_REDCYAN;
314 }
315 }
316
317 if(strlen(fconfig.transport) > 0)
318 {
319 sendPlugin(drawBuf, spoilLast, sync, doStereo, stereoMode);
320 return;
321 }
322
323 switch(compress)
324 {
325 case RRCOMP_PROXY:
326 sendX11(drawBuf, spoilLast, sync, doStereo, stereoMode);
327 break;
328
329 case RRCOMP_JPEG:
330 case RRCOMP_RGB:
331 case RRCOMP_YUV:
332 if(!vglconn)
333 {
334 vglconn = new VGLTrans();
335 vglconn->connect(
336 strlen(fconfig.client) > 0 ? fconfig.client : DisplayString(dpy),
337 fconfig.port);
338 }
339 sendVGL(drawBuf, spoilLast, doStereo, stereoMode, compress, fconfig.qual,
340 fconfig.subsamp);
341 break;
342 #ifdef USEXV
343 case RRCOMP_XV:
344 sendXV(drawBuf, spoilLast, sync, doStereo, stereoMode);
345 #endif
346 }
347 }
348
349
setupPluginTempContext(GLint drawBuf)350 TempContext *VirtualWin::setupPluginTempContext(GLint drawBuf)
351 {
352 // This code is largely copied from VirtualDrawable::readPixels(). It
353 // establishes a temporary OpenGL context suitable for creating GPU-based
354 // buffer objects in RRTransGetFrame() and reading back the rendered frame in
355 // RRTransSendFrame(), should a plugin choose to do so.
356 TempContext *tc = NULL;
357
358 int renderMode = 0;
359 _glGetIntegerv(GL_RENDER_MODE, &renderMode);
360 if(renderMode != GL_RENDER && renderMode != 0)
361 {
362 if(!alreadyWarnedPluginRenderMode && fconfig.verbose)
363 {
364 vglout.print("[VGL] WARNING: Failed to establish temporary OpenGL context for image\n");
365 vglout.print("[VGL] transport plugin one or more times because render mode != GL_RENDER.\n");
366 alreadyWarnedPluginRenderMode = true;
367 }
368 }
369 else
370 {
371 initReadbackContext();
372 tc = new TempContext(dpy, getGLXDrawable(), getGLXDrawable(), ctx);
373 VGLReadBuffer(drawBuf);
374 }
375
376 return tc;
377 }
378
379
sendPlugin(GLint drawBuf,bool spoilLast,bool sync,bool doStereo,int stereoMode)380 void VirtualWin::sendPlugin(GLint drawBuf, bool spoilLast, bool sync,
381 bool doStereo, int stereoMode)
382 {
383 Frame f;
384 int w = oglDraw->getWidth(), h = oglDraw->getHeight();
385 RRFrame *rrframe = NULL;
386 TempContext *tc = NULL;
387
388 try
389 {
390 if(!plugin)
391 {
392 tc = setupPluginTempContext(drawBuf);
393 plugin = new TransPlugin(dpy, x11Draw, fconfig.transport);
394 plugin->connect(
395 strlen(fconfig.client) > 0 ? fconfig.client : DisplayString(dpy),
396 fconfig.port);
397 }
398
399 if(spoilLast && fconfig.spoil && !plugin->ready())
400 {
401 delete tc; return;
402 }
403 if(!tc) tc = setupPluginTempContext(drawBuf);
404 if(!fconfig.spoil) plugin->synchronize();
405
406 if(oglDraw->getRGBSize() != 24)
407 THROW("Transport plugins require 8 bits per component");
408 int desiredFormat = RRTRANS_RGB;
409 if(oglDraw->getFormat() == GL_BGR) desiredFormat = RRTRANS_BGR;
410 else if(oglDraw->getFormat() == GL_BGRA) desiredFormat = RRTRANS_BGRA;
411 else if(oglDraw->getFormat() == GL_RGBA) desiredFormat = RRTRANS_RGBA;
412
413 rrframe = plugin->getFrame(w, h, desiredFormat,
414 doStereo && stereoMode == RRSTEREO_QUADBUF);
415 if(rrframe->bits)
416 {
417 f.init(rrframe->bits, rrframe->w, rrframe->pitch, rrframe->h,
418 trans2pf[rrframe->format], FRAME_BOTTOMUP);
419
420 if(doStereo && stereoMode == RRSTEREO_QUADBUF && rrframe->rbits == NULL)
421 {
422 static bool message = false;
423 if(!message)
424 {
425 vglout.println("[VGL] NOTICE: Quad-buffered stereo is not supported by the plugin.");
426 vglout.println("[VGL] Using anaglyphic stereo instead.");
427 message = true;
428 }
429 stereoMode = RRSTEREO_REDCYAN;
430 }
431 if(doStereo && IS_ANAGLYPHIC(stereoMode))
432 {
433 stereoFrame.deInit();
434 makeAnaglyph(&f, drawBuf, stereoMode);
435 }
436 else if(doStereo && IS_PASSIVE(stereoMode))
437 {
438 rFrame.deInit(); gFrame.deInit(); bFrame.deInit();
439 makePassive(&f, drawBuf, GL_NONE, stereoMode);
440 }
441 else
442 {
443 rFrame.deInit(); gFrame.deInit(); bFrame.deInit();
444 stereoFrame.deInit();
445 GLint readBuf = drawBuf;
446 if(doStereo || stereoMode == RRSTEREO_LEYE) readBuf = LEYE(drawBuf);
447 if(stereoMode == RRSTEREO_REYE) readBuf = REYE(drawBuf);
448 readPixels(0, 0, rrframe->w, rrframe->pitch, rrframe->h, GL_NONE, f.pf,
449 rrframe->bits, readBuf, doStereo);
450 if(doStereo && rrframe->rbits)
451 readPixels(0, 0, rrframe->w, rrframe->pitch, rrframe->h, GL_NONE,
452 f.pf, rrframe->rbits, REYE(drawBuf), doStereo);
453 }
454 if(!syncdpy) { XSync(dpy, False); syncdpy = true; }
455 if(fconfig.logo) f.addLogo();
456 }
457 plugin->sendFrame(rrframe, sync);
458 }
459 catch(...)
460 {
461 delete tc;
462 throw;
463 }
464 delete tc;
465 }
466
467
sendVGL(GLint drawBuf,bool spoilLast,bool doStereo,int stereoMode,int compress,int qual,int subsamp)468 void VirtualWin::sendVGL(GLint drawBuf, bool spoilLast, bool doStereo,
469 int stereoMode, int compress, int qual, int subsamp)
470 {
471 int w = oglDraw->getWidth(), h = oglDraw->getHeight();
472
473 if(spoilLast && fconfig.spoil && !vglconn->isReady())
474 return;
475 Frame *f;
476
477 if(oglDraw->getRGBSize() != 24)
478 THROW("The VGL Transport requires 8 bits per component");
479 int glFormat = GL_RGB, pixelFormat = PF_RGB;
480 if(compress != RRCOMP_RGB)
481 {
482 glFormat = oglDraw->getFormat();
483 if(glFormat == GL_RGBA) pixelFormat = PF_RGBX;
484 else if(glFormat == GL_BGR) pixelFormat = PF_BGR;
485 else if(glFormat == GL_BGRA) pixelFormat = PF_BGRX;
486 }
487
488 if(!fconfig.spoil) vglconn->synchronize();
489 ERRIFNOT(f = vglconn->getFrame(w, h, pixelFormat, FRAME_BOTTOMUP,
490 doStereo && stereoMode == RRSTEREO_QUADBUF));
491 if(doStereo && IS_ANAGLYPHIC(stereoMode))
492 {
493 stereoFrame.deInit();
494 makeAnaglyph(f, drawBuf, stereoMode);
495 }
496 else if(doStereo && IS_PASSIVE(stereoMode))
497 {
498 rFrame.deInit(); gFrame.deInit(); bFrame.deInit();
499 makePassive(f, drawBuf, glFormat, stereoMode);
500 }
501 else
502 {
503 rFrame.deInit(); gFrame.deInit(); bFrame.deInit(); stereoFrame.deInit();
504 GLint readBuf = drawBuf;
505 if(doStereo || stereoMode == RRSTEREO_LEYE) readBuf = LEYE(drawBuf);
506 if(stereoMode == RRSTEREO_REYE) readBuf = REYE(drawBuf);
507 readPixels(0, 0, f->hdr.framew, f->pitch, f->hdr.frameh, glFormat, f->pf,
508 f->bits, readBuf, doStereo);
509 if(doStereo && f->rbits)
510 readPixels(0, 0, f->hdr.framew, f->pitch, f->hdr.frameh, glFormat, f->pf,
511 f->rbits, REYE(drawBuf), doStereo);
512 }
513 f->hdr.winid = x11Draw;
514 f->hdr.framew = f->hdr.width;
515 f->hdr.frameh = f->hdr.height;
516 f->hdr.x = 0;
517 f->hdr.y = 0;
518 f->hdr.qual = qual;
519 f->hdr.subsamp = subsamp;
520 f->hdr.compress = (unsigned char)compress;
521 if(!syncdpy) { XSync(dpy, False); syncdpy = true; }
522 if(fconfig.logo) f->addLogo();
523 vglconn->sendFrame(f);
524 }
525
526
sendX11(GLint drawBuf,bool spoilLast,bool sync,bool doStereo,int stereoMode)527 void VirtualWin::sendX11(GLint drawBuf, bool spoilLast, bool sync,
528 bool doStereo, int stereoMode)
529 {
530 int width = oglDraw->getWidth(), height = oglDraw->getHeight();
531
532 FBXFrame *f;
533 if(!x11trans) x11trans = new X11Trans();
534 if(spoilLast && fconfig.spoil && !x11trans->isReady()) return;
535 if(!fconfig.spoil) x11trans->synchronize();
536 ERRIFNOT(f = x11trans->getFrame(dpy, x11Draw, width, height));
537 f->flags |= FRAME_BOTTOMUP;
538 if(doStereo && IS_ANAGLYPHIC(stereoMode))
539 {
540 stereoFrame.deInit();
541 makeAnaglyph(f, drawBuf, stereoMode);
542 }
543 else
544 {
545 rFrame.deInit(); gFrame.deInit(); bFrame.deInit();
546 if(doStereo && IS_PASSIVE(stereoMode))
547 makePassive(f, drawBuf, GL_NONE, stereoMode);
548 else
549 {
550 stereoFrame.deInit();
551 GLint readBuf = drawBuf;
552 if(stereoMode == RRSTEREO_REYE) readBuf = REYE(drawBuf);
553 else if(stereoMode == RRSTEREO_LEYE) readBuf = LEYE(drawBuf);
554 readPixels(0, 0, min(width, f->hdr.framew), f->pitch,
555 min(height, f->hdr.frameh), GL_NONE, f->pf, f->bits, readBuf, false);
556 }
557 }
558 if(fconfig.logo) f->addLogo();
559 x11trans->sendFrame(f, sync);
560 }
561
562
563 #ifdef USEXV
564
sendXV(GLint drawBuf,bool spoilLast,bool sync,bool doStereo,int stereoMode)565 void VirtualWin::sendXV(GLint drawBuf, bool spoilLast, bool sync,
566 bool doStereo, int stereoMode)
567 {
568 int width = oglDraw->getWidth(), height = oglDraw->getHeight();
569
570 XVFrame *f;
571 if(!xvtrans) xvtrans = new XVTrans();
572 if(spoilLast && fconfig.spoil && !xvtrans->isReady()) return;
573 if(!fconfig.spoil) xvtrans->synchronize();
574 ERRIFNOT(f = xvtrans->getFrame(dpy, x11Draw, width, height));
575 rrframeheader hdr;
576 hdr.x = hdr.y = 0;
577 hdr.width = hdr.framew = width;
578 hdr.height = hdr.frameh = height;
579
580 if(oglDraw->getRGBSize() != 24)
581 THROW("The XV Transport requires 8 bits per component");
582 int glFormat = oglDraw->getFormat(), pixelFormat = PF_RGB;
583 if(glFormat == GL_RGBA) pixelFormat = PF_RGBX;
584 else if(glFormat == GL_BGR) pixelFormat = PF_BGR;
585 else if(glFormat == GL_BGRA) pixelFormat = PF_BGRX;
586
587 frame.init(hdr, pixelFormat, FRAME_BOTTOMUP, false);
588
589 if(doStereo && IS_ANAGLYPHIC(stereoMode))
590 {
591 stereoFrame.deInit();
592 makeAnaglyph(&frame, drawBuf, stereoMode);
593 }
594 else if(doStereo && IS_PASSIVE(stereoMode))
595 {
596 rFrame.deInit(); gFrame.deInit(); bFrame.deInit();
597 makePassive(&frame, drawBuf, glFormat, stereoMode);
598 }
599 else
600 {
601 rFrame.deInit(); gFrame.deInit(); bFrame.deInit(); stereoFrame.deInit();
602 GLint readBuf = drawBuf;
603 if(stereoMode == RRSTEREO_REYE) readBuf = REYE(drawBuf);
604 else if(stereoMode == RRSTEREO_LEYE) readBuf = LEYE(drawBuf);
605 readPixels(0, 0, min(width, frame.hdr.framew), frame.pitch,
606 min(height, frame.hdr.frameh), glFormat, frame.pf, frame.bits, readBuf,
607 false);
608 }
609
610 if(fconfig.logo) frame.addLogo();
611
612 *f = frame;
613 xvtrans->sendFrame(f, sync);
614 }
615
616 #endif
617
618
makeAnaglyph(Frame * f,int drawBuf,int stereoMode)619 void VirtualWin::makeAnaglyph(Frame *f, int drawBuf, int stereoMode)
620 {
621 int rbuf = LEYE(drawBuf), gbuf = REYE(drawBuf), bbuf = REYE(drawBuf);
622 if(stereoMode == RRSTEREO_GREENMAGENTA)
623 {
624 rbuf = REYE(drawBuf); gbuf = LEYE(drawBuf); bbuf = REYE(drawBuf);
625 }
626 else if(stereoMode == RRSTEREO_BLUEYELLOW)
627 {
628 rbuf = REYE(drawBuf); gbuf = REYE(drawBuf); bbuf = LEYE(drawBuf);
629 }
630 rFrame.init(f->hdr, PF_COMP, f->flags, false);
631 readPixels(0, 0, rFrame.hdr.framew, rFrame.pitch, rFrame.hdr.frameh, GL_RED,
632 rFrame.pf, rFrame.bits, rbuf, false);
633 gFrame.init(f->hdr, PF_COMP, f->flags, false);
634 readPixels(0, 0, gFrame.hdr.framew, gFrame.pitch, gFrame.hdr.frameh,
635 GL_GREEN, gFrame.pf, gFrame.bits, gbuf, false);
636 bFrame.init(f->hdr, PF_COMP, f->flags, false);
637 readPixels(0, 0, bFrame.hdr.framew, bFrame.pitch, bFrame.hdr.frameh, GL_BLUE,
638 bFrame.pf, bFrame.bits, bbuf, false);
639 profAnaglyph.startFrame();
640 f->makeAnaglyph(rFrame, gFrame, bFrame);
641 profAnaglyph.endFrame(f->hdr.framew * f->hdr.frameh, 0, 1);
642 }
643
644
makePassive(Frame * f,int drawBuf,GLenum glFormat,int stereoMode)645 void VirtualWin::makePassive(Frame *f, int drawBuf, GLenum glFormat,
646 int stereoMode)
647 {
648 stereoFrame.init(f->hdr, f->pf->id, f->flags, true);
649 readPixels(0, 0, stereoFrame.hdr.framew, stereoFrame.pitch,
650 stereoFrame.hdr.frameh, glFormat, stereoFrame.pf, stereoFrame.bits,
651 LEYE(drawBuf), true);
652 readPixels(0, 0, stereoFrame.hdr.framew, stereoFrame.pitch,
653 stereoFrame.hdr.frameh, glFormat, stereoFrame.pf, stereoFrame.rbits,
654 REYE(drawBuf), true);
655 profPassive.startFrame();
656 f->makePassive(stereoFrame, stereoMode);
657 profPassive.endFrame(f->hdr.framew * f->hdr.frameh, 0, 1);
658 }
659
660
readPixels(GLint x,GLint y,GLint width,GLint pitch,GLint height,GLenum glFormat,PF * pf,GLubyte * bits,GLint buf,bool stereo)661 void VirtualWin::readPixels(GLint x, GLint y, GLint width, GLint pitch,
662 GLint height, GLenum glFormat, PF *pf, GLubyte *bits, GLint buf, bool stereo)
663 {
664 VirtualDrawable::readPixels(x, y, width, pitch, height, glFormat, pf, bits,
665 buf, stereo);
666
667 // Gamma correction
668 if(fconfig.gamma != 0.0 && fconfig.gamma != 1.0 && fconfig.gamma != -1.0)
669 {
670 profGamma.startFrame();
671 static bool first = true;
672 if(first)
673 {
674 first = false;
675 if(fconfig.verbose)
676 vglout.println("[VGL] Using software gamma correction (correction factor=%f)\n",
677 fconfig.gamma);
678 }
679 if(pf->bpc == 10)
680 {
681 int h = height;
682 while(h--)
683 {
684 int w = width;
685 unsigned int *srcPixel = (unsigned int *)bits;
686 while(w--)
687 {
688 unsigned int r =
689 fconfig.gamma_lut10[(*srcPixel >> pf->rshift) & 1023];
690 unsigned int g =
691 fconfig.gamma_lut10[(*srcPixel >> pf->gshift) & 1023];
692 unsigned int b =
693 fconfig.gamma_lut10[(*srcPixel >> pf->bshift) & 1023];
694 *srcPixel++ =
695 (r << pf->rshift) | (g << pf->gshift) | (b << pf->bshift);
696 }
697 bits += pitch;
698 }
699 }
700 else
701 {
702 unsigned short *ptr1, *ptr2 = (unsigned short *)(&bits[pitch * height]);
703 for(ptr1 = (unsigned short *)bits; ptr1 < ptr2; ptr1++)
704 *ptr1 = fconfig.gamma_lut16[*ptr1];
705 if((pitch * height) % 2 != 0)
706 bits[pitch * height - 1] = fconfig.gamma_lut[bits[pitch * height - 1]];
707 }
708 profGamma.endFrame(width * height, 0, stereo ? 0.5 : 1);
709 }
710 }
711
712
isStereo(void)713 bool VirtualWin::isStereo(void)
714 {
715 return oglDraw && oglDraw->isStereo();
716 }
717