Skip to content
Permalink
Browse files
Make WebGLRenderingContext inherit from ActiveDOMObject
https://bugs.webkit.org/show_bug.cgi?id=104733

Patch by Brandon Jones <bajones@chromium.org> on 2013-01-08
Reviewed by Adam Barth.

Source/WebCore:

When ActiveDOMObject::stop is called on the WebGLRenderingContext the
DrawingBuffer and GraphicsContext3D instances are forcibly released in
order to keep GPU memory utilization to a minimum.

Incorporated new layout test based on one just added to the WebGL
conformance suite. Also tested manually by reloading and
navigating between many WebGL apps.

Test: fast/canvas/webgl/context-release-upon-reload.html

* bindings/v8/custom/V8HTMLCanvasElementCustom.cpp:
(WebCore::V8HTMLCanvasElement::getContextCallback):
    Removed garbage collection hack added in Bug 76255.
* html/canvas/WebGLRenderingContext.cpp:
(WebCore):
(WebCore::WebGLRenderingContext::create):
    Call suspendIfNeeded per ActiveDOMObject contract.
(WebCore::WebGLRenderingContext::WebGLRenderingContext):
    Call ActiveDOMObject constructor.
(WebCore::WebGLRenderingContext::~WebGLRenderingContext):
    Call destroyGraphicsContext3D.
(WebCore::WebGLRenderingContext::destroyGraphicsContext3D):
    Drop DrawingBuffer backing store and delete GraphicsContext3D.
(WebCore::WebGLRenderingContext::hasPendingActivity):
    Always return false.
(WebCore::WebGLRenderingContext::stop):
    Force lost context upon page reload or navigation.
* html/canvas/WebGLRenderingContext.h:
(WebGLRenderingContext):
    Inherit from ActiveDOMObject and override notifications.
* platform/graphics/blackberry/DrawingBufferBlackBerry.cpp:
(WebCore):
(WebCore::DrawingBuffer::clearPlatformLayer):
    Add currently no-op implementation.
* platform/graphics/cairo/DrawingBufferCairo.cpp:
(WebCore):
(WebCore::DrawingBuffer::clearPlatformLayer):
    Add currently no-op implementation.
* platform/graphics/chromium/DrawingBufferChromium.cpp:
(WebCore::DrawingBufferPrivate::clearTextureId):
    Clear texture ID from compositor's layer.
(DrawingBufferPrivate):
(WebCore::DrawingBuffer::framebuffer):
    Moved around to reduce number of #ifdefs.
(WebCore):
(WebCore::DrawingBuffer::platformLayer):
(WebCore::DrawingBuffer::clearPlatformLayer):
    Tell compositor to stop referencing DrawingBuffer's texture.
* platform/graphics/clutter/DrawingBufferClutter.cpp:
(WebCore):
(WebCore::DrawingBuffer::clearPlatformLayer):
    Add currently no-op implementation.
* platform/graphics/gpu/DrawingBuffer.cpp:
(WebCore::DrawingBuffer::clear):
    Call clearPlatformLayer before deleting OpenGL resources.
* platform/graphics/gpu/DrawingBuffer.h:
(DrawingBuffer):
    Add clearPlatformLayer.
* platform/graphics/gpu/mac/DrawingBufferMac.mm:
(WebCore):
(WebCore::DrawingBuffer::clearPlatformLayer):
    Add currently no-op implementation.
* platform/graphics/gpu/qt/DrawingBufferQt.cpp:
(WebCore):
(WebCore::DrawingBuffer::clearPlatformLayer):
    Add currently no-op implementation.

LayoutTests:

* fast/canvas/webgl/context-release-upon-reload-expected.txt: Added.
* fast/canvas/webgl/context-release-upon-reload.html: Added.
* fast/canvas/webgl/resources/context-release-upon-reload-child.html: Added.

Canonical link: https://commits.webkit.org/124593@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@139142 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
toji authored and webkit-commit-queue committed Jan 9, 2013
1 parent 19915dc commit ada4cbf606a34f63a1c8d617da0ce26d11cecd72
Showing 16 changed files with 341 additions and 16 deletions.
@@ -1,3 +1,14 @@
2013-01-08 Brandon Jones <bajones@chromium.org>

Make WebGLRenderingContext inherit from ActiveDOMObject
https://bugs.webkit.org/show_bug.cgi?id=104733

Reviewed by Adam Barth.

