| 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
|
| +
|
|
|