Bug 94036 - [WebGL] program should not be able to link if a bad shader is attached
Summary: [WebGL] program should not be able to link if a bad shader is attached
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebGL (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Dean Jackson
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2012-08-14 16:08 PDT by Dean Jackson
Modified: 2013-10-05 12:26 PDT (History)
14 users (show)

See Also:


Attachments
Patch (7.19 KB, patch)
2012-10-10 18:54 PDT, Roger Fong
no flags Details | Formatted Diff | Diff
Patch (5.16 KB, patch)
2013-10-04 18:12 PDT, Dean Jackson
darin: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Dean Jackson 2012-08-14 16:08:43 PDT
WebGL conformance test suite build: 5a7a067ead6 Tue Aug 7 14:34:42 2012 -0700
WebKit: r125123 on Mountain Lion 12A269
GPU: AMD Radeon HD 6750M 1024 MB (yes, fairly old)
Comment 1 Radar WebKit Bug Importer 2012-08-14 16:08:57 PDT
<rdar://problem/12099740>
Comment 2 Roger Fong 2012-10-10 18:40:28 PDT
Khronos WebGL test fails as a result:
conformance/programs/program-test.html failing on Apple Mountain Lion
Comment 3 Roger Fong 2012-10-10 18:54:47 PDT
Created attachment 168122 [details]
Patch
Comment 4 Peter Beverloo (cr-android ews) 2012-10-10 20:39:02 PDT
Comment on attachment 168122 [details]
Patch

Attachment 168122 [details] did not pass cr-android-ews (chromium-android):
Output: http://queues.webkit.org/results/14254399
Comment 5 WebKit Review Bot 2012-10-10 21:10:58 PDT
Comment on attachment 168122 [details]
Patch

Attachment 168122 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/14255431
Comment 6 Dean Jackson 2012-10-11 12:19:34 PDT
Comment on attachment 168122 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=168122&action=review

> Source/WebCore/html/canvas/WebGLShader.h:46
> +    bool isValid() const { return m_valid; }

I think this should be just valid(), but see below about avoiding this.

> Source/WebCore/platform/graphics/GraphicsContext3D.h:677
> -    void compileShader(Platform3DObject);
> +    bool compileShader(Platform3DObject);

Unfortunately this change will require a fair amount of coordination with other platforms, in particular Chromium (who have a bunch of proxies implementing this API, some in the Chromium project).

Let's see if we can come up with another way to do this. ShaderSourceEntry already has a "valid" flag that doesn't seem to be used.

> Source/WebCore/platform/graphics/opengl/GraphicsContext3DOpenGLCommon.cpp:449
>      if (!translatedShaderSource.length())
> -        return;
> +        return false;

OK. Maybe we can do it here! If the validation failed, then get the entry in the Shader Source map and set it to invalid. (In fact, why not set it true/false for every shader?). Hmm... nope, then we'd still need to either update GC3D to have API testing for valid shaders, or have linkProgram repeat the test and communicate the failure.

How does Chrome pass this? Do they detach the shader if it fails validation? I'll need to think about this for a moment.
Comment 7 Dean Jackson 2012-10-11 12:20:01 PDT
Ken, can you give advice here?
Comment 8 Kenneth Russell 2012-10-11 12:46:57 PDT
I don't know off the top of my head how this is implemented in Chrome, but Gregg's command buffer implementation tracks a lot of information about shader and program objects, and is probably caching the state so that it looks like a compilation failure and can be queried as such through getShaderParameter.
Comment 9 Roger Fong 2012-10-11 14:18:58 PDT
Something else I was unsure about was m_linkStatus.
Right it gets set to false when either the vertex or fragment shader is null before the linking happens.

Should it also be false if the the shader source doesn't compile?

I guess the question boils down to:
Should m_linkStatus be false when the state of the attached shaders is bad in general (either null or does not compile) or just when a shader is missing?

If it's the former then I'll need to find a way to access the m_shaderSourceMap from WebGLRenderingContext.
Comment 10 Gregg Tavares 2012-10-11 15:47:11 PDT
not looking at the code, only responding the comment.

The only thing that effects link status is glLinkProgram

You can attach shaders, delete shaders, they can fail to compile, whatever but until you call glLinkProgram again the link status will not change. At that time, it will try to link the 2 shaders. If one of them is bad or missing it will not link and link status will be set to failed.  

Note that the failing for a missing shader has to be emulated on desktop GL as missing shaders fall back to fixed function behavior on desktop GL.
Comment 11 Roger Fong 2012-10-11 18:48:13 PDT
I'm gonna throw out some thoughts about this and maybe someone can tell me if what I'm thinking is wrong:

The code for linkProgram in WebGLRC looks like this:

    if (!isGLES2Compliant()) {
        if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
            program->setLinkStatus(false);
            return;
        }
    }