* fast/canvas/webgl/context-release-upon-reload-expected.txt: Added.
* fast/canvas/webgl/context-release-upon-reload.html: Added.
* fast/canvas/webgl/resources/context-release-upon-reload-child.html: Added.

2013-01-08 Martin Robinson <mrobinson@igalia.com>

WebKitTestRunner needs support for setHandlesAuthenticationChallenges
@@ -0,0 +1,59 @@

This test ensures that WebGL contexts are released properly upon page reload

On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".


Test 1 of 10
PASS context was created properly
PASS getError was expected value: NO_ERROR : Should be no errors
PASS Buffer was the correct size: 1680x1050

Test 2 of 10
PASS context was created properly
PASS getError was expected value: NO_ERROR : Should be no errors
PASS Buffer was the correct size: 1680x1050

Test 3 of 10
PASS context was created properly
PASS getError was expected value: NO_ERROR : Should be no errors
PASS Buffer was the correct size: 1680x1050

Test 4 of 10
PASS context was created properly
PASS getError was expected value: NO_ERROR : Should be no errors
PASS Buffer was the correct size: 1680x1050

Test 5 of 10
PASS context was created properly
PASS getError was expected value: NO_ERROR : Should be no errors
PASS Buffer was the correct size: 1680x1050

Test 6 of 10
PASS context was created properly
PASS getError was expected value: NO_ERROR : Should be no errors
PASS Buffer was the correct size: 1680x1050

Test 7 of 10
PASS context was created properly
PASS getError was expected value: NO_ERROR : Should be no errors
PASS Buffer was the correct size: 1680x1050

Test 8 of 10
PASS context was created properly
PASS getError was expected value: NO_ERROR : Should be no errors
PASS Buffer was the correct size: 1680x1050

Test 9 of 10
PASS context was created properly
PASS getError was expected value: NO_ERROR : Should be no errors
PASS Buffer was the correct size: 1680x1050

Test 10 of 10
PASS context was created properly
PASS getError was expected value: NO_ERROR : Should be no errors
PASS Buffer was the correct size: 1680x1050
PASS successfullyParsed is true

TEST COMPLETE

@@ -0,0 +1,66 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL Context Release Test</title>
<link rel="stylesheet" href="../../js/resources/js-test-style.css"/>
<script src="../../js/resources/js-test-pre.js"></script>
<script src="resources/webgl-test.js"></script>
</head>
<body>
<iframe id="host" style="width: 256px; height: 256px; border: 0;"></iframe>
<div id="description"></div>
<div id="console"></div>
<script>
description("This test ensures that WebGL contexts are released properly upon page reload");

if (window.testRunner) {
testRunner.dumpAsText();
testRunner.waitUntilDone();
}

var host = document.getElementById("host");
var testIterations = 10;
var currentIteration = 0;

function refreshFrame() {
if(currentIteration < testIterations) {
currentIteration++;
debug("");
debug("Test " + currentIteration + " of " + testIterations);
host.src = "resources/context-release-upon-reload-child.html";
} else {
finishTest();
}
}

function testContext() {
var gl = host.contentWindow.glContext;
assertMsg(gl != null, "context was created properly");

glErrorShouldBe(gl, gl.NO_ERROR, "Should be no errors");

if(gl.canvas.width != gl.drawingBufferWidth ||
gl.canvas.height != gl.drawingBufferHeight) {
testFailed("Buffer was the wrong size: " +
gl.drawingBufferWidth + "x" + gl.drawingBufferHeight);
} else {
testPassed("Buffer was the correct size: " +
gl.drawingBufferWidth + "x" + gl.drawingBufferHeight);
refreshFrame();
}

gl = null;
}

window.addEventListener("message", function(event) {
if(event.data == "Ready") {
testContext();
}
});

refreshFrame();
</script>

</body>
</html>
@@ -0,0 +1,49 @@
<!DOCTYPE html>
<html style="margin: 0; padding: 0;">
<head>
<meta charset="utf-8">
<title>Simple WebGL context</title>
<script src="webgl-test-utils.js"> </script>
</head>
<body style="margin: 0; padding: 0; overflow: hidden;">
<canvas id="c"
width="1680" height="1050"
style="width: 256px; height: 256px;"> <!-- scaled to fit page better -->
<script id="vshader" type="x-shader/x-vertex">
attribute vec4 vPosition;
void main()
{
gl_Position = vPosition;
}
</script>

<script id="fshader" type="x-shader/x-fragment">
void main()
{
gl_FragColor = vec4(1.0,0.0,0.0,1.0);
}
</script>

