Chromium Code Reviews| Index: Source/core/html/canvas/WebGLRenderingContext.cpp |
| diff --git a/Source/core/html/canvas/WebGLRenderingContext.cpp b/Source/core/html/canvas/WebGLRenderingContext.cpp |
| index 5e4be277e3e9c4314adec09b8adda4a6bb2d565d..4cb182449469db315f7e5763bf73a5bd81a7d3bd 100644 |
| --- a/Source/core/html/canvas/WebGLRenderingContext.cpp |
| +++ b/Source/core/html/canvas/WebGLRenderingContext.cpp |
| @@ -84,6 +84,100 @@ namespace WebCore { |
| const double secondsBetweenRestoreAttempts = 1.0; |
| const int maxGLErrorsAllowedToConsole = 256; |
| +const int maxGLActiveContexts = 20; |
| + |
| +Vector<WebGLRenderingContext*>& WebGLRenderingContext::activeContexts() |
| +{ |
| + DEFINE_STATIC_LOCAL(Vector<WebGLRenderingContext*>, activeContexts, ()); |
| + return activeContexts; |
| +} |
| + |
| +Vector<WebGLRenderingContext*>& WebGLRenderingContext::forciblyEvictedContexts() |
| +{ |
| + DEFINE_STATIC_LOCAL(Vector<WebGLRenderingContext*>, forciblyEvictedContexts, ()); |
| + return forciblyEvictedContexts; |
| +} |
| + |
| +void WebGLRenderingContext::forciblyLoseOldestContext() |
| +{ |
| + if (activeContexts().size()) { |
| + WebGLRenderingContext* oldestActiveContext = activeContexts().first(); |
| + activeContexts().remove(0); |
| + |
| + // This will call deactivateContext once the context has actually been lost |
| + oldestActiveContext->forceLostContext(WebGLRenderingContext::SyntheticLostContext); |
| + } |
| +} |
| + |
| +IntSize WebGLRenderingContext::oldestContextSize() |
| +{ |
| + IntSize size; |
| + |
| + if (activeContexts().size()) { |
| + WebGLRenderingContext* oldestActiveContext = activeContexts().first(); |
| + size.setWidth(oldestActiveContext->drawingBufferWidth()); |
| + size.setHeight(oldestActiveContext->drawingBufferHeight()); |
| + } |
| + |
| + return size; |
| +} |
| + |
| +void WebGLRenderingContext::activateContext(WebGLRenderingContext* context) |
| +{ |
| + if (!activeContexts().contains(context)) |
| + activeContexts().append(context); |
| + |
| + if (activeContexts().size() > maxGLActiveContexts) |
| + forciblyLoseOldestContext(); |
| +} |
| + |
| +void WebGLRenderingContext::deactivateContext(WebGLRenderingContext* context, bool addToEvictedList) |
| +{ |
| + size_t position = activeContexts().find(context); |
| + if (position != WTF::notFound) |
| + activeContexts().remove(position); |
| + |
| + if (addToEvictedList && !forciblyEvictedContexts().contains(context)) |
| + forciblyEvictedContexts().append(context); |
| +} |
| + |
| +void WebGLRenderingContext::willDestroyContext(WebGLRenderingContext* context) |
| +{ |
| + size_t position = forciblyEvictedContexts().find(context); |
| + if (position != WTF::notFound) |
| + forciblyEvictedContexts().remove(position); |
| + |
| + deactivateContext(context, false); |
| + |
| + // Try to re-enable the oldest inactive contexts |
| + while(activeContexts().size() < maxGLActiveContexts && forciblyEvictedContexts().size()) { |
| + WebGLRenderingContext* evictedContext = forciblyEvictedContexts().first(); |
| + if (!evictedContext->m_restoreAllowed) { |
| + forciblyEvictedContexts().remove(0); |
| + continue; |
| + } |
| + |
| + IntSize desiredSize = evictedContext->m_drawingBuffer->adjustSize(evictedContext->clampedCanvasSize()); |
| + |
| + // If there's room in the pixel budget for this context, restore it! |
| + if (!desiredSize.isEmpty()) { |
| + forciblyEvictedContexts().remove(0); |
| + evictedContext->forceRestoreContext(); |
| + activeContexts().append(evictedContext); |
| + } |
| + break; |
| + } |
| +} |
| + |
| +class WebGLRenderingContextEvictionManager : public ContextEvictionManager { |
| +public: |
| + void forciblyLoseOldestContext() { |
| + WebGLRenderingContext::forciblyLoseOldestContext(); |
| + }; |
| + IntSize oldestContextSize() { |
| + return WebGLRenderingContext::oldestContextSize(); |
| + }; |
| +}; |
| namespace { |
| @@ -474,9 +568,11 @@ WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, Pa |
| m_maxViewportDims[0] = m_maxViewportDims[1] = 0; |
| m_context->getIntegerv(GraphicsContext3D::MAX_VIEWPORT_DIMS, m_maxViewportDims); |
| + RefPtr<WebGLRenderingContextEvictionManager> contextEvictionManager = adoptRef(new WebGLRenderingContextEvictionManager()); |
| + |
| // Create the DrawingBuffer and initialize the platform layer. |
| DrawingBuffer::PreserveDrawingBuffer preserve = m_attributes.preserveDrawingBuffer ? DrawingBuffer::Preserve : DrawingBuffer::Discard; |
| - m_drawingBuffer = DrawingBuffer::create(m_context.get(), clampedCanvasSize(), preserve); |
| + m_drawingBuffer = DrawingBuffer::create(m_context.get(), clampedCanvasSize(), preserve, contextEvictionManager.get()); |
|
Ken Russell (switch to Gerrit)
2013/04/24 01:30:57
Use PassRefPtr in the callee (see the comment else
|
| if (!m_drawingBuffer->isZeroSized()) { |
| m_drawingBuffer->bind(); |
| @@ -563,6 +659,8 @@ void WebGLRenderingContext::initializeNewContext() |
| m_context->setContextLostCallback(adoptPtr(new WebGLRenderingContextLostCallback(this))); |
| m_context->setErrorMessageCallback(adoptPtr(new WebGLRenderingContextErrorMessageCallback(this))); |
| + |
| + activateContext(this); |
| } |
| void WebGLRenderingContext::setupFlags() |
| @@ -623,6 +721,8 @@ WebGLRenderingContext::~WebGLRenderingContext() |
| detachAndRemoveAllObjects(); |
| destroyGraphicsContext3D(); |
| m_contextGroup->removeContext(this); |
| + |
| + willDestroyContext(this); |
| } |
| void WebGLRenderingContext::destroyGraphicsContext3D() |
| @@ -5755,6 +5855,7 @@ void WebGLRenderingContext::dispatchContextLostEvent(Timer<WebGLRenderingContext |
| RefPtr<WebGLContextEvent> event = WebGLContextEvent::create(eventNames().webglcontextlostEvent, false, true, ""); |
| canvas()->dispatchEvent(event); |
| m_restoreAllowed = event->defaultPrevented(); |
| + deactivateContext(this, m_contextLostMode != RealLostContext && m_restoreAllowed); |
| if (m_contextLostMode == RealLostContext && m_restoreAllowed) |
| m_restoreTimer.startOneShot(0); |
| } |
| @@ -5831,10 +5932,12 @@ void WebGLRenderingContext::maybeRestoreContext(Timer<WebGLRenderingContext>*) |
| return; |
| } |
| + RefPtr<WebGLRenderingContextEvictionManager> contextEvictionManager = adoptRef(new WebGLRenderingContextEvictionManager()); |
| + |
| // Construct a new drawing buffer with the new GraphicsContext3D. |
| m_drawingBuffer->clear(); |
| DrawingBuffer::PreserveDrawingBuffer preserve = m_attributes.preserveDrawingBuffer ? DrawingBuffer::Preserve : DrawingBuffer::Discard; |
| - m_drawingBuffer = DrawingBuffer::create(context.get(), clampedCanvasSize(), preserve); |
| + m_drawingBuffer = DrawingBuffer::create(context.get(), clampedCanvasSize(), preserve, contextEvictionManager.get()); |
| if (m_drawingBuffer->isZeroSized()) |
| return; |