glx2.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. //Xorg/GLX OpenGL 2.0 driver
  2. //note: this is a fallback driver for use when OpenGL 3.2 is not available.
  3. //see glx.cpp for comments on how this driver operates (they are very similar.)
  4. #if defined(DISPLAY_XORG)
  5. #include <GL/gl.h>
  6. #include <GL/glx.h>
  7. #ifndef glGetProcAddress
  8. #define glGetProcAddress(name) (*glXGetProcAddress)((const GLubyte*)(name))
  9. #endif
  10. #elif defined(DISPLAY_QUARTZ)
  11. #include <OpenGL/gl3.h>
  12. #elif defined(DISPLAY_WINDOWS)
  13. #include <GL/gl.h>
  14. #include <GL/glext.h>
  15. #ifndef glGetProcAddress
  16. #define glGetProcAddress(name) wglGetProcAddress(name)
  17. #endif
  18. #else
  19. #error "ruby::OpenGL2: unsupported platform"
  20. #endif
  21. struct VideoGLX2 : VideoDriver {
  22. VideoGLX2& self = *this;
  23. VideoGLX2(Video& super) : VideoDriver(super) { construct(); }
  24. ~VideoGLX2() { destruct(); }
  25. auto create() -> bool {
  26. VideoDriver::exclusive = true;
  27. VideoDriver::format = "ARGB24";
  28. return initialize();
  29. }
  30. auto driver() -> string override { return "OpenGL 2.0"; }
  31. auto ready() -> bool override { return _ready; }
  32. auto hasFullScreen() -> bool override { return true; }
  33. auto hasMonitor() -> bool override { return true; }
  34. auto hasContext() -> bool override { return true; }
  35. auto hasBlocking() -> bool override { return true; }
  36. auto hasFlush() -> bool override { return true; }
  37. auto hasShader() -> bool override { return true; }
  38. auto hasFormats() -> vector<string> override {
  39. if(_depth == 30) return {"ARGB30", "ARGB24"};
  40. if(_depth == 24) return {"ARGB24"};
  41. return {"ARGB24"}; //fallback
  42. }
  43. auto setFullScreen(bool fullScreen) -> bool override {
  44. return initialize();
  45. }
  46. auto setMonitor(string monitor) -> bool override {
  47. return initialize();
  48. }
  49. auto setContext(uintptr context) -> bool override {
  50. return initialize();
  51. }
  52. auto setBlocking(bool blocking) -> bool override {
  53. if(glXSwapInterval) glXSwapInterval(blocking);
  54. return true;
  55. }
  56. auto setFormat(string format) -> bool override {
  57. if(format == "ARGB24") {
  58. _glFormat = GL_UNSIGNED_INT_8_8_8_8_REV;
  59. return initialize();
  60. }
  61. if(format == "ARGB30") {
  62. _glFormat = GL_UNSIGNED_INT_2_10_10_10_REV;
  63. return initialize();
  64. }
  65. return false;
  66. }
  67. auto setShader(string shader) -> bool override {
  68. return true;
  69. }
  70. auto focused() -> bool override {
  71. return true;
  72. }
  73. auto clear() -> void override {
  74. memory::fill<uint32_t>(_glBuffer, _glWidth * _glHeight);
  75. glClearColor(0.0, 0.0, 0.0, 1.0);
  76. glClear(GL_COLOR_BUFFER_BIT);
  77. glFlush();
  78. if(_isDoubleBuffered) glXSwapBuffers(_display, _glXWindow);
  79. }
  80. auto size(uint& width, uint& height) -> void override {
  81. if(self.fullScreen) {
  82. width = _monitorWidth;
  83. height = _monitorHeight;
  84. } else {
  85. XWindowAttributes parent;
  86. XGetWindowAttributes(_display, _parent, &parent);
  87. width = parent.width;
  88. height = parent.height;
  89. }
  90. }
  91. auto acquire(uint32_t*& data, uint& pitch, uint width, uint height) -> bool override {
  92. if(width != _width || height != _height) resize(width, height);
  93. pitch = _glWidth * sizeof(uint32_t);
  94. return data = _glBuffer;
  95. }
  96. auto release() -> void override {
  97. }
  98. auto output(uint width, uint height) -> void override {
  99. XWindowAttributes window;
  100. XGetWindowAttributes(_display, _window, &window);
  101. XWindowAttributes parent;
  102. XGetWindowAttributes(_display, _parent, &parent);
  103. if(window.width != parent.width || window.height != parent.height) {
  104. XResizeWindow(_display, _window, parent.width, parent.height);
  105. }
  106. uint viewportX = 0;
  107. uint viewportY = 0;
  108. uint viewportWidth = parent.width;
  109. uint viewportHeight = parent.height;
  110. if(self.fullScreen) {
  111. viewportX = _monitorX;
  112. viewportY = _monitorY;
  113. viewportWidth = _monitorWidth;
  114. viewportHeight = _monitorHeight;
  115. }
  116. if(!width) width = viewportWidth;
  117. if(!height) height = viewportHeight;
  118. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
  119. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
  120. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, self.shader == "Blur" ? GL_LINEAR : GL_NEAREST);
  121. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, self.shader == "Blur" ? GL_LINEAR : GL_NEAREST);
  122. glMatrixMode(GL_PROJECTION);
  123. glLoadIdentity();
  124. //vertex coordinates range from (0,0) to (1,1) for the entire desktop (all monitors)
  125. glOrtho(0, 1, 0, 1, -1.0, 1.0);
  126. //set the viewport to the entire desktop (all monitors)
  127. glViewport(0, 0, parent.width, parent.height);
  128. glMatrixMode(GL_MODELVIEW);
  129. glLoadIdentity();
  130. glPixelStorei(GL_UNPACK_ROW_LENGTH, _glWidth);
  131. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, _width, _height, GL_BGRA, _glFormat, _glBuffer);
  132. //normalize texture coordinates and adjust for NPOT textures
  133. double w = (double)_width / (double)_glWidth;
  134. double h = (double)_height / (double)_glHeight;
  135. //size of the active monitor
  136. double mw = (double)viewportWidth / (double)parent.width;
  137. double mh = (double)viewportHeight / (double)parent.height;
  138. //offset of the active monitor
  139. double mx = (double)viewportX / (double)parent.width;
  140. double my = (double)viewportY / (double)parent.height;
  141. //size of the render area
  142. double vw = (double)width / (double)parent.width;
  143. double vh = (double)height / (double)parent.height;
  144. //center the render area within the active monitor
  145. double vl = mx + (mw - vw) / 2;
  146. double vt = my + (mh - vh) / 2;
  147. double vr = vl + vw;
  148. double vb = vt + vh;
  149. //OpenGL places (0,0) at the bottom left; convert our (0,0) at the top left to this form:
  150. vt = 1.0 - vt;
  151. vb = 1.0 - vb;
  152. glBegin(GL_TRIANGLE_STRIP);
  153. glTexCoord2f(0, 0); glVertex3f(vl, vt, 0);
  154. glTexCoord2f(w, 0); glVertex3f(vr, vt, 0);
  155. glTexCoord2f(0, h); glVertex3f(vl, vb, 0);
  156. glTexCoord2f(w, h); glVertex3f(vr, vb, 0);
  157. glEnd();
  158. glFlush();
  159. if(_isDoubleBuffered) glXSwapBuffers(_display, _glXWindow);
  160. if(self.flush) glFinish();
  161. }
  162. auto poll() -> void override {
  163. while(XPending(_display)) {
  164. XEvent event;
  165. XNextEvent(_display, &event);
  166. if(event.type == Expose) {
  167. XWindowAttributes attributes;
  168. XGetWindowAttributes(_display, _window, &attributes);
  169. super.doUpdate(attributes.width, attributes.height);
  170. }
  171. }
  172. }
  173. private:
  174. auto construct() -> void {
  175. _display = XOpenDisplay(nullptr);
  176. _screen = DefaultScreen(_display);
  177. XWindowAttributes attributes{};
  178. XGetWindowAttributes(_display, RootWindow(_display, _screen), &attributes);
  179. _depth = attributes.depth;
  180. }
  181. auto destruct() -> void {
  182. terminate();
  183. XCloseDisplay(_display);
  184. }
  185. auto initialize() -> bool {
  186. terminate();
  187. if(!self.fullScreen && !self.context) return false;
  188. int versionMajor = 0, versionMinor = 0;
  189. glXQueryVersion(_display, &versionMajor, &versionMinor);
  190. if(versionMajor < 1 || (versionMajor == 1 && versionMinor < 2)) return false;
  191. int redDepth = self.format == "RGB30" ? 10 : 8;
  192. int greenDepth = self.format == "RGB30" ? 10 : 8;
  193. int blueDepth = self.format == "RGB30" ? 10 : 8;
  194. int attributeList[] = {
  195. GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
  196. GLX_RENDER_TYPE, GLX_RGBA_BIT,
  197. GLX_DOUBLEBUFFER, True,
  198. GLX_RED_SIZE, redDepth,
  199. GLX_GREEN_SIZE, greenDepth,
  200. GLX_BLUE_SIZE, blueDepth,
  201. None
  202. };
  203. int fbCount = 0;
  204. auto fbConfig = glXChooseFBConfig(_display, _screen, attributeList, &fbCount);
  205. if(fbCount == 0) return false;
  206. auto visual = glXGetVisualFromFBConfig(_display, fbConfig[0]);
  207. _parent = self.fullScreen ? RootWindow(_display, visual->screen) : (Window)self.context;
  208. XWindowAttributes windowAttributes;
  209. XGetWindowAttributes(_display, _parent, &windowAttributes);
  210. auto monitor = Video::monitor(self.monitor);
  211. _monitorX = monitor.x;
  212. _monitorY = monitor.y;
  213. _monitorWidth = monitor.width;
  214. _monitorHeight = monitor.height;
  215. _colormap = XCreateColormap(_display, RootWindow(_display, visual->screen), visual->visual, AllocNone);
  216. XSetWindowAttributes attributes{};
  217. attributes.border_pixel = 0;
  218. attributes.colormap = _colormap;
  219. attributes.override_redirect = self.fullScreen;
  220. _window = XCreateWindow(_display, _parent,
  221. 0, 0, windowAttributes.width, windowAttributes.height,
  222. 0, visual->depth, InputOutput, visual->visual,
  223. CWBorderPixel | CWColormap | CWOverrideRedirect, &attributes);
  224. XSelectInput(_display, _window, ExposureMask);
  225. XSetWindowBackground(_display, _window, 0);
  226. XMapWindow(_display, _window);
  227. XFlush(_display);
  228. while(XPending(_display)) {
  229. XEvent event;
  230. XNextEvent(_display, &event);
  231. }
  232. _glXContext = glXCreateContext(_display, visual, 0, GL_TRUE);
  233. glXMakeCurrent(_display, _glXWindow = _window, _glXContext);
  234. if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalMESA");
  235. if(!glXSwapInterval) glXSwapInterval = (int (*)(int))glGetProcAddress("glXSwapIntervalSGI");
  236. if(glXSwapInterval) glXSwapInterval(self.blocking);
  237. int value = 0;
  238. glXGetConfig(_display, visual, GLX_DOUBLEBUFFER, &value);
  239. _isDoubleBuffered = value;
  240. _isDirect = glXIsDirect(_display, _glXContext);
  241. glDisable(GL_ALPHA_TEST);
  242. glDisable(GL_BLEND);
  243. glDisable(GL_DEPTH_TEST);
  244. glDisable(GL_POLYGON_SMOOTH);
  245. glDisable(GL_STENCIL_TEST);
  246. glEnable(GL_DITHER);
  247. glEnable(GL_TEXTURE_2D);
  248. resize(256, 256);
  249. return _ready = true;
  250. }
  251. auto terminate() -> void {
  252. _ready = false;
  253. if(_glTexture) {
  254. glDeleteTextures(1, &_glTexture);
  255. _glTexture = 0;
  256. }
  257. if(_glBuffer) {
  258. delete[] _glBuffer;
  259. _glBuffer = nullptr;
  260. }
  261. _glWidth = 0;
  262. _glHeight = 0;
  263. if(_glXContext) {
  264. glXDestroyContext(_display, _glXContext);
  265. _glXContext = nullptr;
  266. }
  267. if(_window) {
  268. XUnmapWindow(_display, _window);
  269. _window = 0;
  270. }
  271. if(_colormap) {
  272. XFreeColormap(_display, _colormap);
  273. _colormap = 0;
  274. }
  275. }
  276. auto resize(uint width, uint height) -> void {
  277. _width = width;
  278. _height = height;
  279. if(_glTexture == 0) glGenTextures(1, &_glTexture);
  280. _glWidth = max(_glWidth, width);
  281. _glHeight = max(_glHeight, height);
  282. delete[] _glBuffer;
  283. _glBuffer = new uint32_t[_glWidth * _glHeight]();
  284. glBindTexture(GL_TEXTURE_2D, _glTexture);
  285. glPixelStorei(GL_UNPACK_ROW_LENGTH, _glWidth);
  286. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _glWidth, _glHeight, 0, GL_BGRA, _glFormat, _glBuffer);
  287. }
  288. bool _ready = false;
  289. bool blur = false;
  290. Display* _display = nullptr;
  291. uint _monitorX = 0;
  292. uint _monitorY = 0;
  293. uint _monitorWidth = 0;
  294. uint _monitorHeight = 0;
  295. int _screen = 0;
  296. uint _depth = 24; //depth of the default root window
  297. Window _parent = 0;
  298. Window _window = 0;
  299. Colormap _colormap = 0;
  300. GLXContext _glXContext = nullptr;
  301. GLXWindow _glXWindow = 0;
  302. bool _isDoubleBuffered = false;
  303. bool _isDirect = false;
  304. uint _width = 256;
  305. uint _height = 256;
  306. GLuint _glTexture = 0;
  307. uint32_t* _glBuffer = nullptr;
  308. uint _glWidth = 0;
  309. uint _glHeight = 0;
  310. uint _glFormat = GL_UNSIGNED_INT_8_8_8_8_REV;
  311. auto (*glXSwapInterval)(int) -> int = nullptr;
  312. };