<script>
var wtu = WebGLTestUtils;

var gl = wtu.create3DContext("c", {"antialiased": false});
program = wtu.setupProgram(gl, ["vshader", "fshader"], ["vPosition"]);

var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0,0.75,0, -0.75,-0.75,0, 0.75,-0.75,0 ]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);

gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);

if(parent) {
window.glContext = gl;
parent.postMessage("Ready", "*");
}
</script>
</body>
</html>
@@ -1,3 +1,77 @@
2013-01-08 Brandon Jones <bajones@chromium.org>

Make WebGLRenderingContext inherit from ActiveDOMObject
https://bugs.webkit.org/show_bug.cgi?id=104733

Reviewed by Adam Barth.

When ActiveDOMObject::stop is called on the WebGLRenderingContext the
DrawingBuffer and GraphicsContext3D instances are forcibly released in
order to keep GPU memory utilization to a minimum.

Incorporated new layout test based on one just added to the WebGL
conformance suite. Also tested manually by reloading and
navigating between many WebGL apps.

Test: fast/canvas/webgl/context-release-upon-reload.html

* bindings/v8/custom/V8HTMLCanvasElementCustom.cpp:
(WebCore::V8HTMLCanvasElement::getContextCallback):
Removed garbage collection hack added in Bug 76255.
* html/canvas/WebGLRenderingContext.cpp:
(WebCore):
(WebCore::WebGLRenderingContext::create):
Call suspendIfNeeded per ActiveDOMObject contract.
(WebCore::WebGLRenderingContext::WebGLRenderingContext):
Call ActiveDOMObject constructor.
(WebCore::WebGLRenderingContext::~WebGLRenderingContext):
Call destroyGraphicsContext3D.
(WebCore::WebGLRenderingContext::destroyGraphicsContext3D):
Drop DrawingBuffer backing store and delete GraphicsContext3D.
(WebCore::WebGLRenderingContext::hasPendingActivity):
Always return false.
(WebCore::WebGLRenderingContext::stop):
Force lost context upon page reload or navigation.
* html/canvas/WebGLRenderingContext.h:
(WebGLRenderingContext):
Inherit from ActiveDOMObject and override notifications.
* platform/graphics/blackberry/DrawingBufferBlackBerry.cpp:
(WebCore):
(WebCore::DrawingBuffer::clearPlatformLayer):
Add currently no-op implementation.
* platform/graphics/cairo/DrawingBufferCairo.cpp:
(WebCore):
(WebCore::DrawingBuffer::clearPlatformLayer):
Add currently no-op implementation.
* platform/graphics/chromium/DrawingBufferChromium.cpp:
(WebCore::DrawingBufferPrivate::clearTextureId):
Clear texture ID from compositor's layer.
(DrawingBufferPrivate):
(WebCore::DrawingBuffer::framebuffer):
Moved around to reduce number of #ifdefs.
(WebCore):
(WebCore::DrawingBuffer::platformLayer):
(WebCore::DrawingBuffer::clearPlatformLayer):
Tell compositor to stop referencing DrawingBuffer's texture.
* platform/graphics/clutter/DrawingBufferClutter.cpp:
(WebCore):
(WebCore::DrawingBuffer::clearPlatformLayer):
Add currently no-op implementation.
* platform/graphics/gpu/DrawingBuffer.cpp:
(WebCore::DrawingBuffer::clear):
Call clearPlatformLayer before deleting OpenGL resources.
* platform/graphics/gpu/DrawingBuffer.h:
(DrawingBuffer):
Add clearPlatformLayer.
* platform/graphics/gpu/mac/DrawingBufferMac.mm:
(WebCore):
(WebCore::DrawingBuffer::clearPlatformLayer):
Add currently no-op implementation.
* platform/graphics/gpu/qt/DrawingBufferQt.cpp:
(WebCore):
(WebCore::DrawingBuffer::clearPlatformLayer):
Add currently no-op implementation.

2013-01-08 Tony Gentilcore <tonyg@chromium.org>

