Index: Source/core/html/canvas/WebGLSharedObject.cpp |
diff --git a/Source/core/html/canvas/WebGLSharedObject.cpp b/Source/core/html/canvas/WebGLSharedObject.cpp |
index f5d63651ff51b90d8b53a0cebd5009cb176f1560..34b89edf18eda75f9e564018cced9bfd091ad53f 100644 |
--- a/Source/core/html/canvas/WebGLSharedObject.cpp |
+++ b/Source/core/html/canvas/WebGLSharedObject.cpp |
@@ -27,21 +27,29 @@ |
#include "core/html/canvas/WebGLSharedObject.h" |
+#include "core/html/canvas/WebGLAcquireSharedResourceCallback.h" |
#include "core/html/canvas/WebGLContextGroup.h" |
#include "core/html/canvas/WebGLRenderingContext.h" |
namespace WebCore { |
WebGLSharedObject::WebGLSharedObject(WebGLRenderingContext* context) |
- : WebGLObject(context), |
- m_contextGroup(context->contextGroup()) |
+ : WebGLObject(context) |
+ , m_contextGroup(context->contextGroup()) |
+ , m_acquireMode(WebGLSharedObject::Unacquired) |
{ |
+ bool success = acquire(WebGLSharedObject::Exclusive, context); |
+ ASSERT(success); |
+ |
+ // We need to mark shaders and programs as bound as there is no way to easy way to bind/attach them. |
+ markAsBoundSinceLastAcquireForContext(context); |
} |
WebGLSharedObject::~WebGLSharedObject() |
{ |
- if (m_contextGroup) |
+ if (m_contextGroup) { |
m_contextGroup->removeObject(this); |
+ } |
} |
void WebGLSharedObject::detachContextGroup() |
@@ -59,4 +67,289 @@ GraphicsContext3D* WebGLSharedObject::getAGraphicsContext3D() const |
return m_contextGroup ? m_contextGroup->getAGraphicsContext3D() : 0; |
} |
+bool WebGLSharedObject::isAcquiredForContext(const WebGLRenderingContext* context, WebGLSharedObject::AcquireMode neededMode, bool mustBeBoundSinceLastAcquire, bool* hasBeenBoundSinceLastAcquire, const char** reason) const |
+{ |
+ AcquireContextMap::const_iterator it = m_acquireContextMap.find(context); |
+ if (it == m_acquireContextMap.end()) { |
+ *reason = " not acquired in this context"; |
+ return false; |
+ } |
+ |
+ bool sameMode = m_acquireMode == neededMode; |
+ bool validCombo = m_acquireMode == WebGLSharedObject::Exclusive && neededMode == WebGLSharedObject::ReadOnly; |
+ if (!sameMode && !validCombo) { |
+ *reason = " not acquired for exclusive access"; |
+ return false; |
+ } |
+ |
+ if (mustBeBoundSinceLastAcquire && !it->value) { |
+ *reason = " has not been bound since last acquired"; |
+ return false; |
+ } |
+ |
+ if (hasBeenBoundSinceLastAcquire) { |
+ *hasBeenBoundSinceLastAcquire = it->value; |
+ } |
+ |
+ return true; |
+} |
+ |
+bool WebGLSharedObject::validate(const char* functionName, WebGLRenderingContext* context, WebGLSharedObject::AcquireMode neededMode, bool mustBeBoundSinceLastAcquire, bool* boundSinceLastAcquire) const |
+{ |
+ if (context->contextGroup() != m_contextGroup) { |
+ String msg(String(typeName()) + " not from this share group"); |
+ context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, msg.utf8().data()); |
+ return false; |
+ } |
+ |
+ const char* reason; |
+ if (!isAcquiredForContext(context, neededMode, mustBeBoundSinceLastAcquire, boundSinceLastAcquire, &reason)) { |
+ String msg(String(typeName()) + reason); |
+ context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, functionName, msg.utf8().data()); |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+void WebGLSharedObject::markAsBoundSinceLastAcquireForContext(const WebGLRenderingContext* context) |
+{ |
+ AcquireContextMap::iterator it = m_acquireContextMap.find(context); |
+ ASSERT(it != m_acquireContextMap.end()); |
+ it->value = true; |
+} |
+ |
+bool WebGLSharedObject::acquire(WebGLSharedObject::AcquireMode desiredMode, const WebGLRenderingContext* context) |
+{ |
+ AcquireContextMap::const_iterator it = m_acquireContextMap.find(context); |
+ if (it != m_acquireContextMap.end()) { |
+ // How can I get here? |
+ return false; |
+ } |
+ |
+ bool unacquired = m_acquireMode == WebGLSharedObject::Unacquired; |
+ bool bothReadOnly = m_acquireMode == WebGLSharedObject::ReadOnly && desiredMode == WebGLSharedObject::ReadOnly; |
+ if (!unacquired && !bothReadOnly) { |
+ return false; |
+ } |
+ |
+ // Note: The resource is acquired at this point. The user may still cancel |
+ // the request though before it the acquire callback is fired. If it is |
+ // cancelled the cancel acts as a call to release. |
+ m_acquireMode = desiredMode; |
+ m_acquireContextMap.add(context, false); |
+ return true; |
+} |
+ |
+bool WebGLSharedObject::addAcquireRequest(WebGLRenderingContext* context, WebGLSharedObject::AcquireMode desiredMode, PassRefPtr<WebGLAcquireSharedResourceCallback> callback, long& id) |
+{ |
+ switch (desiredMode) { |
+ case WebGLSharedObject::ReadOnly: |
+ case WebGLSharedObject::Exclusive: |
+ break; |
+ default: |
+ context->synthesizeGLError(GraphicsContext3D::INVALID_ENUM, "acquireSharedResource", "mode is not READ_ONLY or EXCLUSIVE"); |
+ return false; |
+ } |
+ |
+ // Checks the object belongs to this group. |
+ // Note: We let lost objects go through here. |
+ if (context->contextGroup() != m_contextGroup && !isLost()) { |
+ context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "acquireSharedResource", "object is not from this ShareGroup"); |
+ return false; |
+ } |
+ |
+ // Checks it is not already acquired by this context. |
+ AcquireContextMap::iterator it = m_acquireContextMap.find(context); |
+ if (it != m_acquireContextMap.end()) { |
+ context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "acquireSharedResource", "object is already acquired in this context"); |
+ return false; |
+ } |
+ |
+ // Checks it is not already in one of the queues. |
+ if (isRequestPending(context)) { |
+ context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION, "acquireSharedResource", "request to acquire this object is already pending in this context"); |
+ return false; |
+ } |
+ |
+ // Adds the request. |
+ id = generateAcquireRequestId(); |
+ m_acquireRequestQueue.append(WebGLAcquireSharedResourceRequest::create(this, callback, desiredMode, context, id)); |
+ processAcquireRequests(); |
+ return true; |
+} |
+ |
+bool WebGLSharedObject::release(WebGLRenderingContext* context) |
+{ |
+ AcquireContextMap::iterator it = m_acquireContextMap.find(context); |
+ if (it == m_acquireContextMap.end()) { |
+ return false; |
+ } |
+ |
+ m_acquireContextMap.remove(it); |
+ if (m_acquireContextMap.isEmpty()) { |
+ if (m_acquireMode == WebGLSharedObject::Exclusive) { |
+ // TODO: Use flush if on top of virtual contexts (maybe we should have an extension GL_CHROMIUM_flush_sync to mark that only flush is needed) |
+ // Use sync objects/fences if available. |
+ // Use glFinish otherwise. |
+ context->flush(); // Using flush for now. So far only certain Android devices need a finish. |
+ } |
+ m_acquireMode = WebGLSharedObject::Unacquired; |
+ processAcquireRequests(); |
+ } |
+ |
+ return true; |
+} |
+ |
+void WebGLSharedObject::processAcquireRequests() |
+{ |
+ // Queue all the events that could succeed right now. |
+ while (!m_acquireRequestQueue.isEmpty()) { |
+ RefPtr<WebGLAcquireSharedResourceRequest> request = m_acquireRequestQueue.first(); |
+ if (!acquire(request->acquireMode(), request->context())) { |
+ break; |
+ } |
+ |
+ m_acquireRequestQueue.removeFirst(); |
+ m_acquireRequestPostedList.append(request); |
+ |
+ // queue event |
+ ScriptExecutionContext* scriptExecutionContext = request->context()->scriptExecutionContext(); |
+ if (scriptExecutionContext) { |
+ scriptExecutionContext->postTask(adoptPtr(new DispatchCallbackTask(request))); |
+ } |
+ } |
+} |
+ |
+bool WebGLSharedObject::isRequestPending(const WebGLRenderingContext* context) |
+{ |
+ for (AcquireRequestQueue::iterator it = m_acquireRequestQueue.begin(); it != m_acquireRequestQueue.end(); ++it) { |
+ if ((*it)->context() == context) { |
+ return true; |
+ } |
+ } |
+ for (AcquireRequestList::iterator it = m_acquireRequestPostedList.begin(); it != m_acquireRequestPostedList.end(); ++it) { |
+ if ((*it)->context() == context) { |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+bool WebGLSharedObject::cancelAcquireRequest(const WebGLRenderingContext* context, long id) |
+{ |
+ for (AcquireRequestQueue::iterator it = m_acquireRequestQueue.begin(); it != m_acquireRequestQueue.end(); ++it) { |
+ if ((*it)->id() == id) { |
+ // Only remove it if it's from this context. |
+ if ((*it)->context() == context) { |
+ (*it)->cancel(); |
+ m_acquireRequestQueue.remove(it); |
+ processAcquireRequests(); |
+ } |
+ return true; |
+ } |
+ } |
+ for (AcquireRequestList::iterator it = m_acquireRequestPostedList.begin(); it != m_acquireRequestPostedList.end(); ++it) { |
+ if ((*it)->id() == id) { |
+ // Only remove it if it's from this context. |
+ if ((*it)->context() == context) { |
+ (*it)->cancel(); |
+ m_acquireRequestPostedList.remove(it); |
+ processAcquireRequests(); |
+ } |
+ return true; |
+ } |
+ } |
+ return false; |
+} |
+ |
+void WebGLSharedObject::cancelAllPendingRequestsForContext(const WebGLRenderingContext* context) |
+{ |
+ bool done = false; |
+ while (!done) { |
+ done = true; |
+ for (AcquireRequestQueue::iterator it = m_acquireRequestQueue.begin(); it != m_acquireRequestQueue.end(); ++it) { |
+ if ((*it)->context() == context) { |
+ cancelAcquireRequest(context, (*it)->id()); |
+ done = false; |
+ break; |
+ } |
+ } |
+ } |
+ |
+ done = false; |
+ while (!done) { |
+ done = true; |
+ for (AcquireRequestList::iterator it = m_acquireRequestPostedList.begin(); it != m_acquireRequestPostedList.end(); ++it) { |
+ if ((*it)->context() == context) { |
+ cancelAcquireRequest(context, (*it)->id()); |
+ done = false; |
+ break; |
+ } |
+ } |
+ } |
+} |
+ |
+void WebGLSharedObject::removePostedAcquireRequest(const WebGLRenderingContext* context, long id) |
+{ |
+ for (AcquireRequestList::iterator it = m_acquireRequestPostedList.begin(); it != m_acquireRequestPostedList.end(); ++it) { |
+ if ((*it)->id() == id) { |
+ ASSERT((*it)->context() == context); |
+ m_acquireRequestPostedList.remove(it); |
+ return; |
+ } |
+ } |
+ ASSERT(false); // should never get here. |
+} |
+ |
+int WebGLSharedObject::generateAcquireRequestId() |
+{ |
+ AtomicallyInitializedStatic(int, acquireRequestId = 0); |
+ return atomicIncrement(&acquireRequestId); |
+} |
+ |
+WebGLSharedObject::DispatchCallbackTask::~DispatchCallbackTask() |
+{ |
+} |
+ |
+void WebGLSharedObject::DispatchCallbackTask::performTask(ScriptExecutionContext*) |
+{ |
+ m_request->run(); |
+} |
+ |
+WebGLAcquireSharedResourceRequest::WebGLAcquireSharedResourceRequest(PassRefPtr<WebGLSharedObject> sharedObject, PassRefPtr<WebGLAcquireSharedResourceCallback> callback, WebGLSharedObject::AcquireMode acquireMode, WebGLRenderingContext* context, long id) |
+ : m_sharedObject(sharedObject) |
+ , m_context(context) |
+ , m_id(id) |
+ , m_acquireMode(acquireMode) |
+ , m_callback(callback) |
+{ |
+} |
+ |
+WebGLAcquireSharedResourceRequest::~WebGLAcquireSharedResourceRequest() |
+{ |
} |
+ |
+PassRefPtr<WebGLAcquireSharedResourceRequest> WebGLAcquireSharedResourceRequest::create(PassRefPtr<WebGLSharedObject> sharedObject, PassRefPtr<WebGLAcquireSharedResourceCallback> callback, WebGLSharedObject::AcquireMode acquireMode, WebGLRenderingContext* context, long id) |
+{ |
+ return adoptRef(new WebGLAcquireSharedResourceRequest(sharedObject, callback, acquireMode, context, id)); |
+} |
+ |
+void WebGLAcquireSharedResourceRequest::cancel() |
+{ |
+ m_acquireMode = WebGLSharedObject::Unacquired; |
+ m_callback.clear(); |
+} |
+ |
+void WebGLAcquireSharedResourceRequest::run() |
+{ |
+ if (m_callback) { |
+ RefPtr<WebGLAcquireSharedResourceRequest> self(this); // Need to keep a reference to ourselves as the next line may remove our last reference. |
+ m_sharedObject->removePostedAcquireRequest(context(), id()); |
+ m_callback->handleEvent(); |
+ m_callback.clear(); |
+ } |
+} |
+ |
+} // namespace WebCore |
+ |