Commit 0f9b8f57 authored by zmo@google.com's avatar zmo@google.com

2010-08-11 Zhenyao Mo <zmo@google.com>

        Reviewed by Dimitri Glazkov.

        Regression in linking of programs
        https://bugs.webkit.org/show_bug.cgi?id=43820

        Shaders and programs shouldn't be deleted until their attachments are removed, therefore, we need to track the attach/detach/useProgram.

        * html/canvas/WebGLObject.cpp: Track the object attachment count and whether it should really be deleted.
        (WebCore::WebGLObject::WebGLObject):
        (WebCore::WebGLObject::setObject):
        (WebCore::WebGLObject::deleteObject):
        * html/canvas/WebGLObject.h: Track the object attachment count and whether it should really be deleted.
        (WebCore::WebGLObject::onAttached):
        (WebCore::WebGLObject::onDetached):
        (WebCore::WebGLObject::getAttachmentCount):
        * html/canvas/WebGLProgram.cpp: Track the attached shaders.
        (WebCore::WebGLProgram::WebGLProgram):
        (WebCore::WebGLProgram::deleteObjectImpl):
        (WebCore::WebGLProgram::getAttachedShader):
        (WebCore::WebGLProgram::attachShader):
        (WebCore::WebGLProgram::detachShader):
        * html/canvas/WebGLProgram.h: Track the attached shaders.
        * html/canvas/WebGLRenderingContext.cpp:
        (WebCore::WebGLRenderingContext::attachShader): Track the attachment of a shader to a program.
        (WebCore::WebGLRenderingContext::deleteProgram): Detach shaders.
        (WebCore::WebGLRenderingContext::detachShader): Track the attachment of a shader to a program.
        (WebCore::WebGLRenderingContext::validateWebGLObject): Also check if object == 0.
        (WebCore::WebGLRenderingContext::linkProgram): Using the cached attached shaders instead of query from driver.
        (WebCore::WebGLRenderingContext::useProgram): Track the attachment of a program to the current rendering pipeline.
2010-08-11  Zhenyao Mo  <zmo@google.com>

        Reviewed by Dimitri Glazkov.

        Regression in linking of programs
        https://bugs.webkit.org/show_bug.cgi?id=43820

        * fast/canvas/webgl/program-test-expected.txt: Fix the tests so a second shader of the same type attaching to a program will generate error; also, add tests for deleteShader/deleteProgram behavior.
        * fast/canvas/webgl/program-test.html: Ditto.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@65330 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 52ca7c02