Remove dependency on Document from HTMLConstructionSite::inQuirksMode()
@@ -97,12 +97,6 @@ v8::Handle<v8::Value> V8HTMLCanvasElement::getContextCallback(const v8::Argument
}
#if ENABLE(WEBGL)
else if (result->is3d()) {
// 3D canvas contexts can hold on to lots of GPU resources, and we want to take an
// opportunity to get rid of them as soon as possible when we navigate away from pages using
// them.
V8PerIsolateData* perIsolateData = V8PerIsolateData::from(args.GetIsolate());
perIsolateData->setShouldCollectGarbageSoon();

v8::Handle<v8::Value> v8Result = toV8(static_cast<WebGLRenderingContext*>(result), args.Holder(), args.GetIsolate());
if (InspectorInstrumentation::canvasAgentEnabled(imp->document())) {
ScriptState* scriptState = ScriptState::forContext(v8::Context::GetCurrent());
@@ -439,6 +439,7 @@ PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElemen
extensions->pushGroupMarkerEXT("WebGLRenderingContext");

OwnPtr<WebGLRenderingContext> renderingContext = adoptPtr(new WebGLRenderingContext(canvas, context, attributes));
renderingContext->suspendIfNeeded();

#if PLATFORM(CHROMIUM)
if (!renderingContext->m_drawingBuffer) {
@@ -453,6 +454,7 @@ PassOwnPtr<WebGLRenderingContext> WebGLRenderingContext::create(HTMLCanvasElemen
WebGLRenderingContext::WebGLRenderingContext(HTMLCanvasElement* passedCanvas, PassRefPtr<GraphicsContext3D> context,
GraphicsContext3D::Attributes attributes)
: CanvasRenderingContext(passedCanvas)
, ActiveDOMObject(passedCanvas->document(), this)
, m_context(context)
, m_drawingBuffer(0)
, m_dispatchContextLostEventTimer(this, &WebGLRenderingContext::dispatchContextLostEvent)
@@ -615,11 +617,24 @@ WebGLRenderingContext::~WebGLRenderingContext()
m_blackTextureCubeMap = 0;

detachAndRemoveAllObjects();
m_context->setContextLostCallback(nullptr);
m_context->setErrorMessageCallback(nullptr);
destroyGraphicsContext3D();
m_contextGroup->removeContext(this);
}

void WebGLRenderingContext::destroyGraphicsContext3D()
{
// The drawing buffer holds a context reference. It must also be destroyed
// in order for the context to be released.
if (m_drawingBuffer)
m_drawingBuffer.clear();

if (m_context) {
m_context->setContextLostCallback(nullptr);
m_context->setErrorMessageCallback(nullptr);
m_context.clear();
}
}

void WebGLRenderingContext::markContextChanged()
{
if (m_framebufferBinding)
@@ -4584,6 +4599,19 @@ void WebGLRenderingContext::detachAndRemoveAllObjects()
}
}

bool WebGLRenderingContext::hasPendingActivity() const
{
return false;
}

void WebGLRenderingContext::stop()
{
if (!isContextLost()) {
forceLostContext(SyntheticLostContext);
destroyGraphicsContext3D();
}
}

WebGLGetInfo WebGLRenderingContext::getBooleanParameter(GC3Denum pname)
{
GC3Dboolean value = 0;
@@ -26,6 +26,7 @@
#ifndef WebGLRenderingContext_h
#define WebGLRenderingContext_h

#include "ActiveDOMObject.h"
#include "CanvasRenderingContext.h"
#include "DrawingBuffer.h"
#include "GraphicsContext3D.h"
@@ -75,7 +76,7 @@ class WebGLVertexArrayObjectOES;

typedef int ExceptionCode;

class WebGLRenderingContext : public CanvasRenderingContext {
class WebGLRenderingContext : public CanvasRenderingContext, public ActiveDOMObject {
public:
static PassOwnPtr<WebGLRenderingContext> create(HTMLCanvasElement*, WebGLContextAttributes*);
virtual ~WebGLRenderingContext();
@@ -317,6 +318,10 @@ class WebGLRenderingContext : public CanvasRenderingContext {

unsigned getMaxVertexAttribs() const { return m_maxVertexAttribs; }

// ActiveDOMObject notifications
virtual bool hasPendingActivity() const;
virtual void stop();

private:
friend class WebGLFramebuffer;
friend class WebGLObject;
@@ -334,6 +339,7 @@ class WebGLRenderingContext : public CanvasRenderingContext {
void addContextObject(WebGLContextObject*);
void detachAndRemoveAllObjects();

void destroyGraphicsContext3D();
void markContextChanged();
void cleanupAfterGraphicsCall(bool changed)
{
@@ -122,6 +122,10 @@ unsigned DrawingBuffer::frontColorBuffer() const
{
return colorBuffer();
}

void DrawingBuffer::clearPlatformLayer()
{
}
#endif

} // namespace WebCore

0 comments on commit ada4cbf

Please sign in to comment.