Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
visual.cc
Go to the documentation of this file.
1 
18 
21 #if defined(ION_PLATFORM_WINDOWS)
22 # if defined(NOGDI)
23 # undef NOGDI
24 # endif
25 # include <windows.h> // NOLINT
26 # undef ERROR // This is defined in Windows headers.
27 #endif
28 
30 #include "ion/portgfx/visual.h"
31 
32 #if defined(ION_PLATFORM_ASMJS)
33 # include <emscripten.h>
34 #endif
35 
36 #include <cstddef> // For NULL.
37 #include <cstring> // For strchr().
38 #include <unordered_map>
39 
40 #include "ion/portgfx/glheaders.h"
41 
42 #if defined(ION_PLATFORM_LINUX) && !defined(ION_GFX_OGLES20)
43 # include <GL/glx.h> // NOLINT
44 # undef None // Defined in X.h, but reused in gtest.h.
45 # undef Bool // Defined in X.h, but reused in gtest.h.
46 
47 #elif defined(ION_PLATFORM_NACL)
48 # include "ppapi/cpp/graphics_3d.h"
49 # include "ppapi/cpp/instance.h"
50 # include "ppapi/cpp/module.h"
51 # include "ppapi/lib/gl/gles2/gl2ext_ppapi.h"
52 #endif
53 
54 #include "ion/base/lockguards.h"
55 #include "ion/base/logging.h"
57 #include "ion/base/stringutils.h"
59 #include "ion/port/environment.h"
60 #include "ion/port/mutex.h"
61 
62 namespace ion {
63 namespace portgfx {
64 
65 namespace {
66 
68 
73 
74 
75 class VisualStorage {
76  public:
77  VisualStorage() : current_(NULL) {}
78  const Visual* GetCurrent() const { return current_; }
79  void SetCurrent(const Visual* value) { current_ = value; }
80 
81  private:
82  const Visual* current_;
83 };
84 
86 static VisualStorage* GetHolder() {
87  ION_DECLARE_SAFE_STATIC_POINTER(base::ThreadLocalObject<VisualStorage>,
88  s_helper);
89  return s_helper->Get();
90 }
91 
93 
99 
100 
102 typedef std::unordered_map<size_t, const Visual*> VisualMap;
103 
105 static VisualMap& GetVisualMap() {
106  ION_DECLARE_SAFE_STATIC_POINTER(VisualMap, visuals);
107  return *visuals;
108 }
109 
111 static port::Mutex* GetVisualMapMutex() {
112  ION_DECLARE_SAFE_STATIC_POINTER(port::Mutex, mutex);
113  return mutex;
114 }
115 
116 #if defined(ION_PLATFORM_WINDOWS)
117 
119 class IonWindowClass {
120  public:
121  IonWindowClass() {
122  WNDCLASSEX window_class;
123  memset(&window_class, 0, sizeof(window_class));
124  window_class.cbSize = sizeof(window_class);
125  window_class.style = CS_OWNDC;
126  window_class.lpfnWndProc = &DefWindowProc;
127  window_class.hInstance = GetModuleHandle(nullptr);
128  window_class.lpszClassName = kClassName;
129  atom_ = RegisterClassEx(&window_class);
130  }
131 
132  ~IonWindowClass() { UnregisterClass(kClassName, GetModuleHandle(nullptr)); }
133 
134  ATOM GetAtom() const { return atom_; }
135 
136  private:
137  static const char kClassName[];
138 
139  ATOM atom_;
140 };
141 
142 const char IonWindowClass::kClassName[] = "ION";
143 
144 ATOM GetIonWindowClass() {
145  ION_DECLARE_SAFE_STATIC_POINTER(IonWindowClass, window_class);
146  return window_class->GetAtom();
147 }
148 
149 #endif
150 
151 } // anonymous namespace
152 
153 struct Visual::VisualInfo {
158  static void* GetCurrentContext();
160  static void ClearCurrentContext();
161 
162 #if defined(ION_PLATFORM_ANDROID) || defined(ION_PLATFORM_ASMJS) || \
163  defined(ION_PLATFORM_GENERIC_ARM) || \
164  (defined(ION_PLATFORM_LINUX) && defined(ION_GFX_OGLES20))
165  VisualInfo()
166  : display(NULL),
167  surface(NULL),
168  context(NULL) {}
169  void InitEgl(Type type);
170  EGLDisplay display;
171  EGLSurface surface;
172  EGLContext context;
173 #elif defined(ION_PLATFORM_LINUX)
174  VisualInfo()
175  : display(NULL),
176  info(NULL),
177  context(NULL),
178  colormap(0),
179  window(0) {}
180  Display* display;
181  XVisualInfo* info;
182  GLXContext context;
183  Colormap colormap;
184  Window window;
185 #elif defined(ION_PLATFORM_NACL)
186  VisualInfo() : context(0) {}
187  PP_Resource context;
188 #elif defined(ION_PLATFORM_WINDOWS)
189  VisualInfo()
190 # if defined(ION_ANGLE)
191  : display(nullptr),
192  surface(nullptr),
193  context(nullptr),
194 # else
195  : device_context(nullptr),
196  context(nullptr),
197 # endif
198  window(nullptr) {
199  }
200 # if defined(ION_ANGLE)
201  void InitEgl(Type type);
202  EGLDisplay display;
203  EGLSurface surface;
204  EGLContext context;
205 # else
206  HDC device_context;
207  HGLRC context;
208 # endif
209  HWND window; // Only populated if this VisualInfo created a window.
210 #endif
211 };
212 
216  const Visual* current = GetHolder()->GetCurrent();
218  if (current && current->type_ == kMock)
219  return current;
220 
224  const size_t id = reinterpret_cast<size_t>(VisualInfo::GetCurrentContext());
225  if (current && id == current->GetId()) {
226  return current;
227  }
228 
232  current = nullptr;
233 
234  VisualMap& visuals = GetVisualMap();
235  base::LockGuard guard(GetVisualMapMutex());
236  if (id) {
239  VisualMap::iterator it = visuals.find(id);
240  if (it != visuals.end())
241  current = it->second;
242  }
243  if (current) {
245  GetHolder()->SetCurrent(current);
246  } else if (id) {
249  DCHECK(id);
250  DCHECK(visuals.find(id) == visuals.end());
251  Visual* new_visual = new Visual(kCurrent);
252  new_visual->UpdateId();
253  current = new_visual;
254  DCHECK_EQ(id, current->GetId());
255  visuals[id] = new_visual;
256  if (!MakeCurrent(current))
257  current = nullptr;
258  } else {
260  GetHolder()->SetCurrent(nullptr);
261  }
262 
263  return current;
264 }
265 
266 bool Visual::MakeCurrent(const Visual* new_visual) {
267  if (!new_visual) {
268  if (const Visual* current = GetCurrent()) {
269  GetHolder()->SetCurrent(NULL);
270  if (current->type_ != kMock) {
271  VisualInfo::ClearCurrentContext();
272  }
273  }
274  return true;
275  } else if (new_visual->IsValid()) {
276  const bool success = new_visual->MakeCurrent();
277  if (success) {
278  GetHolder()->SetCurrent(new_visual);
279  } else {
280  GetHolder()->SetCurrent(NULL);
281  }
282  return success;
283  } else {
284  LOG(WARNING) << "Failed to make Visual current: " << new_visual;
285  return false;
288  }
289 }
290 
292  if (visual) {
293  const Visual* visual_to_delete = NULL;
294  {
295  VisualMap& visuals = GetVisualMap();
296  base::LockGuard guard(GetVisualMapMutex());
297 
300  VisualMap::iterator it = visuals.find(visual->GetId());
301  if (it != visuals.end()) {
302  DCHECK_EQ(visual, it->second);
304  if (visual->type_ == kCurrent)
305  visual_to_delete = it->second;
306  }
307  }
308  if (visual_to_delete)
309  delete visual_to_delete;
310  }
311 }
312 
318  const Visual* ptr = GetHolder()->GetCurrent();
319  if (ptr && ptr->type_ == kMock) {
320  return ptr->GetId();
321  }
322  return reinterpret_cast<size_t>(VisualInfo::GetCurrentContext());
323 }
324 
326  DCHECK(visual);
327  const bool was_current = visual == GetHolder()->GetCurrent();
328  if (was_current) {
329  GetHolder()->SetCurrent(NULL);
330  }
332  if (visual->GetId()) {
333  base::LockGuard guard(GetVisualMapMutex());
334  VisualMap& visuals = GetVisualMap();
335  VisualMap::iterator it = visuals.find(visual->GetId());
336  DCHECK(it != visuals.end());
337  visuals.erase(it);
338  }
339 
340  if (visual->type_ == kNew) {
342  if (was_current) {
343  VisualInfo::ClearCurrentContext();
344  }
345  visual->TeardownContextNew();
346  } else if (visual->type_ == kShare) {
347  visual->TeardownContextShared();
348  } else {
350  }
351 }
352 
353 std::unique_ptr<Visual> Visual::CreateVisual() {
354  Visual* visual = new Visual(kNew);
355  visual->UpdateId();
356  RegisterVisual(visual);
357  return std::unique_ptr<Visual>(visual);
358 }
359 
360 std::unique_ptr<Visual> Visual::CreateVisualInCurrentShareGroup() {
361  const Visual* current = GetCurrent();
362  if (!current || !current->IsValid()) {
363  LOG(WARNING) << "GetCurrent() returned NULL or InValid()";
364  }
365  Visual* visual = current ? current->CreateVisualInShareGroup() : NULL;
366  if (visual) {
367  visual->UpdateId();
368  RegisterVisual(visual);
369  }
370  return std::unique_ptr<Visual>(visual);
371 }
372 
374  if (visual && visual->IsValid()) {
375  base::LockGuard guard(GetVisualMapMutex());
376  VisualMap& visuals = GetVisualMap();
377  visuals[visual->GetId()] = visual;
378  }
379 }
380 
382  DCHECK_EQ(this, GetCurrent());
383  return new Visual(kShare);
384 }
385 
386 #if defined(ION_PLATFORM_ANDROID) || defined(ION_PLATFORM_ASMJS) || \
387  defined(ION_PLATFORM_GENERIC_ARM) || defined(ION_ANGLE) || \
388  (defined(ION_PLATFORM_LINUX) && defined(ION_GFX_OGLES20))
389 
390 void Visual::VisualInfo::InitEgl(Visual::Type type) {
391  if (display == EGL_NO_DISPLAY) {
392  LOG(ERROR) << "Could not get EGL display";
393  return;
394  }
395 
396  EGLint major = 0;
397  EGLint minor = 0;
398  if (!eglInitialize(display, &major, &minor)) {
399  LOG(ERROR) << "Could not init EGL";
400  return;
401  }
402  if (major < 1 || minor < 2) {
403  LOG(ERROR) << "System does not support at least EGL 1.2";
404  return;
405  }
406 
407  if (type == kCurrent) {
408 #if defined(ION_PLATFORM_ASMJS)
409  context = reinterpret_cast<EGLContext>(EM_ASM_INT_V({
412  return Module.ctx ? 1 : 0;
413  }));
414 #else
415  surface = eglGetCurrentSurface(EGL_DRAW);
416  if (surface == EGL_NO_SURFACE)
417  LOG(ERROR) <<
418  "Unable to get current surface while creating a kCurrent Visual.";
419  context = eglGetCurrentContext();
420  if (context == EGL_NO_CONTEXT)
421  LOG(ERROR) <<
422  "Unable to get current context while creating a kCurrent Visual.";
423 #endif
424  } else {
425  EGLint attr[] = {
426  EGL_BUFFER_SIZE, 24,
427  EGL_RENDERABLE_TYPE,
428  EGL_OPENGL_ES2_BIT,
429  EGL_NONE
430  };
431 
432  EGLConfig ecfg;
433  EGLint num_config;
434  if (!eglChooseConfig(display, attr, &ecfg, 1, &num_config)) {
435  LOG(ERROR) << "Could not to choose config (egl code: " << eglGetError()
436  << ")";
437  return;
438  }
439 
440 #if defined(ION_PLATFORM_ANDROID) || defined(ION_PLATFORM_GENERIC_ARM) || \
441  (defined(ION_PLATFORM_LINUX) && defined(ION_GFX_OGLES20))
442  EGLint buffer_attr[] = {
446  EGL_WIDTH, 1,
447  EGL_HEIGHT, 1,
448  EGL_NONE
449  };
450  surface = eglCreatePbufferSurface(display, ecfg, buffer_attr);
451 #elif defined(ION_PLATFORM_ASMJS)
452  surface = eglCreateWindowSurface(display, ecfg, NULL, NULL);
453 #else
454  surface = eglCreateWindowSurface(display, ecfg, window, NULL);
455 #endif
456  if (surface == EGL_NO_SURFACE) {
457  LOG(ERROR) << "Could not create EGL surface (egl code: " << eglGetError()
458  << ")";
459  return;
460  }
461 
462  const EGLint ctxattr[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
463  const EGLContext share_context =
464  type == kShare ? eglGetCurrentContext() : EGL_NO_CONTEXT;
465  if (kShare == type && EGL_NO_CONTEXT == share_context) {
466  LOG(ERROR) << "Attempting to share a NULL context.";
467  }
468  context = eglCreateContext(display, ecfg, share_context, ctxattr);
469  if (context == EGL_NO_CONTEXT)
470  LOG(ERROR) << "Could not create EGL context (egl code: " << eglGetError()
471  << ").";
472  }
473 }
474 #endif
475 
476 #if defined(ION_PLATFORM_ANDROID) || defined(ION_PLATFORM_ASMJS) || \
477  defined(ION_PLATFORM_GENERIC_ARM) || \
478  (defined(ION_PLATFORM_LINUX) && defined(ION_GFX_OGLES20))
479 void* Visual::VisualInfo::GetCurrentContext() {
480 #if defined(ION_PLATFORM_ASMJS)
481  EGLContext context = reinterpret_cast<EGLContext>(EM_ASM_INT_V({
483  return Module.ctx ? 1 : 0;
484  }));
485  return context;
486 #else
487  return eglGetCurrentSurface(EGL_DRAW) != EGL_NO_SURFACE ?
488  eglGetCurrentContext() : NULL;
489 #endif
490 }
491 
492 void Visual::VisualInfo::ClearCurrentContext() {
493  eglMakeCurrent(eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY),
494  EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
495 }
496 
497 Visual::Visual(Type type)
498  : visual_(new VisualInfo), type_(type) {
499  visual_->display = eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY);
500  if (visual_->display == EGL_NO_DISPLAY)
501  return;
502  visual_->InitEgl(type);
503  if (type_ == kCurrent) {
504  MakeCurrent(this);
505  }
506 }
507 
508 Visual::Visual() : visual_(new VisualInfo), type_(kMock) {}
509 
510 bool Visual::IsValid() const {
511  return visual_->context;
512 }
513 
514 bool Visual::MakeCurrent() const {
515 #if defined(ION_PLATFORM_ASMJS)
516  return visual_->context != 0;
517 #endif
518  const EGLBoolean success = eglMakeCurrent(
519  visual_->display, visual_->surface, visual_->surface, visual_->context);
520  if (success == EGL_FALSE) {
521  LOG(ERROR) << "Unable to make Visual current.";
522  return false;
523  } else {
524  return true;
525  }
526 }
527 
529  eglDestroyContext(visual_->display, visual_->context);
530  eglDestroySurface(visual_->display, visual_->surface);
531  eglTerminate(visual_->display);
532 }
533 
535  if (eglGetCurrentContext() != visual_->context) {
536  eglDestroyContext(visual_->display, visual_->context);
537  }
538  if (eglGetCurrentSurface(EGL_DRAW) != visual_->surface) {
539  eglDestroySurface(visual_->display, visual_->surface);
540  }
541  if (eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY) !=
542  visual_->display) {
543  eglTerminate(visual_->display);
544  }
545 }
546 
547 Visual::~Visual() {
548  TeardownVisual(this);
549 }
550 
551 #elif defined(ION_PLATFORM_LINUX) && !defined(ION_GFX_OGLES20)
552 namespace {
553 
559 Display* OpenDisplay() {
560  static const int x_return_value =
561  system("pgrep -c '^Xorg$' >& /dev/null");
562  static const bool is_x_running =
563  x_return_value == 0;
564  static const bool is_system_working =
565  x_return_value != -1;
566  Display* display = nullptr;
567  if (is_x_running || !is_system_working) {
568  std::string display_name = port::GetEnvironmentVariableValue("DISPLAY");
569  if (!display_name.empty()) {
570  display = XOpenDisplay(display_name.c_str());
571  } else {
572  display = XOpenDisplay(":0");
573  }
574  }
575  return display;
576 }
577 
580 port::Mutex* GetXMutex() {
581  ION_DECLARE_SAFE_STATIC_POINTER(port::Mutex, mutex);
582  return mutex;
583 }
584 
585 } // anonymous namespace
586 
587 void* Visual::VisualInfo::GetCurrentContext() {
588  return glXGetCurrentContext();
589 }
590 
591 void Visual::VisualInfo::ClearCurrentContext() {
592  base::LockGuard guard(GetXMutex());
593  if (Display* display = OpenDisplay()) {
594  glXMakeCurrent(display, 0, NULL);
595  XCloseDisplay(display);
596  }
597 }
598 
599 Visual::Visual(Type type)
600  : visual_(new VisualInfo), type_(type) {
601  base::LockGuard guard(GetXMutex());
602  if (type == kCurrent) {
603  visual_->display = glXGetCurrentDisplay();
604  visual_->window = glXGetCurrentDrawable();
605  visual_->context = glXGetCurrentContext();
606  guard.Unlock();
607  MakeCurrent(this);
608  return;
609  } else {
611  visual_->display = OpenDisplay();
612  if (!visual_->display)
613  return;
614 
615  int error_base, event_base;
617  if (!glXQueryExtension(visual_->display, &error_base, &event_base)) {
620  visual_->context = NULL;
621  return;
622  }
623 
625  int attributes[] = { GLX_RGBA, 0 };
626  visual_->info = glXChooseVisual(
627  visual_->display, DefaultScreen(visual_->display), attributes);
628  if (!visual_->info)
629  return;
630 
632  GLXContext share_context = type == kShare ? glXGetCurrentContext() : NULL;
633  visual_->context =
634  glXCreateContext(visual_->display, visual_->info, share_context, True);
635  if (!visual_->context)
636  return;
637 
639  visual_->colormap = XCreateColormap(
640  visual_->display, RootWindow(visual_->display, visual_->info->screen),
641  visual_->info->visual, AllocNone);
642  XSetWindowAttributes window_attributes;
643  window_attributes.border_pixel = 0;
644  window_attributes.colormap = visual_->colormap;
645  visual_->window = XCreateWindow(
646  visual_->display, RootWindow(visual_->display, visual_->info->screen),
647  0, 0, 1, 1, 0, visual_->info->depth, InputOutput, visual_->info->visual,
648  CWBorderPixel | CWColormap, &window_attributes);
649  }
650 }
651 
652 Visual::Visual() : visual_(new VisualInfo), type_(kMock) {}
653 
654 bool Visual::IsValid() const {
655  return visual_->display && visual_->context && visual_->window;
656 }
657 
658 bool Visual::MakeCurrent() const {
659  const int success =
660  glXMakeCurrent(visual_->display, visual_->window, visual_->context);
661  if (!success) {
662  LOG(ERROR) << "Unable to make Visual current.";
663  return false;
664  } else {
665  return true;
666  }
667 }
668 
670  base::LockGuard guard(GetXMutex());
671 
672  if (visual_->context)
673  glXDestroyContext(visual_->display, visual_->context);
674  if (visual_->window)
675  XDestroyWindow(visual_->display, visual_->window);
676  if (visual_->colormap)
677  XFreeColormap(visual_->display, visual_->colormap);
678  if (visual_->info)
679  XFree(visual_->info);
680  if (visual_->display)
681  XCloseDisplay(visual_->display);
682 }
683 
685  base::LockGuard guard(GetXMutex());
686 
687  const Display* display = glXGetCurrentDisplay();
688  const Window window = glXGetCurrentDrawable();
689  const GLXContext context = glXGetCurrentContext();
690 
691  if (visual_->context && context != visual_->context)
692  glXDestroyContext(visual_->display, visual_->context);
693  if (visual_->window && window != visual_->window)
694  XDestroyWindow(visual_->display, visual_->window);
695  if (visual_->colormap)
696  XFreeColormap(visual_->display, visual_->colormap);
697  if (visual_->info)
698  XFree(visual_->info);
699  if (visual_->display && display != visual_->display)
700  XCloseDisplay(visual_->display);
701 }
702 
703 Visual::~Visual() {
704  TeardownVisual(this);
705 }
706 
707 #elif defined(ION_PLATFORM_NACL)
708 void* Visual::VisualInfo::GetCurrentContext() {
709  return reinterpret_cast<void*>(glGetCurrentContextPPAPI());
710 }
711 
712 void Visual::VisualInfo::ClearCurrentContext() {
713  glSetCurrentContextPPAPI(0);
714 }
715 
716 Visual::Visual(Type type)
717  : visual_(new VisualInfo), type_(type) {
718  if (type == kCurrent) {
719  visual_->context = glGetCurrentContextPPAPI();
720  MakeCurrent(this);
721  } else {
722  pp::Module* module = pp::Module::Get();
723  if (!module || !glInitializePPAPI(module->get_browser_interface())) {
724  LOG(ERROR) << "Unable to initialize GL PPAPI since there is no browser!";
725  return;
726  }
727 
728  const PPB_Graphics3D* interface = reinterpret_cast<const PPB_Graphics3D*>(
729  module->GetBrowserInterface(PPB_GRAPHICS_3D_INTERFACE));
730  if (!interface) {
731  LOG(ERROR) << "Unable to initialize PP Graphics3D interface!";
732  return;
733  }
734 
735  int32_t attribs[] = {
736  PP_GRAPHICS3DATTRIB_ALPHA_SIZE, 8,
737  PP_GRAPHICS3DATTRIB_DEPTH_SIZE, 24,
738  PP_GRAPHICS3DATTRIB_STENCIL_SIZE, 8,
739  PP_GRAPHICS3DATTRIB_NONE
740  };
741 
742  PP_Resource share_context =
743  type == kShare ? glGetCurrentContextPPAPI() : 0U;
744 
745  const pp::Module::InstanceMap& instances = module->current_instances();
746  for (pp::Module::InstanceMap::const_iterator iter = instances.begin();
747  iter != instances.end(); ++iter) {
749  if (pp::Instance* instance = iter->second) {
750  visual_->context =
751  interface->Create(instance->pp_instance(), share_context, attribs);
752  break;
753  }
754  }
755  }
756 }
757 
758 Visual::Visual() : visual_(new VisualInfo), type_(kMock) {}
759 
760 bool Visual::IsValid() const {
761  return visual_->context;
762 }
763 
764 bool Visual::MakeCurrent() const {
765  glSetCurrentContextPPAPI(visual_->context);
766  if (visual_->context != glGetCurrentContextPPAPI()) {
767  LOG(ERROR) << "Unable to make Visual current.";
768  return false;
769  } else {
770  return true;
771  }
772 }
773 
775  glTerminatePPAPI();
776 }
777 
779 }
780 
781 Visual::~Visual() {
782  TeardownVisual(this);
783 }
784 
785 #elif defined(ION_PLATFORM_WINDOWS)
786 void* Visual::VisualInfo::GetCurrentContext() {
787 # if defined(ION_ANGLE)
788  return eglGetCurrentContext();
789 # else
790  return wglGetCurrentContext();
791 # endif
792 }
793 
794 void Visual::VisualInfo::ClearCurrentContext() {
795 # if defined(ION_ANGLE)
796  eglMakeCurrent(eglGetDisplay((EGLNativeDisplayType)EGL_DEFAULT_DISPLAY),
797  EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
798 # else
799  wglMakeCurrent(nullptr, nullptr);
800 # endif
801 }
802 
803 Visual::Visual(Visual::Type type)
804  : visual_(new VisualInfo), type_(type) {
805  if (type == kCurrent) {
806 # if defined(ION_ANGLE)
807  visual_->context = eglGetCurrentContext();
808 # else
809  visual_->device_context = wglGetCurrentDC();
814  visual_->context = wglGetCurrentContext();
815 
818  DCHECK(visual_->device_context);
819  DCHECK(visual_->context);
820 # endif
821  MakeCurrent(this);
822  } else {
823  const DWORD dwExStyle = 0;
824  const LPCTSTR lpClassName = reinterpret_cast<LPCTSTR>(GetIonWindowClass());
825  const LPCTSTR lpWindowName = "ION";
826  const DWORD dwStyle = 0;
827  const int x = CW_USEDEFAULT;
828  const int y = CW_USEDEFAULT;
829  const int nWidth = CW_USEDEFAULT;
830  const int nHeight = CW_USEDEFAULT;
831  const HWND hWndParent = nullptr;
832  const HMENU hMenu = nullptr;
833  const HINSTANCE hInstance = GetModuleHandle(nullptr);
834  const LPVOID lpParam = nullptr;
835  visual_->window =
836  CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y,
837  nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
838  if (!visual_->window)
839  return;
840 
843  const HDC device_context = GetDC(visual_->window);
844  if (!device_context)
845  return;
846 
847  PIXELFORMATDESCRIPTOR format_descriptor;
848  memset(&format_descriptor, 0, sizeof(format_descriptor));
849  format_descriptor.nSize = sizeof(format_descriptor);
850  format_descriptor.nVersion = 1;
851  format_descriptor.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
852  format_descriptor.iPixelType = PFD_TYPE_RGBA;
853  format_descriptor.cColorBits = 24;
854  format_descriptor.cAlphaBits = 8;
855  format_descriptor.cDepthBits = 8;
856  format_descriptor.iLayerType = PFD_MAIN_PLANE;
857  const int pixel_format =
858  ChoosePixelFormat(device_context, &format_descriptor);
859  if (pixel_format == 0)
860  return;
861 
862  if (!SetPixelFormat(device_context, pixel_format, &format_descriptor))
863  return;
864 
865 #if defined(ION_ANGLE)
866  visual_->display = eglGetDisplay((EGLNativeDisplayType)device_context);
867  if (visual_->display == EGL_NO_DISPLAY)
868  if ((visual_->display = eglGetDisplay(
869  (EGLNativeDisplayType) EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY)
870  return;
871 
872  visual_->InitEgl(type);
873 
874 #else
875  visual_->context = wglCreateContext(device_context);
876  if (!visual_->context)
877  return;
878  if (type == kShare) {
879  const HGLRC share_context = wglGetCurrentContext();
880  wglShareLists(share_context, visual_->context);
881  }
882  visual_->device_context = device_context;
883 #endif
884  }
885 }
886 
887 Visual::Visual() : visual_(new VisualInfo), type_(kMock) {}
888 
889 bool Visual::IsValid() const { return visual_->context; }
890 
891 bool Visual::MakeCurrent() const {
892  bool succeeded = false;
893 # if defined(ION_ANGLE)
894  static const EGLBoolean kFailed = EGL_FALSE;
895  const EGLBoolean success = eglMakeCurrent(visual_->display, visual_->surface,
896  visual_->surface, visual_->context);
897 # else
898  static const BOOL kFailed = FALSE;
899  const BOOL success =
900  wglMakeCurrent(visual_->device_context, visual_->context);
901 # endif
902  if (success == kFailed) {
903  LOG(ERROR) << "Unable to make Visual current.";
904  return false;
905  } else {
906  return true;
907  }
908 }
909 
910 #if defined(ION_ANGLE)
912  eglDestroyContext(visual_->display, visual_->context);
913  eglDestroySurface(visual_->display, visual_->surface);
914  eglTerminate(visual_->display);
915 }
916 
919 }
920 #else
922  if (visual_->context)
923  wglDeleteContext(visual_->context);
926 }
927 
930 }
931 #endif
932 
933 Visual::~Visual() {
934  TeardownVisual(this);
935 
936  if (visual_->window) {
937  DestroyWindow(visual_->window);
938  }
939 }
940 
941 #elif !defined(ION_PLATFORM_IOS) && !defined(ION_PLATFORM_MAC)
942 void* Visual::VisualInfo::GetCurrentContext() { return NULL; }
943 void Visual::VisualInfo::ClearCurrentContext() {}
944 
947 Visual::Visual(Type type) : visual_(new VisualInfo), type_(type) {}
948 Visual::Visual() : visual_(new VisualInfo), type_(kMock) {}
949 bool Visual::IsValid() const { return false; }
950 void Visual::MakeCurrent() const {}
954  TeardownVisual(this);
955 }
956 #endif
957 
958 #if !defined(ION_PLATFORM_IOS) && !defined(ION_PLATFORM_MAC)
960  SetId(reinterpret_cast<size_t>(reinterpret_cast<void*>(visual_->context)));
961 }
962 #endif
963 
964 int Visual::GetGlVersion() const {
967  const char* version_string = NULL;
968  const char* dot_string = NULL;
969 
972  version_string = reinterpret_cast<const char*>(glGetString(GL_VERSION));
973  if (!version_string) {
974  LOG(WARNING) << "This system does not seem to support OpenGL.";
975  return 0;
976  }
977  if (ion::base::StartsWith(version_string, "WebGL"))
978  version_string = "2.0";
979  dot_string = strchr(version_string, '.');
980  if (!dot_string) {
981  LOG(WARNING) << "Unable to determine the OpenGL version.";
982  return 0;
983  }
984 
985  int major = 0;
986  int minor = 0;
987  major = dot_string[-1] - '0';
988  minor = dot_string[1] - '0';
989  return major * 10 + minor;
990 }
991 
993 #if defined(ION_PLATFORM_ANDROID) || defined(ION_PLATFORM_ASMJS) || \
994  defined(ION_PLATFORM_GENERIC_ARM) || defined(ION_ANGLE) || \
995  (defined(ION_PLATFORM_LINUX) && defined(ION_GFX_OGLES20))
996  const Visual* visual = GetCurrent();
997  if (visual->type_ != kMock) {
998  visual->visual_->surface = eglGetCurrentSurface(EGL_DRAW);
999  }
1000 #endif
1001 }
1002 
1003 } // namespace portgfx
1004 } // namespace ion
static void RefreshCurrentVisual()
Refreshes the current visual's internal state.
Definition: visual.cc:992
const std::string GetEnvironmentVariableValue(const std::string &name)
Returns the value of the named environment variable.
Definition: environment.cc:29
static bool MakeCurrent(const Visual *new_current)
Makes the passed Visual the current one for this thread.
Definition: visual.cc:266
virtual bool IsValid() const
Returns true if the OpenGL initialization was successful.
Definition: visual.cc:949
bool StartsWith(const std::string &target, const std::string &start)
Returns whether target begins with start.
Definition: stringutils.h:76
static void RegisterVisual(Visual *visual)
Registers the passed Visual in the global list.
Definition: visual.cc:373
#define ION_DECLARE_SAFE_STATIC_POINTER(type, variable)
Declare a static non-array pointer and calls a default constructor.
std::string type
Definition: printer.cc:353
static size_t GetCurrentId()
Returns a unique ID for the currently bound Visual.
Definition: visual.cc:313
static const Visual * GetCurrent()
Returns the Visual that is current for the calling thread.
Definition: visual.cc:213
#define DCHECK(expr)
Definition: logging.h:331
GenericLockGuard< port::Mutex > LockGuard
Convenient typedefs for ion::port::Mutex.
Definition: lockguards.h:192
double value
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
Definition: logging.h:216
virtual void UpdateId()
Updates this' ID in a platform dependent way.
Definition: visual.cc:959
Visual()
Constructor for subclasses that make their own contexts.
Definition: visual.cc:948
uint32 id
static void DestroyWrappingVisual(const Visual *visual)
If the passed Visual wraps a GL context not created by Ion, the Visual is destroyed; the passed point...
Definition: visual.cc:291
A LockGuard locks a mutex when created, and unlocks it when destroyed.
Definition: lockguards.h:90
virtual void TeardownContextNew()
Destroy Visuals of type kNew.
Definition: visual.cc:951
virtual Visual * CreateVisualInShareGroup() const
Return a newly-instantiated Visual in the same share group as this Visual.
Definition: visual.cc:381
virtual ~Visual()
OpenGL calls should not be made after the Visual is destroyed.
Definition: visual.cc:953
virtual void TeardownContextShared()
Destroy Visuals of type kShare.
Definition: visual.cc:952
static std::unique_ptr< Visual > CreateVisualInCurrentShareGroup()
Creates a new Visual in the same share group as the current Visual.
Definition: visual.cc:360
size_t GetId() const
Returns the ID associated with this Visual.
Definition: visual.h:54
Copyright 2016 Google Inc.
static std::unique_ptr< Visual > CreateVisual()
Creates a new Visual that is not in a share group.
Definition: visual.cc:353
Opaque class that sets up an offscreen OpenGL context/surface/visual in a platform-specific way to al...
Definition: visual.h:40
#define DCHECK_EQ(val1, val2)
Definition: logging.h:332
virtual bool MakeCurrent() const
Makes this Visual current for this thread and returns whether its associated GL context was successfu...
Definition: visual.cc:950
static void TeardownVisual(Visual *visual)
Responsible for cleaning up |visual's| resources.
Definition: visual.cc:325
int GetGlVersion() const
Returns the major and minor OpenGL version without a decimal point, e.g.
Definition: visual.cc:964
void SetId(size_t id)
Sets the ID of this.
Definition: visual.h:127
const Visual * current_
Definition: visual.cc:82