OLD | NEW |
| (Empty) |
1 // Copyright 2010 The Ginsu Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can | |
3 // be found in the LICENSE file. | |
4 | |
5 #include "c_salt/opengl_context.h" | |
6 | |
7 #include <pthread.h> | |
8 | |
9 #include <cassert> | |
10 #include <cstring> | |
11 #include <map> | |
12 #include <sstream> | |
13 | |
14 #include "c_salt/browser_3d_device.h" | |
15 #include "c_salt/instance.h" | |
16 #include "c_salt/module.h" | |
17 #include "c_salt/notification_center.h" | |
18 | |
19 namespace c_salt { | |
20 | |
21 // Map the platform-specific context handle to an instance of OpenGLContext. | |
22 // This map is lazily allocated on the heap. | |
23 typedef std::map<PGLContext, SharedOpenGLContext> ContextDictionary; | |
24 static ContextDictionary* g_context_dictionary = NULL; | |
25 static pthread_mutex_t g_context_dict_lock = PTHREAD_MUTEX_INITIALIZER; | |
26 | |
27 const char* const OpenGLContext::kInitializeOpenGLContextNotification = | |
28 "kInitializeOpenGLContext.OpenGLContext.c_salt"; | |
29 const char* const OpenGLContext::kDeleteOpenGLContextNotification = | |
30 "kDeleteOpenGLContext.OpenGLContext.c_salt"; | |
31 const char* const OpenGLContext::kRenderOpenGLContextNotification = | |
32 "kRenderOpenGLContext.OpenGLContext.c_salt"; | |
33 | |
34 OpenGLContext::OpenGLContext(const Instance& instance) | |
35 : instance_(instance), | |
36 pgl_context_(PGL_NO_CONTEXT), | |
37 browser_device_(CreateBrowser3DDevice(instance)) { | |
38 std::stringstream instance_name; | |
39 instance_name << this << ".OpenGLContext.c_salt"; | |
40 instance_name_ = instance_name.str(); | |
41 } | |
42 | |
43 OpenGLContext::~OpenGLContext() { | |
44 DeleteContext(); | |
45 } | |
46 | |
47 void OpenGLContext::DeleteContext() { | |
48 if (!is_valid()) | |
49 return; | |
50 // Make this context current before posting the "will destroy context" | |
51 // notification. This means that any context tear-down code in observers | |
52 // will operate on this context. | |
53 MakeContextCurrent(); | |
54 PostNotification(kDeleteOpenGLContextNotification); | |
55 pglMakeCurrent(PGL_NO_CONTEXT); | |
56 DestroyPGLContext(); | |
57 } | |
58 | |
59 SharedOpenGLContext OpenGLContext::CurrentContext() { | |
60 SharedOpenGLContext current_context; | |
61 PGLContext current_pgl_context = pglGetCurrentContext(); | |
62 if (g_context_dictionary != NULL && | |
63 current_pgl_context != PGL_NO_CONTEXT) { | |
64 pthread_mutex_lock(&g_context_dict_lock); | |
65 ContextDictionary::const_iterator iter = | |
66 g_context_dictionary->find(current_pgl_context); | |
67 if (iter != g_context_dictionary->end()) | |
68 current_context = iter->second; | |
69 pthread_mutex_unlock(&g_context_dict_lock); | |
70 } | |
71 return current_context; | |
72 } | |
73 | |
74 bool OpenGLContext::MakeContextCurrent() { | |
75 bool new_context_created = false; | |
76 if (!is_valid()) { | |
77 // If this is the first attempt at making the context current, perform all | |
78 // the 3D device initialization. | |
79 browser_device_->AcquireBrowser3DDevice(); | |
80 // Create an OpenGL device in the instance. | |
81 c_salt::Module& module = c_salt::Module::GetModuleSingleton(); | |
82 if (module.InitializeOpenGL()) { | |
83 new_context_created = CreatePGLContext(); | |
84 } | |
85 if (!is_valid()) { | |
86 return false; | |
87 } | |
88 } | |
89 bool success = pglMakeCurrent(pgl_context_) == PGL_TRUE; | |
90 if (!success && pglGetError() == PGL_CONTEXT_LOST) { | |
91 // If the browser context was lost, attempt to create a new one. Note that | |
92 // CreatePGLContext() will set |new_context_created| to |true|, so that | |
93 // observers can have a chance to re-initialize OpenGL resources if needed. | |
94 DestroyPGLContext(); | |
95 new_context_created = CreatePGLContext(); | |
96 success = pglMakeCurrent(pgl_context_) == PGL_TRUE; | |
97 } | |
98 if (new_context_created && success) { | |
99 PostNotification(kInitializeOpenGLContextNotification); | |
100 } | |
101 return success; | |
102 } | |
103 | |
104 void OpenGLContext::FlushContext() const { | |
105 pglSwapBuffers(); | |
106 } | |
107 | |
108 void OpenGLContext::RenderContext() { | |
109 if (!MakeContextCurrent()) | |
110 return; | |
111 PostNotification(kRenderOpenGLContextNotification); | |
112 FlushContext(); | |
113 } | |
114 | |
115 bool OpenGLContext::CreatePGLContext() { | |
116 if (is_valid()) | |
117 return true; // Nothing to do here. | |
118 // Create a PGL context. | |
119 pgl_context_ = browser_device_->CreateBrowser3DContext(this); | |
120 if (pgl_context_ == PGL_NO_CONTEXT) | |
121 return false; | |
122 pthread_mutex_lock(&g_context_dict_lock); | |
123 if (!g_context_dictionary) { | |
124 g_context_dictionary = new ContextDictionary(); | |
125 } | |
126 SharedOpenGLContext shared_context(this); | |
127 g_context_dictionary->insert( | |
128 ContextDictionary::value_type(pgl_context_, shared_context)); | |
129 pthread_mutex_unlock(&g_context_dict_lock); | |
130 return true; | |
131 } | |
132 | |
133 void OpenGLContext::DestroyPGLContext() { | |
134 assert(is_valid()); | |
135 assert(g_context_dictionary); | |
136 if (g_context_dictionary) { | |
137 pthread_mutex_lock(&g_context_dict_lock); | |
138 ContextDictionary::iterator iter = | |
139 g_context_dictionary->find(pgl_context_); | |
140 if (iter != g_context_dictionary->end()) | |
141 g_context_dictionary->erase(iter); | |
142 pthread_mutex_unlock(&g_context_dict_lock); | |
143 } | |
144 pglDestroyContext(pgl_context_); | |
145 pgl_context_ = PGL_NO_CONTEXT; | |
146 browser_device_->DeleteBrowser3DContext(); | |
147 } | |
148 | |
149 void OpenGLContext::PostNotification(const char* const notification_name) | |
150 const { | |
151 NotificationCenter* default_center = | |
152 NotificationCenter::DefaultCenter(instance()); | |
153 if (default_center == NULL) | |
154 return; | |
155 default_center->PublishNotification(notification_name, | |
156 Notification(notification_name), | |
157 instance_name_); | |
158 } | |
159 } // namespace c_salt | |
OLD | NEW |