OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011 Apple Inc. All rights reserved. | 2 * Copyright (C) 2011 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
11 * documentation and/or other materials provided with the distribution. | 11 * documentation and/or other materials provided with the distribution. |
12 * | 12 * |
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY | 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR | 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 */ | 24 */ |
25 | 25 |
26 #include "config.h" | 26 #include "config.h" |
27 | 27 |
28 #include "core/html/canvas/WebGLSharedObject.h" | 28 #include "core/html/canvas/WebGLSharedObject.h" |
29 | 29 |
| 30 #include "core/html/canvas/WebGLAcquireSharedResourceCallback.h" |
30 #include "core/html/canvas/WebGLContextGroup.h" | 31 #include "core/html/canvas/WebGLContextGroup.h" |
31 #include "core/html/canvas/WebGLRenderingContext.h" | 32 #include "core/html/canvas/WebGLRenderingContext.h" |
32 | 33 |
33 namespace WebCore { | 34 namespace WebCore { |
34 | 35 |
35 WebGLSharedObject::WebGLSharedObject(WebGLRenderingContext* context) | 36 WebGLSharedObject::WebGLSharedObject(WebGLRenderingContext* context) |
36 : WebGLObject(context), | 37 : WebGLObject(context) |
37 m_contextGroup(context->contextGroup()) | 38 , m_contextGroup(context->contextGroup()) |
| 39 , m_acquireMode(WebGLSharedObject::Unacquired) |
38 { | 40 { |
| 41 bool success = acquire(WebGLSharedObject::Exclusive, context); |
| 42 ASSERT(success); |
| 43 |
| 44 // We need to mark shaders and programs as bound as there is no way to easy
way to bind/attach them. |
| 45 markAsBoundSinceLastAcquireForContext(context); |
39 } | 46 } |
40 | 47 |
41 WebGLSharedObject::~WebGLSharedObject() | 48 WebGLSharedObject::~WebGLSharedObject() |
42 { | 49 { |
43 if (m_contextGroup) | 50 if (m_contextGroup) { |
44 m_contextGroup->removeObject(this); | 51 m_contextGroup->removeObject(this); |
| 52 } |
45 } | 53 } |
46 | 54 |
47 void WebGLSharedObject::detachContextGroup() | 55 void WebGLSharedObject::detachContextGroup() |
48 { | 56 { |
49 detach(); | 57 detach(); |
50 if (m_contextGroup) { | 58 if (m_contextGroup) { |
51 deleteObject(0); | 59 deleteObject(0); |
52 m_contextGroup->removeObject(this); | 60 m_contextGroup->removeObject(this); |
53 m_contextGroup = 0; | 61 m_contextGroup = 0; |
54 } | 62 } |
55 } | 63 } |
56 | 64 |
57 GraphicsContext3D* WebGLSharedObject::getAGraphicsContext3D() const | 65 GraphicsContext3D* WebGLSharedObject::getAGraphicsContext3D() const |
58 { | 66 { |
59 return m_contextGroup ? m_contextGroup->getAGraphicsContext3D() : 0; | 67 return m_contextGroup ? m_contextGroup->getAGraphicsContext3D() : 0; |
60 } | 68 } |
61 | 69 |
62 } | 70 bool WebGLSharedObject::isAcquiredForContext(const WebGLRenderingContext* contex
t, WebGLSharedObject::AcquireMode neededMode, bool mustBeBoundSinceLastAcquire,
bool* hasBeenBoundSinceLastAcquire, const char** reason) const |
| 71 { |
| 72 AcquireContextMap::const_iterator it = m_acquireContextMap.find(context); |
| 73 if (it == m_acquireContextMap.end()) { |
| 74 *reason = " not acquired in this context"; |
| 75 return false; |
| 76 } |
| 77 |
| 78 bool sameMode = m_acquireMode == neededMode; |
| 79 bool validCombo = m_acquireMode == WebGLSharedObject::Exclusive && neededMod
e == WebGLSharedObject::ReadOnly; |
| 80 if (!sameMode && !validCombo) { |
| 81 *reason = " not acquired for exclusive access"; |
| 82 return false; |
| 83 } |
| 84 |
| 85 if (mustBeBoundSinceLastAcquire && !it->value) { |
| 86 *reason = " has not been bound since last acquired"; |
| 87 return false; |
| 88 } |
| 89 |
| 90 if (hasBeenBoundSinceLastAcquire) { |
| 91 *hasBeenBoundSinceLastAcquire = it->value; |
| 92 } |
| 93 |
| 94 return true; |
| 95 } |
| 96 |
| 97 bool WebGLSharedObject::validate(const char* functionName, WebGLRenderingContext
* context, WebGLSharedObject::AcquireMode neededMode, bool mustBeBoundSinceLastA
cquire, bool* boundSinceLastAcquire) const |
| 98 { |
| 99 if (context->contextGroup() != m_contextGroup) { |
| 100 String msg(String(typeName()) + " not from this share group"); |
| 101 context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functio
nName, msg.utf8().data()); |
| 102 return false; |
| 103 } |
| 104 |
| 105 const char* reason; |
| 106 if (!isAcquiredForContext(context, neededMode, mustBeBoundSinceLastAcquire,
boundSinceLastAcquire, &reason)) { |
| 107 String msg(String(typeName()) + reason); |
| 108 context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functio
nName, msg.utf8().data()); |
| 109 return false; |
| 110 } |
| 111 |
| 112 return true; |
| 113 } |
| 114 |
| 115 void WebGLSharedObject::markAsBoundSinceLastAcquireForContext(const WebGLRenderi
ngContext* context) |
| 116 { |
| 117 AcquireContextMap::iterator it = m_acquireContextMap.find(context); |
| 118 ASSERT(it != m_acquireContextMap.end()); |
| 119 it->value = true; |
| 120 } |
| 121 |
| 122 bool WebGLSharedObject::acquire(WebGLSharedObject::AcquireMode desiredMode, cons
t WebGLRenderingContext* context) |
| 123 { |
| 124 AcquireContextMap::const_iterator it = m_acquireContextMap.find(context); |
| 125 if (it != m_acquireContextMap.end()) { |
| 126 // How can I get here? |
| 127 return false; |
| 128 } |
| 129 |
| 130 bool unacquired = m_acquireMode == WebGLSharedObject::Unacquired; |
| 131 bool bothReadOnly = m_acquireMode == WebGLSharedObject::ReadOnly && desiredM
ode == WebGLSharedObject::ReadOnly; |
| 132 if (!unacquired && !bothReadOnly) { |
| 133 return false; |
| 134 } |
| 135 |
| 136 // Note: The resource is acquired at this point. The user may still cancel |
| 137 // the request though before it the acquire callback is fired. If it is |
| 138 // cancelled the cancel acts as a call to release. |
| 139 m_acquireMode = desiredMode; |
| 140 m_acquireContextMap.add(context, false); |
| 141 return true; |
| 142 } |
| 143 |
| 144 bool WebGLSharedObject::addAcquireRequest(WebGLRenderingContext* context, WebGLS
haredObject::AcquireMode desiredMode, PassRefPtr<WebGLAcquireSharedResourceCallb
ack> callback, long& id) |
| 145 { |
| 146 switch (desiredMode) { |
| 147 case WebGLSharedObject::ReadOnly: |
| 148 case WebGLSharedObject::Exclusive: |
| 149 break; |
| 150 default: |
| 151 context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "acquireShar
edResource", "mode is not READ_ONLY or EXCLUSIVE"); |
| 152 return false; |
| 153 } |
| 154 |
| 155 // Checks the object belongs to this group. |
| 156 // Note: We let lost objects go through here. |
| 157 if (context->contextGroup() != m_contextGroup && !isLost()) { |
| 158 context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "acquir
eSharedResource", "object is not from this ShareGroup"); |
| 159 return false; |
| 160 } |
| 161 |
| 162 // Checks it is not already acquired by this context. |
| 163 AcquireContextMap::iterator it = m_acquireContextMap.find(context); |
| 164 if (it != m_acquireContextMap.end()) { |
| 165 context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "acquir
eSharedResource", "object is already acquired in this context"); |
| 166 return false; |
| 167 } |
| 168 |
| 169 // Checks it is not already in one of the queues. |
| 170 if (isRequestPending(context)) { |
| 171 context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "acquir
eSharedResource", "request to acquire this object is already pending in this con
text"); |
| 172 return false; |
| 173 } |
| 174 |
| 175 // Adds the request. |
| 176 id = generateAcquireRequestId(); |
| 177 m_acquireRequestQueue.append(WebGLAcquireSharedResourceRequest::create(this,
callback, desiredMode, context, id)); |
| 178 processAcquireRequests(); |
| 179 return true; |
| 180 } |
| 181 |
| 182 bool WebGLSharedObject::release(WebGLRenderingContext* context) |
| 183 { |
| 184 AcquireContextMap::iterator it = m_acquireContextMap.find(context); |
| 185 if (it == m_acquireContextMap.end()) { |
| 186 return false; |
| 187 } |
| 188 |
| 189 m_acquireContextMap.remove(it); |
| 190 if (m_acquireContextMap.isEmpty()) { |
| 191 if (m_acquireMode == WebGLSharedObject::Exclusive) { |
| 192 // TODO: Use flush if on top of virtual contexts (maybe we should ha
ve an extension GL_CHROMIUM_flush_sync to mark that only flush is needed) |
| 193 // Use sync objects/fences if available. |
| 194 // Use glFinish otherwise. |
| 195 context->flush(); // Using flush for now. So far only certain Androi
d devices need a finish. |
| 196 } |
| 197 m_acquireMode = WebGLSharedObject::Unacquired; |
| 198 processAcquireRequests(); |
| 199 } |
| 200 |
| 201 return true; |
| 202 } |
| 203 |
| 204 void WebGLSharedObject::processAcquireRequests() |
| 205 { |
| 206 // Queue all the events that could succeed right now. |
| 207 while (!m_acquireRequestQueue.isEmpty()) { |
| 208 RefPtr<WebGLAcquireSharedResourceRequest> request = m_acquireRequestQueu
e.first(); |
| 209 if (!acquire(request->acquireMode(), request->context())) { |
| 210 break; |
| 211 } |
| 212 |
| 213 m_acquireRequestQueue.removeFirst(); |
| 214 m_acquireRequestPostedList.append(request); |
| 215 |
| 216 // queue event |
| 217 ScriptExecutionContext* scriptExecutionContext = request->context()->scr
iptExecutionContext(); |
| 218 if (scriptExecutionContext) { |
| 219 scriptExecutionContext->postTask(adoptPtr(new DispatchCallbackTask(r
equest))); |
| 220 } |
| 221 } |
| 222 } |
| 223 |
| 224 bool WebGLSharedObject::isRequestPending(const WebGLRenderingContext* context) |
| 225 { |
| 226 for (AcquireRequestQueue::iterator it = m_acquireRequestQueue.begin(); it !=
m_acquireRequestQueue.end(); ++it) { |
| 227 if ((*it)->context() == context) { |
| 228 return true; |
| 229 } |
| 230 } |
| 231 for (AcquireRequestList::iterator it = m_acquireRequestPostedList.begin(); i
t != m_acquireRequestPostedList.end(); ++it) { |
| 232 if ((*it)->context() == context) { |
| 233 return true; |
| 234 } |
| 235 } |
| 236 return false; |
| 237 } |
| 238 |
| 239 bool WebGLSharedObject::cancelAcquireRequest(const WebGLRenderingContext* contex
t, long id) |
| 240 { |
| 241 for (AcquireRequestQueue::iterator it = m_acquireRequestQueue.begin(); it !=
m_acquireRequestQueue.end(); ++it) { |
| 242 if ((*it)->id() == id) { |
| 243 // Only remove it if it's from this context. |
| 244 if ((*it)->context() == context) { |
| 245 (*it)->cancel(); |
| 246 m_acquireRequestQueue.remove(it); |
| 247 processAcquireRequests(); |
| 248 } |
| 249 return true; |
| 250 } |
| 251 } |
| 252 for (AcquireRequestList::iterator it = m_acquireRequestPostedList.begin(); i
t != m_acquireRequestPostedList.end(); ++it) { |
| 253 if ((*it)->id() == id) { |
| 254 // Only remove it if it's from this context. |
| 255 if ((*it)->context() == context) { |
| 256 (*it)->cancel(); |
| 257 m_acquireRequestPostedList.remove(it); |
| 258 processAcquireRequests(); |
| 259 } |
| 260 return true; |
| 261 } |
| 262 } |
| 263 return false; |
| 264 } |
| 265 |
| 266 void WebGLSharedObject::cancelAllPendingRequestsForContext(const WebGLRenderingC
ontext* context) |
| 267 { |
| 268 bool done = false; |
| 269 while (!done) { |
| 270 done = true; |
| 271 for (AcquireRequestQueue::iterator it = m_acquireRequestQueue.begin(); i
t != m_acquireRequestQueue.end(); ++it) { |
| 272 if ((*it)->context() == context) { |
| 273 cancelAcquireRequest(context, (*it)->id()); |
| 274 done = false; |
| 275 break; |
| 276 } |
| 277 } |
| 278 } |
| 279 |
| 280 done = false; |
| 281 while (!done) { |
| 282 done = true; |
| 283 for (AcquireRequestList::iterator it = m_acquireRequestPostedList.begin(
); it != m_acquireRequestPostedList.end(); ++it) { |
| 284 if ((*it)->context() == context) { |
| 285 cancelAcquireRequest(context, (*it)->id()); |
| 286 done = false; |
| 287 break; |
| 288 } |
| 289 } |
| 290 } |
| 291 } |
| 292 |
| 293 void WebGLSharedObject::removePostedAcquireRequest(const WebGLRenderingContext*
context, long id) |
| 294 { |
| 295 for (AcquireRequestList::iterator it = m_acquireRequestPostedList.begin(); i
t != m_acquireRequestPostedList.end(); ++it) { |
| 296 if ((*it)->id() == id) { |
| 297 ASSERT((*it)->context() == context); |
| 298 m_acquireRequestPostedList.remove(it); |
| 299 return; |
| 300 } |
| 301 } |
| 302 ASSERT(false); // should never get here. |
| 303 } |
| 304 |
| 305 int WebGLSharedObject::generateAcquireRequestId() |
| 306 { |
| 307 AtomicallyInitializedStatic(int, acquireRequestId = 0); |
| 308 return atomicIncrement(&acquireRequestId); |
| 309 } |
| 310 |
| 311 WebGLSharedObject::DispatchCallbackTask::~DispatchCallbackTask() |
| 312 { |
| 313 } |
| 314 |
| 315 void WebGLSharedObject::DispatchCallbackTask::performTask(ScriptExecutionContext
*) |
| 316 { |
| 317 m_request->run(); |
| 318 } |
| 319 |
| 320 WebGLAcquireSharedResourceRequest::WebGLAcquireSharedResourceRequest(PassRefPtr<
WebGLSharedObject> sharedObject, PassRefPtr<WebGLAcquireSharedResourceCallback>
callback, WebGLSharedObject::AcquireMode acquireMode, WebGLRenderingContext* con
text, long id) |
| 321 : m_sharedObject(sharedObject) |
| 322 , m_context(context) |
| 323 , m_id(id) |
| 324 , m_acquireMode(acquireMode) |
| 325 , m_callback(callback) |
| 326 { |
| 327 } |
| 328 |
| 329 WebGLAcquireSharedResourceRequest::~WebGLAcquireSharedResourceRequest() |
| 330 { |
| 331 } |
| 332 |
| 333 PassRefPtr<WebGLAcquireSharedResourceRequest> WebGLAcquireSharedResourceRequest:
:create(PassRefPtr<WebGLSharedObject> sharedObject, PassRefPtr<WebGLAcquireShare
dResourceCallback> callback, WebGLSharedObject::AcquireMode acquireMode, WebGLRe
nderingContext* context, long id) |
| 334 { |
| 335 return adoptRef(new WebGLAcquireSharedResourceRequest(sharedObject, callback
, acquireMode, context, id)); |
| 336 } |
| 337 |
| 338 void WebGLAcquireSharedResourceRequest::cancel() |
| 339 { |
| 340 m_acquireMode = WebGLSharedObject::Unacquired; |
| 341 m_callback.clear(); |
| 342 } |
| 343 |
| 344 void WebGLAcquireSharedResourceRequest::run() |
| 345 { |
| 346 if (m_callback) { |
| 347 RefPtr<WebGLAcquireSharedResourceRequest> self(this); // Need to keep a
reference to ourselves as the next line may remove our last reference. |
| 348 m_sharedObject->removePostedAcquireRequest(context(), id()); |
| 349 m_callback->handleEvent(); |
| 350 m_callback.clear(); |
| 351 } |
| 352 } |
| 353 |
| 354 } // namespace WebCore |
| 355 |
OLD | NEW |