21 #if defined(ION_PLATFORM_WINDOWS)
26 # undef ERROR // This is defined in Windows headers.
32 #if defined(ION_PLATFORM_ASMJS)
33 # include <emscripten.h>
38 #include <unordered_map>
42 #if defined(ION_PLATFORM_LINUX) && !defined(ION_GFX_OGLES20)
44 # undef None // Defined in X.h, but reused in gtest.h.
45 # undef Bool // Defined in X.h, but reused in gtest.h.
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"
78 const Visual* GetCurrent()
const {
return current_; }
86 static VisualStorage* GetHolder() {
89 return s_helper->Get();
102 typedef std::unordered_map<size_t, const Visual*> VisualMap;
105 static VisualMap& GetVisualMap() {
111 static port::Mutex* GetVisualMapMutex() {
116 #if defined(ION_PLATFORM_WINDOWS)
119 class 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);
132 ~IonWindowClass() { UnregisterClass(kClassName, GetModuleHandle(
nullptr)); }
134 ATOM GetAtom()
const {
return atom_; }
137 static const char kClassName[];
142 const char IonWindowClass::kClassName[] =
"ION";
144 ATOM GetIonWindowClass() {
146 return window_class->GetAtom();
153 struct Visual::VisualInfo {
158 static void* GetCurrentContext();
160 static void ClearCurrentContext();
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))
169 void InitEgl(Type
type);
173 #elif defined(ION_PLATFORM_LINUX)
185 #elif defined(ION_PLATFORM_NACL)
186 VisualInfo() : context(0) {}
188 #elif defined(ION_PLATFORM_WINDOWS)
190 # if defined(ION_ANGLE)
195 : device_context(
nullptr),
200 # if defined(ION_ANGLE)
201 void InitEgl(Type
type);
218 if (current && current->type_ == kMock)
224 const size_t id =
reinterpret_cast<size_t>(VisualInfo::GetCurrentContext());
225 if (current &&
id == current->
GetId()) {
234 VisualMap& visuals = GetVisualMap();
239 VisualMap::iterator it = visuals.find(
id);
240 if (it != visuals.end())
241 current = it->second;
245 GetHolder()->SetCurrent(current);
250 DCHECK(visuals.find(
id) == visuals.end());
252 new_visual->UpdateId();
253 current = new_visual;
255 visuals[
id] = new_visual;
260 GetHolder()->SetCurrent(
nullptr);
269 GetHolder()->SetCurrent(NULL);
270 if (current->type_ != kMock) {
271 VisualInfo::ClearCurrentContext();
275 }
else if (new_visual->
IsValid()) {
278 GetHolder()->SetCurrent(new_visual);
280 GetHolder()->SetCurrent(NULL);
284 LOG(
WARNING) <<
"Failed to make Visual current: " << new_visual;
293 const Visual* visual_to_delete = NULL;
295 VisualMap& visuals = GetVisualMap();
300 VisualMap::iterator it = visuals.find(visual->
GetId());
301 if (it != visuals.end()) {
304 if (visual->type_ == kCurrent)
305 visual_to_delete = it->second;
308 if (visual_to_delete)
309 delete visual_to_delete;
319 if (ptr && ptr->type_ == kMock) {
322 return reinterpret_cast<size_t>(VisualInfo::GetCurrentContext());
327 const bool was_current = visual == GetHolder()->
GetCurrent();
329 GetHolder()->SetCurrent(NULL);
332 if (visual->
GetId()) {
334 VisualMap& visuals = GetVisualMap();
335 VisualMap::iterator it = visuals.find(visual->
GetId());
336 DCHECK(it != visuals.end());
340 if (visual->type_ == kNew) {
343 VisualInfo::ClearCurrentContext();
346 }
else if (visual->type_ == kShare) {
357 return std::unique_ptr<Visual>(visual);
362 if (!current || !current->
IsValid()) {
363 LOG(
WARNING) <<
"GetCurrent() returned NULL or InValid()";
370 return std::unique_ptr<Visual>(visual);
374 if (visual && visual->
IsValid()) {
376 VisualMap& visuals = GetVisualMap();
377 visuals[visual->
GetId()] = visual;
383 return new Visual(kShare);
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))
390 void Visual::VisualInfo::InitEgl(Visual::Type
type) {
391 if (display == EGL_NO_DISPLAY) {
392 LOG(
ERROR) <<
"Could not get EGL display";
398 if (!eglInitialize(display, &major, &minor)) {
402 if (major < 1 || minor < 2) {
403 LOG(
ERROR) <<
"System does not support at least EGL 1.2";
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;
415 surface = eglGetCurrentSurface(EGL_DRAW);
416 if (surface == EGL_NO_SURFACE)
418 "Unable to get current surface while creating a kCurrent Visual.";
419 context = eglGetCurrentContext();
420 if (context == EGL_NO_CONTEXT)
422 "Unable to get current context while creating a kCurrent Visual.";
434 if (!eglChooseConfig(display, attr, &ecfg, 1, &num_config)) {
435 LOG(
ERROR) <<
"Could not to choose config (egl code: " << eglGetError()
440 #if defined(ION_PLATFORM_ANDROID) || defined(ION_PLATFORM_GENERIC_ARM) || \
441 (defined(ION_PLATFORM_LINUX) && defined(ION_GFX_OGLES20))
442 EGLint buffer_attr[] = {
450 surface = eglCreatePbufferSurface(display, ecfg, buffer_attr);
451 #elif defined(ION_PLATFORM_ASMJS)
452 surface = eglCreateWindowSurface(display, ecfg, NULL, NULL);
454 surface = eglCreateWindowSurface(display, ecfg, window, NULL);
456 if (surface == EGL_NO_SURFACE) {
457 LOG(
ERROR) <<
"Could not create EGL surface (egl code: " << eglGetError()
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.";
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()
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;
487 return eglGetCurrentSurface(EGL_DRAW) != EGL_NO_SURFACE ?
488 eglGetCurrentContext() : NULL;
492 void Visual::VisualInfo::ClearCurrentContext() {
493 eglMakeCurrent(eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY),
494 EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
498 : visual_(new VisualInfo), type_(type) {
499 visual_->display = eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY);
500 if (visual_->display == EGL_NO_DISPLAY)
502 visual_->InitEgl(type);
503 if (type_ == kCurrent) {
511 return visual_->context;
515 #if defined(ION_PLATFORM_ASMJS)
516 return visual_->context != 0;
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.";
529 eglDestroyContext(visual_->display, visual_->context);
530 eglDestroySurface(visual_->display, visual_->surface);
531 eglTerminate(visual_->display);
535 if (eglGetCurrentContext() != visual_->context) {
536 eglDestroyContext(visual_->display, visual_->context);
538 if (eglGetCurrentSurface(EGL_DRAW) != visual_->surface) {
539 eglDestroySurface(visual_->display, visual_->surface);
541 if (eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY) !=
543 eglTerminate(visual_->display);
551 #elif defined(ION_PLATFORM_LINUX) && !defined(ION_GFX_OGLES20)
559 Display* OpenDisplay() {
560 static const int x_return_value =
561 system(
"pgrep -c '^Xorg$' >& /dev/null");
562 static const bool is_x_running =
564 static const bool is_system_working =
565 x_return_value != -1;
566 Display* display =
nullptr;
567 if (is_x_running || !is_system_working) {
569 if (!display_name.empty()) {
570 display = XOpenDisplay(display_name.c_str());
572 display = XOpenDisplay(
":0");
580 port::Mutex* GetXMutex() {
587 void* Visual::VisualInfo::GetCurrentContext() {
588 return glXGetCurrentContext();
591 void Visual::VisualInfo::ClearCurrentContext() {
593 if (Display* display = OpenDisplay()) {
594 glXMakeCurrent(display, 0, NULL);
595 XCloseDisplay(display);
600 : visual_(new VisualInfo), type_(type) {
602 if (type == kCurrent) {
603 visual_->display = glXGetCurrentDisplay();
604 visual_->window = glXGetCurrentDrawable();
605 visual_->context = glXGetCurrentContext();
611 visual_->display = OpenDisplay();
612 if (!visual_->display)
615 int error_base, event_base;
617 if (!glXQueryExtension(visual_->display, &error_base, &event_base)) {
620 visual_->context = NULL;
625 int attributes[] = { GLX_RGBA, 0 };
626 visual_->info = glXChooseVisual(
627 visual_->display, DefaultScreen(visual_->display), attributes);
632 GLXContext share_context = type == kShare ? glXGetCurrentContext() : NULL;
634 glXCreateContext(visual_->display, visual_->info, share_context, True);
635 if (!visual_->context)
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);
655 return visual_->display && visual_->context && visual_->window;
660 glXMakeCurrent(visual_->display, visual_->window, visual_->context);
662 LOG(
ERROR) <<
"Unable to make Visual current.";
672 if (visual_->context)
673 glXDestroyContext(visual_->display, visual_->context);
675 XDestroyWindow(visual_->display, visual_->window);
676 if (visual_->colormap)
677 XFreeColormap(visual_->display, visual_->colormap);
679 XFree(visual_->info);
680 if (visual_->display)
681 XCloseDisplay(visual_->display);
687 const Display* display = glXGetCurrentDisplay();
688 const Window window = glXGetCurrentDrawable();
689 const GLXContext context = glXGetCurrentContext();
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);
698 XFree(visual_->info);
699 if (visual_->display && display != visual_->display)
700 XCloseDisplay(visual_->display);
707 #elif defined(ION_PLATFORM_NACL)
708 void* Visual::VisualInfo::GetCurrentContext() {
709 return reinterpret_cast<void*
>(glGetCurrentContextPPAPI());
712 void Visual::VisualInfo::ClearCurrentContext() {
713 glSetCurrentContextPPAPI(0);
717 : visual_(new VisualInfo), type_(type) {
718 if (type == kCurrent) {
719 visual_->context = glGetCurrentContextPPAPI();
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!";
728 const PPB_Graphics3D*
interface = reinterpret_cast<const PPB_Graphics3D*>(
729 module->GetBrowserInterface(PPB_GRAPHICS_3D_INTERFACE));
731 LOG(
ERROR) <<
"Unable to initialize PP Graphics3D interface!";
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
742 PP_Resource share_context =
743 type == kShare ? glGetCurrentContextPPAPI() : 0U;
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) {
751 interface->Create(instance->pp_instance(), share_context, attribs);
761 return visual_->context;
765 glSetCurrentContextPPAPI(visual_->context);
766 if (visual_->context != glGetCurrentContextPPAPI()) {
767 LOG(
ERROR) <<
"Unable to make Visual current.";
785 #elif defined(ION_PLATFORM_WINDOWS)
786 void* Visual::VisualInfo::GetCurrentContext() {
787 # if defined(ION_ANGLE)
788 return eglGetCurrentContext();
790 return wglGetCurrentContext();
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);
799 wglMakeCurrent(
nullptr,
nullptr);
804 : visual_(new VisualInfo), type_(type) {
805 if (type == kCurrent) {
806 # if defined(ION_ANGLE)
807 visual_->context = eglGetCurrentContext();
809 visual_->device_context = wglGetCurrentDC();
814 visual_->context = wglGetCurrentContext();
818 DCHECK(visual_->device_context);
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;
836 CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y,
837 nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam);
838 if (!visual_->window)
843 const HDC device_context = GetDC(visual_->window);
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)
862 if (!SetPixelFormat(device_context, pixel_format, &format_descriptor))
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)
872 visual_->InitEgl(type);
875 visual_->context = wglCreateContext(device_context);
876 if (!visual_->context)
878 if (type == kShare) {
879 const HGLRC share_context = wglGetCurrentContext();
880 wglShareLists(share_context, visual_->context);
882 visual_->device_context = device_context;
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);
898 static const BOOL kFailed = FALSE;
900 wglMakeCurrent(visual_->device_context, visual_->context);
902 if (success == kFailed) {
903 LOG(
ERROR) <<
"Unable to make Visual current.";
910 #if defined(ION_ANGLE)
912 eglDestroyContext(visual_->display, visual_->context);
913 eglDestroySurface(visual_->display, visual_->surface);
914 eglTerminate(visual_->display);
922 if (visual_->context)
923 wglDeleteContext(visual_->context);
936 if (visual_->window) {
937 DestroyWindow(visual_->window);
941 #elif !defined(ION_PLATFORM_IOS) && !defined(ION_PLATFORM_MAC)
942 void* Visual::VisualInfo::GetCurrentContext() {
return NULL; }
943 void Visual::VisualInfo::ClearCurrentContext() {}
947 Visual::Visual(Type type) : visual_(new VisualInfo), type_(type) {}
958 #if !defined(ION_PLATFORM_IOS) && !defined(ION_PLATFORM_MAC)
960 SetId(reinterpret_cast<size_t>(reinterpret_cast<void*>(visual_->context)));
967 const char* version_string = NULL;
968 const char* dot_string = NULL;
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.";
978 version_string =
"2.0";
979 dot_string = strchr(version_string,
'.');
981 LOG(
WARNING) <<
"Unable to determine the OpenGL version.";
987 major = dot_string[-1] -
'0';
988 minor = dot_string[1] -
'0';
989 return major * 10 + minor;
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))
997 if (visual->type_ != kMock) {
998 visual->visual_->surface = eglGetCurrentSurface(EGL_DRAW);
static void RefreshCurrentVisual()
Refreshes the current visual's internal state.
const std::string GetEnvironmentVariableValue(const std::string &name)
Returns the value of the named environment variable.
static bool MakeCurrent(const Visual *new_current)
Makes the passed Visual the current one for this thread.
virtual bool IsValid() const
Returns true if the OpenGL initialization was successful.
bool StartsWith(const std::string &target, const std::string &start)
Returns whether target begins with start.
static void RegisterVisual(Visual *visual)
Registers the passed Visual in the global list.
#define ION_DECLARE_SAFE_STATIC_POINTER(type, variable)
Declare a static non-array pointer and calls a default constructor.
static size_t GetCurrentId()
Returns a unique ID for the currently bound Visual.
static const Visual * GetCurrent()
Returns the Visual that is current for the calling thread.
GenericLockGuard< port::Mutex > LockGuard
Convenient typedefs for ion::port::Mutex.
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
virtual void UpdateId()
Updates this' ID in a platform dependent way.
Visual()
Constructor for subclasses that make their own contexts.
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...
A LockGuard locks a mutex when created, and unlocks it when destroyed.
virtual void TeardownContextNew()
Destroy Visuals of type kNew.
virtual Visual * CreateVisualInShareGroup() const
Return a newly-instantiated Visual in the same share group as this Visual.
virtual ~Visual()
OpenGL calls should not be made after the Visual is destroyed.
virtual void TeardownContextShared()
Destroy Visuals of type kShare.
static std::unique_ptr< Visual > CreateVisualInCurrentShareGroup()
Creates a new Visual in the same share group as the current Visual.
size_t GetId() const
Returns the ID associated with this Visual.
Copyright 2016 Google Inc.
static std::unique_ptr< Visual > CreateVisual()
Creates a new Visual that is not in a share group.
Opaque class that sets up an offscreen OpenGL context/surface/visual in a platform-specific way to al...
#define DCHECK_EQ(val1, val2)
virtual bool MakeCurrent() const
Makes this Visual current for this thread and returns whether its associated GL context was successfu...
static void TeardownVisual(Visual *visual)
Responsible for cleaning up |visual's| resources.
int GetGlVersion() const
Returns the major and minor OpenGL version without a decimal point, e.g.
void SetId(size_t id)
Sets the ID of this.