GLWindowContext_unix.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /*
  2. * Copyright 2016 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "include/gpu/gl/GrGLInterface.h"
  8. #include "tools/sk_app/GLWindowContext.h"
  9. #include "tools/sk_app/unix/WindowContextFactory_unix.h"
  10. #include <GL/gl.h>
  11. using sk_app::window_context_factory::XlibWindowInfo;
  12. using sk_app::DisplayParams;
  13. using sk_app::GLWindowContext;
  14. namespace {
  15. static bool gCtxErrorOccurred = false;
  16. static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
  17. gCtxErrorOccurred = true;
  18. return 0;
  19. }
  20. class GLWindowContext_xlib : public GLWindowContext {
  21. public:
  22. GLWindowContext_xlib(const XlibWindowInfo&, const DisplayParams&);
  23. ~GLWindowContext_xlib() override;
  24. void onSwapBuffers() override;
  25. void onDestroyContext() override;
  26. protected:
  27. sk_sp<const GrGLInterface> onInitializeContext() override;
  28. private:
  29. GLWindowContext_xlib(void*, const DisplayParams&);
  30. Display* fDisplay;
  31. XWindow fWindow;
  32. GLXFBConfig* fFBConfig;
  33. XVisualInfo* fVisualInfo;
  34. GLXContext fGLContext;
  35. typedef GLWindowContext INHERITED;
  36. };
  37. GLWindowContext_xlib::GLWindowContext_xlib(const XlibWindowInfo& winInfo, const DisplayParams& params)
  38. : INHERITED(params)
  39. , fDisplay(winInfo.fDisplay)
  40. , fWindow(winInfo.fWindow)
  41. , fFBConfig(winInfo.fFBConfig)
  42. , fVisualInfo(winInfo.fVisualInfo)
  43. , fGLContext() {
  44. fWidth = winInfo.fWidth;
  45. fHeight = winInfo.fHeight;
  46. this->initializeContext();
  47. }
  48. using CreateContextAttribsFn = GLXContext(Display*, GLXFBConfig, GLXContext, Bool, const int*);
  49. sk_sp<const GrGLInterface> GLWindowContext_xlib::onInitializeContext() {
  50. SkASSERT(fDisplay);
  51. SkASSERT(!fGLContext);
  52. sk_sp<const GrGLInterface> interface;
  53. bool current = false;
  54. // We attempt to use glXCreateContextAttribsARB as RenderDoc requires that the context be
  55. // created with this rather than glXCreateContext.
  56. CreateContextAttribsFn* createContextAttribs = (CreateContextAttribsFn*)glXGetProcAddressARB(
  57. (const GLubyte*)"glXCreateContextAttribsARB");
  58. if (createContextAttribs && fFBConfig) {
  59. // Install Xlib error handler that will set gCtxErrorOccurred
  60. int (*oldHandler)(Display*, XErrorEvent*) = XSetErrorHandler(&ctxErrorHandler);
  61. // Specifying 3.2 allows an arbitrarily high context version (so long as no 3.2 features
  62. // have been removed).
  63. for (int minor = 2; minor >= 0 && !fGLContext; --minor) {
  64. // Ganesh prefers a compatibility profile for possible NVPR support. However, RenderDoc
  65. // requires a core profile. Edit this code to use RenderDoc.
  66. for (int profile : {GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
  67. GLX_CONTEXT_CORE_PROFILE_BIT_ARB}) {
  68. gCtxErrorOccurred = false;
  69. int attribs[] = {
  70. GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, minor,
  71. GLX_CONTEXT_PROFILE_MASK_ARB, profile,
  72. 0
  73. };
  74. fGLContext = createContextAttribs(fDisplay, *fFBConfig, nullptr, True, attribs);
  75. // Sync to ensure any errors generated are processed.
  76. XSync(fDisplay, False);
  77. if (gCtxErrorOccurred) { continue; }
  78. if (fGLContext && profile == GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB &&
  79. glXMakeCurrent(fDisplay, fWindow, fGLContext)) {
  80. current = true;
  81. // Look to see if RenderDoc is attached. If so, re-create the context with a
  82. // core profile.
  83. interface = GrGLMakeNativeInterface();
  84. if (interface && interface->fExtensions.has("GL_EXT_debug_tool")) {
  85. interface.reset();
  86. glXMakeCurrent(fDisplay, None, nullptr);
  87. glXDestroyContext(fDisplay, fGLContext);
  88. current = false;
  89. fGLContext = nullptr;
  90. }
  91. }
  92. if (fGLContext) {
  93. break;
  94. }
  95. }
  96. }
  97. // Restore the original error handler
  98. XSetErrorHandler(oldHandler);
  99. }
  100. if (!fGLContext) {
  101. fGLContext = glXCreateContext(fDisplay, fVisualInfo, nullptr, GL_TRUE);
  102. }
  103. if (!fGLContext) {
  104. return nullptr;
  105. }
  106. if (!current && !glXMakeCurrent(fDisplay, fWindow, fGLContext)) {
  107. return nullptr;
  108. }
  109. const char* glxExtensions = glXQueryExtensionsString(fDisplay, DefaultScreen(fDisplay));
  110. if (glxExtensions) {
  111. if (strstr(glxExtensions, "GLX_EXT_swap_control")) {
  112. PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT =
  113. (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB(
  114. (const GLubyte*)"glXSwapIntervalEXT");
  115. glXSwapIntervalEXT(fDisplay, fWindow, fDisplayParams.fDisableVsync ? 0 : 1);
  116. }
  117. }
  118. glClearStencil(0);
  119. glClearColor(0, 0, 0, 0);
  120. glStencilMask(0xffffffff);
  121. glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
  122. glXGetConfig(fDisplay, fVisualInfo, GLX_STENCIL_SIZE, &fStencilBits);
  123. glXGetConfig(fDisplay, fVisualInfo, GLX_SAMPLES_ARB, &fSampleCount);
  124. fSampleCount = SkTMax(fSampleCount, 1);
  125. XWindow root;
  126. int x, y;
  127. unsigned int border_width, depth;
  128. XGetGeometry(fDisplay, fWindow, &root, &x, &y, (unsigned int*)&fWidth, (unsigned int*)&fHeight,
  129. &border_width, &depth);
  130. glViewport(0, 0, fWidth, fHeight);
  131. return interface ? interface : GrGLMakeNativeInterface();
  132. }
  133. GLWindowContext_xlib::~GLWindowContext_xlib() {
  134. this->destroyContext();
  135. }
  136. void GLWindowContext_xlib::onDestroyContext() {
  137. if (!fDisplay || !fGLContext) {
  138. return;
  139. }
  140. glXMakeCurrent(fDisplay, None, nullptr);
  141. glXDestroyContext(fDisplay, fGLContext);
  142. fGLContext = nullptr;
  143. }
  144. void GLWindowContext_xlib::onSwapBuffers() {
  145. if (fDisplay && fGLContext) {
  146. glXSwapBuffers(fDisplay, fWindow);
  147. }
  148. }
  149. } // anonymous namespace
  150. namespace sk_app {
  151. namespace window_context_factory {
  152. WindowContext* NewGLForXlib(const XlibWindowInfo& winInfo, const DisplayParams& params) {
  153. WindowContext* ctx = new GLWindowContext_xlib(winInfo, params);
  154. if (!ctx->isValid()) {
  155. delete ctx;
  156. return nullptr;
  157. }
  158. return ctx;
  159. }
  160. } // namespace window_context_factory
  161. } // namespace sk_app