2010-08-11 Zhenyao Mo <zmo@google.com>
Reviewed by Dimitri Glazkov.
Regression in linking of programs
https://bugs.webkit.org/show_bug.cgi?id=43820
* fast/canvas/webgl/program-test-expected.txt: Fix the tests so a second shader of the same type attaching to a program will generate error; also, add tests for deleteShader/deleteProgram behavior.
* fast/canvas/webgl/program-test.html: Ditto.
2010-08-13 Steve Block <steveblock@google.com>
Reviewed by Alexey Proskuryakov.
......@@ -12,15 +12,17 @@ PASS bad vertex shader should fail to compile
PASS good fragment shader should compile
PASS good fragment shader #2 should compile
PASS bad fragment shader should fail to compile
PASS should be no errors at this point
PASS attaching a vertex shader should succeed
PASS attaching an already attached vertex shader should generate INVALID_OPERATION
PASS attaching a fragment shader should succeed
PASS attaching an already attached fragment shader should generate INVALID_OPERATION
PASS detaching a vertex shader should succeed
PASS detaching a not already attached vertex shader should generate INVALID_OPERATION
PASS detaching a fragment shader should succeed
PASS detaching a not already attached fragment shader should generate INVALID_OPERATION
PASS getError was expected value: NO_ERROR : should be no errors at this point
PASS getError was expected value: NO_ERROR : attaching a vertex shader should succeed
PASS getError was expected value: INVALID_OPERATION : attaching an already attached vertex shader should generate INVALID_OPERATION
PASS getError was expected value: NO_ERROR : attaching a fragment shader should succeed
PASS getError was expected value: INVALID_OPERATION : attaching an already attached fragment shader should generate INVALID_OPERATION
PASS getError was expected value: INVALID_OPERATION : attaching shaders of the same type to a program should generate INVALID_OPERATION
PASS getError was expected value: INVALID_OPERATION : attaching shaders of the same type to a program should generate INVALID_OPERATION
PASS getError was expected value: NO_ERROR : detaching a vertex shader should succeed
PASS getError was expected value: INVALID_OPERATION : detaching a not already attached vertex shader should generate INVALID_OPERATION
PASS getError was expected value: NO_ERROR : detaching a fragment shader should succeed
PASS getError was expected value: INVALID_OPERATION : detaching a not already attached fragment shader should generate INVALID_OPERATION
PASS getAttachedShaders should return an empty list by default
PASS attaching a single shader should give the expected list
PASS attaching some shaders should give the expected list
......@@ -32,26 +34,38 @@ PASS attaching and detaching some shaders should leave the difference list
PASS attaching a shader that failed to compile should still show it in the list
PASS attaching shaders, including one that failed to compile, should still show the it in the list
PASS valid program should link
PASS using a valid program should succeed
PASS getError was expected value: NO_ERROR : using a valid program should succeed
PASS valid program #2 should link
PASS using a valid program should succeed
PASS getError was expected value: NO_ERROR : using a valid program should succeed
PASS program with no fragment shader should fail to link
PASS using an invalid program should generate INVALID_OPERATION
PASS getError was expected value: INVALID_OPERATION : using an invalid program should generate INVALID_OPERATION
PASS program with no vertex shader should fail to link
PASS using an invalid program should generate INVALID_OPERATION
PASS getError was expected value: INVALID_OPERATION : using an invalid program should generate INVALID_OPERATION
PASS program with bad vertex shader should fail to link
PASS using an invalid program should generate INVALID_OPERATION
PASS getError was expected value: INVALID_OPERATION : using an invalid program should generate INVALID_OPERATION
PASS program with bad fragment shader should fail to link
PASS using an invalid program should generate INVALID_OPERATION
PASS getError was expected value: INVALID_OPERATION : using an invalid program should generate INVALID_OPERATION
PASS program with bad shaders should fail to link
PASS using an invalid program should generate INVALID_OPERATION
PASS using a valid program shouldn't generate a GL error
PASS should be no errors at this point #2
PASS drawing with a valid program shouldn't generate a GL error
PASS using an invalid program should generate INVALID_OPERATION
PASS drawing with an invalid program should generate some GL error XXX
PASS getError was expected value: INVALID_OPERATION : using an invalid program should generate INVALID_OPERATION
PASS getError was expected value: NO_ERROR : using a valid program shouldn't generate a GL error
PASS getError was expected value: NO_ERROR : should be no errors at this point #2
PASS getError was expected value: NO_ERROR : drawing with a valid program shouldn't generate a GL error
PASS getError was expected value: INVALID_OPERATION : using an invalid program should generate INVALID_OPERATION
PASS getError was expected value: NO_ERROR : Try to use an invalid program should not change the current rendering state
PASS getError was expected value: NO_ERROR : drawing with a valid program shouldn't generate a GL error
PASS linking should fail with in-use formerly good program, with new bad shader attached
PASS drawing with a valid when last used program shouldn't generate a GL error
PASS getError was expected value: NO_ERROR : drawing with a valid when last used program shouldn't generate a GL error
PASS delete shaders after attaching them and before linking program should not affect linkProgram
PASS getError was expected value: NO_ERROR : using a valid program should succeed
PASS getError was expected value: NO_ERROR : drawing with a valid when last used program shouldn't generate a GL error
PASS getError was expected value: NO_ERROR : delete the current program shouldn't change the current rendering state
PASS getError was expected value: NO_ERROR : The current program shouldn't be deleted
PASS good fragment shader should compile
PASS getError was expected value: INVALID_VALUE : an unattached shader should be deleted immediately
PASS good fragment shader should compile
PASS an attached shader shouldn't be deleted
PASS getError was expected value: INVALID_VALUE : a delete-marked program should be deleted once it's no longer the current program
PASS getError was expected value: INVALID_VALUE : a delete-marked shader should be deleted once all its attachments are removed
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -75,8 +75,7 @@ function go() {
assertMsg(gl.getShaderParameter(fsBad, gl.COMPILE_STATUS) == false,
"bad fragment shader should fail to compile");
assertMsg(gl.getError() == gl.NO_ERROR,
"should be no errors at this point");
glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors at this point");
/////// Check attachShader() /////////////////////////////
......@@ -87,7 +86,7 @@ function go() {
if(gl.getError() != gl.NO_ERROR)
assertMsg(false, "unexpected error in attachShader()");
gl.attachShader(prog, shader);
assertMsg(gl.getError() == expected_error_code, errmsg);
glErrorShouldBe(gl, expected_error_code, errmsg);
}
checkAttachShader([], vs, gl.NO_ERROR, "attaching a vertex shader should succeed");
......@@ -96,6 +95,10 @@ function go() {
checkAttachShader([], fs, gl.NO_ERROR, "attaching a fragment shader should succeed");
checkAttachShader([fs], fs, gl.INVALID_OPERATION,
"attaching an already attached fragment shader should generate INVALID_OPERATION");
checkAttachShader([vs], vs2, gl.INVALID_OPERATION,
"attaching shaders of the same type to a program should generate INVALID_OPERATION");
checkAttachShader([fs], fs2, gl.INVALID_OPERATION,
"attaching shaders of the same type to a program should generate INVALID_OPERATION");
/////// Check detachShader() /////////////////////////////
......@@ -106,7 +109,7 @@ function go() {
if(gl.getError() != gl.NO_ERROR)
assertMsg(false, "unexpected error in attachShader()");
gl.detachShader(prog, shader);
assertMsg(gl.getError() == expected_error_code, errmsg);
glErrorShouldBe(gl, expected_error_code, errmsg);
}
checkDetachShader([vs], vs, gl.NO_ERROR, "detaching a vertex shader should succeed");
......@@ -132,28 +135,31 @@ function go() {
}
checkGetAttachedShaders([], [], [], "getAttachedShaders should return an empty list by default");
checkGetAttachedShaders([fs], [], [fs], "attaching a single shader should give the expected list");
checkGetAttachedShaders([fs, vs, fs2, vs2], [], [fs, vs, fs2, vs2],
checkGetAttachedShaders([fs, vs], [], [fs, vs],
"attaching some shaders should give the expected list");
checkGetAttachedShaders([fs], [fs], [], "attaching a shader and detaching it shoud leave an empty list");
checkGetAttachedShaders([fs, vs, fs2, vs2], [fs, vs, fs2, vs2], [],
checkGetAttachedShaders([fs, vs], [fs, vs], [],
"attaching some shaders and detaching them in same order shoud leave an empty list");
checkGetAttachedShaders([fs, vs, fs2, vs2], [fs, vs2, vs, fs2], [],
checkGetAttachedShaders([fs, vs], [vs, fs], [],
"attaching some shaders and detaching them in random order shoud leave an empty list");
checkGetAttachedShaders([fs, vs, fs2, vs2], [vs], [fs, fs2, vs2],
checkGetAttachedShaders([fs, vs], [vs], [fs],
"attaching and detaching some shaders should leave the difference list");
checkGetAttachedShaders([fs, vs, fs2, vs2], [fs, vs2], [vs, fs2],
checkGetAttachedShaders([fs, vs], [fs], [vs],
"attaching and detaching some shaders should leave the difference list");
checkGetAttachedShaders([fsBad], [], [fsBad],
"attaching a shader that failed to compile should still show it in the list");
checkGetAttachedShaders([fs, vsBad, fs2], [], [fs, vsBad, fs2],
checkGetAttachedShaders([fs, vsBad], [], [fs, vsBad],
"attaching shaders, including one that failed to compile, should still show the it in the list");
/////// Check linkProgram() and useProgram /////////////////////////////
function checkLinkAndUse(shaders, expected_status, errmsg) {
function checkLinkAndUse(shaders, deleteShaderAfterAttach, expected_status, errmsg) {
var prog = gl.createProgram();
for (var i = 0; i < shaders.length; ++i)
for (var i = 0; i < shaders.length; ++i) {
gl.attachShader(prog, shaders[i]);
if (deleteShaderAfterAttach)
gl.deleteShader(shaders[i]);
}
gl.bindAttribLocation(prog, 0, "aVertex");
gl.bindAttribLocation(prog, 1, "aColor");
gl.linkProgram(prog);
......@@ -166,23 +172,22 @@ function go() {
assertMsg(false, "unexpected error in getProgramParameter()");
gl.useProgram(prog);
if (expected_status == true)
assertMsg(gl.getError() == gl.NO_ERROR, "using a valid program should succeed");
glErrorShouldBe(gl, gl.NO_ERROR, "using a valid program should succeed");
if (expected_status == false)
assertMsg(gl.getError() == gl.INVALID_OPERATION, "using an invalid program should generate INVALID_OPERATION");
glErrorShouldBe(gl, gl.INVALID_OPERATION, "using an invalid program should generate INVALID_OPERATION");
return prog;
}
var progGood1 = checkLinkAndUse([vs, fs], true, "valid program should link");
var progGood2 = checkLinkAndUse([vs, fs2], true, "valid program #2 should link");
var progBad1 = checkLinkAndUse([vs], false, "program with no fragment shader should fail to link");
var progBad2 = checkLinkAndUse([fs], false, "program with no vertex shader should fail to link");
var progBad3 = checkLinkAndUse([vsBad, fs], false, "program with bad vertex shader should fail to link");
var progBad4 = checkLinkAndUse([vs, fsBad], false, "program with bad fragment shader should fail to link");
var progBad5 = checkLinkAndUse([vsBad, fsBad], false, "program with bad shaders should fail to link");
var progGood1 = checkLinkAndUse([vs, fs], false, true, "valid program should link");
var progGood2 = checkLinkAndUse([vs, fs2], false, true, "valid program #2 should link");
var progBad1 = checkLinkAndUse([vs], false, false, "program with no fragment shader should fail to link");
var progBad2 = checkLinkAndUse([fs], false, false, "program with no vertex shader should fail to link");
var progBad3 = checkLinkAndUse([vsBad, fs], false, false, "program with bad vertex shader should fail to link");
var progBad4 = checkLinkAndUse([vs, fsBad], false, false, "program with bad fragment shader should fail to link");
var progBad5 = checkLinkAndUse([vsBad, fsBad], false, false, "program with bad shaders should fail to link");
gl.useProgram(progGood1);
assertMsg(gl.getError() == gl.NO_ERROR,
"using a valid program shouldn't generate a GL error");
glErrorShouldBe(gl, gl.NO_ERROR, "using a valid program shouldn't generate a GL error");
var vbuf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbuf);
......@@ -197,22 +202,21 @@ function go() {
gl.enableVertexAttribArray(0);
gl.vertexAttrib3f(1, 1.0, 0.0, 0.0);
assertMsg(gl.getError() == gl.NO_ERROR,
"should be no errors at this point #2");
glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors at this point #2");
gl.useProgram(progGood1);
gl.drawArrays(gl.TRIANGLES, 0, 3);
assertMsg(gl.getError() == gl.NO_ERROR,
"drawing with a valid program shouldn't generate a GL error");
glErrorShouldBe(gl, gl.NO_ERROR, "drawing with a valid program shouldn't generate a GL error");
gl.useProgram(progBad1);
assertMsg(gl.getError() == gl.INVALID_OPERATION,
"using an invalid program should generate INVALID_OPERATION");
glErrorShouldBe(gl, gl.INVALID_OPERATION, "using an invalid program should generate INVALID_OPERATION");
gl.drawArrays(gl.TRIANGLES, 0, 3);
assertMsg(gl.getError() != gl.NO_ERROR,
"drawing with an invalid program should generate some GL error XXX");
glErrorShouldBe(gl, gl.NO_ERROR, "Try to use an invalid program should not change the current rendering state");
gl.useProgram(progGood2);
gl.drawArrays(gl.TRIANGLES, 0, 3);
glErrorShouldBe(gl, gl.NO_ERROR, "drawing with a valid program shouldn't generate a GL error");
gl.detachShader(progGood2, fs2);
gl.attachShader(progGood2, fsBad);
gl.linkProgram(progGood2);
assertMsg(gl.getProgramParameter(progGood2, gl.LINK_STATUS) == false,
......@@ -220,14 +224,61 @@ function go() {
gl.useProgram(progGood1);
gl.drawArrays(gl.TRIANGLES, 0, 4);
assertMsg(gl.getError() == gl.NO_ERROR,
"drawing with a valid when last used program shouldn't generate a GL error");
glErrorShouldBe(gl, gl.NO_ERROR, "drawing with a valid when last used program shouldn't generate a GL error");
var progGood1 = checkLinkAndUse([vs, fs], true, true, "delete shaders after attaching them and before linking program should not affect linkProgram");
gl.useProgram(progGood1);
gl.drawArrays(gl.TRIANGLES, 0, 4);
glErrorShouldBe(gl, gl.NO_ERROR, "drawing with a valid when last used program shouldn't generate a GL error");
/////// Check deleteProgram() and deleteShader() /////////////////////////////
gl.useProgram(progGood1);
gl.deleteProgram(progGood1);
gl.drawArrays(gl.TRIANGLES, 0, 4);
glErrorShouldBe(gl, gl.NO_ERROR, "delete the current program shouldn't change the current rendering state");
gl.linkProgram(progGood1);
glErrorShouldBe(gl, gl.NO_ERROR, "The current program shouldn't be deleted");
var fs3 = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs3, "#ifdef GL_ES\nprecision mediump float;\n#endif\n varying vec4 vColor; void main() { gl_FragColor = vColor; }");
gl.compileShader(fs3);
assertMsg(gl.getShaderParameter(fs3, gl.COMPILE_STATUS) == true,
"good fragment shader should compile");
gl.deleteShader(fs3);
gl.compileShader(fs3);
glErrorShouldBe(gl, gl.INVALID_VALUE, "an unattached shader should be deleted immediately");
fs3 = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs3, "#ifdef GL_ES\nprecision mediump float;\n#endif\n varying vec4 vColor; void main() { gl_FragColor = vColor; }");
gl.compileShader(fs3);
assertMsg(gl.getShaderParameter(fs3, gl.COMPILE_STATUS) == true,
"good fragment shader should compile");
gl.detachShader(progGood1, fs);
gl.attachShader(progGood1, fs3);
gl.deleteShader(fs3);
gl.compileShader(fs3);
assertMsg(gl.getShaderParameter(fs3, gl.COMPILE_STATUS) == true,
"an attached shader shouldn't be deleted");
gl.useProgram(null);
gl.linkProgram(progGood1);
glErrorShouldBe(gl, gl.INVALID_VALUE, "a delete-marked program should be deleted once it's no longer the current program");
gl.compileShader(fs3);
glErrorShouldBe(gl, gl.INVALID_VALUE, "a delete-marked shader should be deleted once all its attachments are removed");
}
debug("");
successfullyParsed = true;
go();
successfullyParsed = true;
</script>
<script src="../../js/resources/js-test-post.js"></script>
......
2010-08-11 Zhenyao Mo <zmo@google.com>
Reviewed by Dimitri Glazkov.
Regression in linking of programs
https://bugs.webkit.org/show_bug.cgi?id=43820
Shaders and programs shouldn't be deleted until their attachments are removed, therefore, we need to track the attach/detach/useProgram.
* html/canvas/WebGLObject.cpp: Track the object attachment count and whether it should really be deleted.
(WebCore::WebGLObject::WebGLObject):
(WebCore::WebGLObject::setObject):
(WebCore::WebGLObject::deleteObject):
* html/canvas/WebGLObject.h: Track the object attachment count and whether it should really be deleted.
(WebCore::WebGLObject::onAttached):
(WebCore::WebGLObject::onDetached):
(WebCore::WebGLObject::getAttachmentCount):
* html/canvas/WebGLProgram.cpp: Track the attached shaders.
(WebCore::WebGLProgram::WebGLProgram):
(WebCore::WebGLProgram::deleteObjectImpl):
(WebCore::WebGLProgram::getAttachedShader):
(WebCore::WebGLProgram::attachShader):
(WebCore::WebGLProgram::detachShader):
* html/canvas/WebGLProgram.h: Track the attached shaders.
* html/canvas/WebGLRenderingContext.cpp:
(WebCore::WebGLRenderingContext::attachShader): Track the attachment of a shader to a program.
(WebCore::WebGLRenderingContext::deleteProgram): Detach shaders.
(WebCore::WebGLRenderingContext::detachShader): Track the attachment of a shader to a program.
(WebCore::WebGLRenderingContext::validateWebGLObject): Also check if object == 0.
(WebCore::WebGLRenderingContext::linkProgram): Using the cached attached shaders instead of query from driver.
(WebCore::WebGLRenderingContext::useProgram): Track the attachment of a program to the current rendering pipeline.
2010-08-13 Steve Block <steveblock@google.com>
Reviewed by Alexey Proskuryakov.
......@@ -35,8 +35,9 @@ namespace WebCore {
WebGLObject::WebGLObject(WebGLRenderingContext* context)
: m_object(0)
, m_shouldDeleteObject(true)
, m_context(context)
, m_attachmentCount(0)
, m_deleted(false)
{
}
......@@ -46,27 +47,26 @@ WebGLObject::~WebGLObject()
m_context->removeObject(this);
}
void WebGLObject::setObject(Platform3DObject object, bool shouldDeleteObject)
void WebGLObject::setObject(Platform3DObject object)
{
if (object == m_object)
return;
deleteObject();
m_object = object;
m_shouldDeleteObject = shouldDeleteObject;
}
void WebGLObject::deleteObject()
{
if (m_object) {
if (m_shouldDeleteObject)
if (m_context) {
m_context->graphicsContext3D()->makeContextCurrent();
deleteObjectImpl(m_object);
}
m_object = 0;
if (m_context) {
m_context->graphicsContext3D()->makeContextCurrent();
deleteObjectImpl(m_object);
}
if (!m_attachmentCount)
m_object = 0;
m_deleted = true;
}
m_shouldDeleteObject = true;
}
}
......
......@@ -40,7 +40,7 @@ public:
virtual ~WebGLObject();
Platform3DObject object() const { return m_object; }
void setObject(Platform3DObject, bool shouldDeleteObject = true);
void setObject(Platform3DObject);
void deleteObject();
void detachContext()
......@@ -58,20 +58,25 @@ public:
virtual bool isShader() const { return false; }
virtual bool isTexture() const { return false; }
void onAttached() { ++m_attachmentCount; }
void onDetached()
{
if (m_attachmentCount)
--m_attachmentCount;
if (!m_attachmentCount && m_deleted)
m_object = 0;
}
unsigned getAttachmentCount() { return m_attachmentCount; }
protected:
WebGLObject(WebGLRenderingContext*);
virtual void deleteObjectImpl(Platform3DObject) = 0;
private:
Platform3DObject m_object;
// The shouldDeleteObject flag indicates whether this wrapper
// owns the underlying resource and should delete it when the
// wrapper is unreferenced for the last time and deleted. It
// is only set to false for certain objects returned from get
// queries. FIXME: should consider canonicalizing all of these
// objects in the future.
bool m_shouldDeleteObject;
WebGLRenderingContext* m_context;
unsigned m_attachmentCount;
bool m_deleted;
};
} // namespace WebCore
......
......@@ -45,9 +45,15 @@ WebGLProgram::WebGLProgram(WebGLRenderingContext* ctx)
setObject(context()->graphicsContext3D()->createProgram());
}
void WebGLProgram::deleteObjectImpl(Platform3DObject object)
void WebGLProgram::deleteObjectImpl(Platform3DObject obj)
{
context()->graphicsContext3D()->deleteProgram(object);
context()->graphicsContext3D()->deleteProgram(obj);
if (!object()) {
if (m_vertexShader)
m_vertexShader->onDetached();
if (m_fragmentShader)
m_fragmentShader->onDetached();
}
}
bool WebGLProgram::cacheActiveAttribLocations()
......@@ -94,6 +100,58 @@ bool WebGLProgram::isUsingVertexAttrib0() const
return false;
}
WebGLShader* WebGLProgram::getAttachedShader(GraphicsContext3D::WebGLEnumType type)
{
switch (type) {
case GraphicsContext3D::VERTEX_SHADER:
return m_vertexShader.get();
case GraphicsContext3D::FRAGMENT_SHADER:
return m_fragmentShader.get();
default:
return 0;
}
}
bool WebGLProgram::attachShader(WebGLShader* shader)
{
if (!shader || !shader->object())
return false;
switch (shader->getType()) {
case GraphicsContext3D::VERTEX_SHADER:
if (m_vertexShader)
return false;
m_vertexShader = shader;
return true;
case GraphicsContext3D::FRAGMENT_SHADER:
if (m_fragmentShader)
return false;
m_fragmentShader = shader;
return true;
default:
return false;
}
}
bool WebGLProgram::detachShader(WebGLShader* shader)
{
if (!shader || !shader->object())
return false;
switch (shader->getType()) {
case GraphicsContext3D::VERTEX_SHADER:
if (m_vertexShader != shader)
return false;
m_vertexShader = 0;
return true;
case GraphicsContext3D::FRAGMENT_SHADER:
if (m_fragmentShader != shader)
return false;
m_fragmentShader = 0;
return true;
default:
return false;
}
}
}
#endif // ENABLE(3D_CANVAS)
......@@ -28,6 +28,8 @@
#include "WebGLObject.h"
#include "WebGLShader.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/Vector.h>
......@@ -54,6 +56,10 @@ public:
bool isLinkFailureFlagSet() const { return m_linkFailure; }
void setLinkFailureFlag(bool failed) { m_linkFailure = failed; }
WebGLShader* getAttachedShader(GraphicsContext3D::WebGLEnumType);
bool attachShader(WebGLShader*);
bool detachShader(WebGLShader*);
protected:
WebGLProgram(WebGLRenderingContext*);
......@@ -65,6 +71,9 @@ private:
Vector<int> m_activeAttribLocations;
bool m_linkFailure;
RefPtr<WebGLShader> m_vertexShader;
RefPtr<WebGLShader> m_fragmentShader;
};
} // namespace WebCore
......
......@@ -217,7 +217,12 @@ void WebGLRenderingContext::attachShader(WebGLProgram* program, WebGLShader* sha
UNUSED_PARAM(ec);
if (!validateWebGLObject(program) || !validateWebGLObject(shader))
return;
if (!program->attachShader(shader)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
m_context->attachShader(objectOrZero(program), objectOrZero(shader));
shader->onAttached();
cleanupAfterGraphicsCall(false);
}
......@@ -650,7 +655,12 @@ void WebGLRenderingContext::deleteProgram(WebGLProgram* program)
{
if (!program)
return;
if (program->context() != this) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
if (!program->object())
return;
program->deleteObject();
}
......@@ -705,7 +715,12 @@ void WebGLRenderingContext::detachShader(WebGLProgram* program, WebGLShader* sha
UNUSED_PARAM(ec);
if (!validateWebGLObject(program) || !validateWebGLObject(shader))
return;
if (!program->detachShader(shader)) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
m_context->detachShader(objectOrZero(program), objectOrZero(shader));
shader->onDetached();
cleanupAfterGraphicsCall(false);
}
......@@ -892,7 +907,7 @@ bool WebGLRenderingContext::validateRenderingState(long numElementsRequired)
bool WebGLRenderingContext::validateWebGLObject(WebGLObject* object)
{
if (!object) {
if (!object || !object->object()) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_VALUE);
return false;
}
......@@ -1882,21 +1897,7 @@ void WebGLRenderingContext::linkProgram(WebGLProgram* program, ExceptionCode& ec
if (!validateWebGLObject(program))
return;
if (!isGLES2Compliant()) {
Vector<WebGLShader*> shaders;
bool succeed = getAttachedShaders(program, shaders, ec);
if (succeed) {
bool vShader = false;
bool fShader = false;
for (size_t ii = 0; ii < shaders.size() && (!vShader || !fShader); ++ii) {
if (shaders[ii]->getType() == GraphicsContext3D::VERTEX_SHADER)
vShader = true;
else if (shaders[ii]->getType() == GraphicsContext3D::FRAGMENT_SHADER)
fShader = true;
}
if (!vShader || !fShader)
succeed = false;
}
if (!succeed) {
if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
program->setLinkFailureFlag(true);
return;
}
......@@ -2701,13 +2702,23 @@ void WebGLRenderingContext::uniformMatrix4fv(const WebGLUniformLocation* locatio
void WebGLRenderingContext::useProgram(WebGLProgram* program, ExceptionCode& ec)
{
UNUSED_PARAM(ec);
if (program && program->context() != this) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
return;
}
m_currentProgram = program;
m_context->useProgram(objectOrZero(program));
if (program && program->object() && !getProgramParameter(program, GraphicsContext3D::LINK_STATUS, ec).getBool()) {
m_context->synthesizeGLError(GraphicsContext3D::INVALID_OPERATION);
cleanupAfterGraphicsCall(false);
return;
}
if (m_currentProgram != program) {