(At least the part we care about).

With a bad shader, it must get to the program->setLinkStatus(false), but check that's performed on the shader is the !program->getAttachedShader, which just returns the shader itself on the WebGLProgram.

The shader is not going to be null if it's bad...so how does this test pass anywhere?
Comment 12 Roger Fong 2012-10-11 18:55:56 PDT
Just noticed there's a method I can use from WebGLRC that you can look for shader compile status with...so I don't need GC3D's compileShader method to return anything...so doing that and using the extra flag in the WebGLShader I can make it work properly...

Still probably not the best solution though...
Comment 13 Roger Fong 2012-10-11 19:10:00 PDT
(In reply to comment #11)
> I'm gonna throw out some thoughts about this and maybe someone can tell me if what I'm thinking is wrong:
> 
> The code for linkProgram in WebGLRC looks like this:
> 
>     if (!isGLES2Compliant()) {
>         if (!program->getAttachedShader(GraphicsContext3D::VERTEX_SHADER) || !program->getAttachedShader(GraphicsContext3D::FRAGMENT_SHADER)) {
>             program->setLinkStatus(false);
>             return;
>         }
>     }
> 
> (At least the part we care about).
> 
> With a bad shader, it must get to the program->setLinkStatus(false), but check that's performed on the shader is the !program->getAttachedShader, which just returns the shader itself on the WebGLProgram.
> 
> The shader is not going to be null if it's bad...so how does this test pass anywhere?

O also, I tried not attaching the shader if the compiling failed, leaving the shader detached.
That causes another test to fail. The rule is apparently that the shader should get attached even if it's bad.
Comment 14 Dean Jackson 2012-10-17 17:45:19 PDT
(In reply to comment #10)
> not looking at the code, only responding the comment.
> 
> The only thing that effects link status is glLinkProgram
> 
> You can attach shaders, delete shaders, they can fail to compile, whatever but until you call glLinkProgram again the link status will not change. At that time, it will try to link the 2 shaders. If one of them is bad or missing it will not link and link status will be set to failed.  

Thanks Gregg. We're a little confused here because the test takes a working and linked program, attaches a bad shader, then attempts to link again. The link fails, as expected.

The bit we're breaking on is that the subsequent drawArrays call is producing INVALID_OPERATION, when the test expects it to work. The OpenGL spec says "If the program object currently in use is relinked unsuccessfully, its link status will be set to GL_FALSE , but the executables and associated state will remain part of the current state until a subsequent call to glUseProgram removes it from use. "

I assume this is why the test expects the drawArrays to pass, even though the linkProgram failed.

Since we're calling our platform glLinkProgram, I'm confused as to how Chromium is passing this test.  Do you actually call glLinkProgram when you have a shader attached that didn't compile?
Comment 15 Gregg Tavares 2012-10-18 10:08:27 PDT
No, we don't call LinkProgram if the shader didn't compile. We just synthesize a failed link status
Comment 16 Gregg Tavares 2012-10-18 10:13:59 PDT
The check you mentioned above that just checks that shaders are attached works around the difference mentioned above between ES and Desktop GL in that desktop GL will succeed even if no shaders are attached since it falls back  to fixed function operations in that case.
Comment 17 Dean Jackson 2012-10-19 11:43:38 PDT
(In reply to comment #16)
> The check you mentioned above that just checks that shaders are attached works around the difference mentioned above between ES and Desktop GL in that desktop GL will succeed even if no shaders are attached since it falls back  to fixed function operations in that case.

Got it, thanks.

Our problem is that we don't keep any program state in GC3D, the way Chromium does in your GPU command buffer implementation. Even if we tested the attached shaders to make sure they are valid, we have no way of propagating the link status.

This will be an easy addition into our port's version of GC3D.
Comment 18 Dean Jackson 2013-10-04 18:12:56 PDT
Created attachment 213429 [details]
Patch
Comment 19 Kenneth Russell 2013-10-04 18:47:47 PDT
Comment on attachment 213429 [details]
Patch

LGTM FWIW.
Comment 20 Darin Adler 2013-10-05 00:38:48 PDT
Comment on attachment 213429 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=213429&action=review

> Source/WebCore/html/canvas/WebGLRenderingContext.cpp:1301
> +    shader->setValid(!!value);

Don't need the !! with C++ bool; just "value" will work fine.
Comment 21 Dean Jackson 2013-10-05 12:26:32 PDT
Committed r156971: <http://trac.webkit.org/changeset/156971>