Bug 43820 - Regression in linking of programs
Summary: Regression in linking of programs
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebGL (show other bugs)
Version: 528+ (Nightly build)
Hardware: All All
: P2 Normal
Assignee: Zhenyao Mo
URL:
Keywords:
Depends on: 41380
Blocks: 43942
  Show dependency treegraph
 
Reported: 2010-08-10 17:38 PDT by Kenneth Russell
Modified: 2010-08-13 10:51 PDT (History)
6 users (show)

See Also:


Attachments
patch (30.39 KB, patch)
2010-08-11 20:45 PDT, Zhenyao Mo
zmo: commit-queue-
Details | Formatted Diff | Diff
revised patch: use RefPtr for shader members in WebGLProgram (30.27 KB, patch)
2010-08-12 16:25 PDT, Zhenyao Mo
zmo: commit-queue-
Details | Formatted Diff | Diff
revised patch: no need to initialize RefPtr. (30.11 KB, patch)
2010-08-12 16:30 PDT, Zhenyao Mo
dglazkov: review+
zmo: commit-queue-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Kenneth Russell 2010-08-10 17:38:14 PDT
https://bugs.webkit.org/show_bug.cgi?id=41380 introduced a regression in the linking of programs when the shaders are first attached to a program, then deleted, and then the program is linked. The WebGLShader object has its m_object cleared when deleteShader is called from JavaScript. Later, during linkProgram, the WebGLRenderingContext attempts to look up the WebGLShaderObject associated with the program and fails.

The validation of the attached shaders' types must be done with GraphicsContext3D calls instead, calling getShaderiv(shader, SHADER_TYPE, &val).
Comment 1 Zhenyao Mo 2010-08-11 11:13:26 PDT
The real problem is when we deleteShader, if a shader is attached to a program, it's not really deleted; instead, DELETE_STATUS is set to true.  Currently in deleteShader, the name in WebGLShader is always set to 0.  Therefore, when we call getAttachedShaders(), we can't find any matching WebGLShader objects.

The fix should be tracking whether a shader is attached and don't set the name in WebGLShader to 0 when deleteShader if it is attached.
Comment 2 Kenneth Russell 2010-08-11 11:28:09 PDT
(In reply to comment #1)
> The real problem is when we deleteShader, if a shader is attached to a program, it's not really deleted; instead, DELETE_STATUS is set to true.  Currently in deleteShader, the name in WebGLShader is always set to 0.  Therefore, when we call getAttachedShaders(), we can't find any matching WebGLShader objects.
> 
> The fix should be tracking whether a shader is attached and don't set the name in WebGLShader to 0 when deleteShader if it is attached.

This isn't the only situation in which the WebGLObject wrappers might get out of sync with the underlying OpenGL resources. Another example would be WebGLRenderbuffer. When a renderbuffer is attached to a framebuffer object, the framebuffer references it, and even if the renderbuffer is deleted, it is still referenced until detached from the framebuffer (or the framebuffer is deleted). In order to properly handle lookups of these renderbuffers, we would need to also track whether they are attached to a framebuffer at the time they are deleted. This tracking logic will quickly become complicated; it will be needed for nearly every WebGLObject subclass.

I believe the correct fix is to avoid looking up the WebGLShader object at all, and simply perform the needed queries against the underlying OpenGL shader object.
Comment 3 Zhenyao Mo 2010-08-11 13:44:41 PDT
(In reply to comment #2)
> (In reply to comment #1)
> > The real problem is when we deleteShader, if a shader is attached to a program, it's not really deleted; instead, DELETE_STATUS is set to true.  Currently in deleteShader, the name in WebGLShader is always set to 0.  Therefore, when we call getAttachedShaders(), we can't find any matching WebGLShader objects.
> > 
> > The fix should be tracking whether a shader is attached and don't set the name in WebGLShader to 0 when deleteShader if it is attached.
> 
> This isn't the only situation in which the WebGLObject wrappers might get out of sync with the underlying OpenGL resources. Another example would be WebGLRenderbuffer. When a renderbuffer is attached to a framebuffer object, the framebuffer references it, and even if the renderbuffer is deleted, it is still referenced until detached from the framebuffer (or the framebuffer is deleted). In order to properly handle lookups of these renderbuffers, we would need to also track whether they are attached to a framebuffer at the time they are deleted. This tracking logic will quickly become complicated; it will be needed for nearly every WebGLObject subclass.
> 
> I believe the correct fix is to avoid looking up the WebGLShader object at all, and simply perform the needed queries against the underlying OpenGL shader object.

If we don't track WebGLShader objects, in the case of getAttachedShaders() we have to create a second WebGLShader object where the underlying name is the same as the original WebGLShader object.  This will really be confusing.

So at least for the case of WebGLShader, I think we should do the tracking.
Comment 4 Kenneth Russell 2010-08-11 14:05:25 PDT
(In reply to comment #3)
> (In reply to comment #2)
> > (In reply to comment #1)
> > > The real problem is when we deleteShader, if a shader is attached to a program, it's not really deleted; instead, DELETE_STATUS is set to true.  Currently in deleteShader, the name in WebGLShader is always set to 0.  Therefore, when we call getAttachedShaders(), we can't find any matching WebGLShader objects.
> > > 
> > > The fix should be tracking whether a shader is attached and don't set the name in WebGLShader to 0 when deleteShader if it is attached.
> > 
> > This isn't the only situation in which the WebGLObject wrappers might get out of sync with the underlying OpenGL resources. Another example would be WebGLRenderbuffer. When a renderbuffer is attached to a framebuffer object, the framebuffer references it, and even if the renderbuffer is deleted, it is still referenced until detached from the framebuffer (or the framebuffer is deleted). In order to properly handle lookups of these renderbuffers, we would need to also track whether they are attached to a framebuffer at the time they are deleted. This tracking logic will quickly become complicated; it will be needed for nearly every WebGLObject subclass.
> > 
> > I believe the correct fix is to avoid looking up the WebGLShader object at all, and simply perform the needed queries against the underlying OpenGL shader object.
> 
> If we don't track WebGLShader objects, in the case of getAttachedShaders() we have to create a second WebGLShader object where the underlying name is the same as the original WebGLShader object.  This will really be confusing.
> 
> So at least for the case of WebGLShader, I think we should do the tracking.

OK, I see your point about the public APIs needing to work properly. Agreed, the best way to make both work is to track whether a given shader has really been deleted, or whether it is still referenced from a program.
Comment 5 Zhenyao Mo 2010-08-11 20:45:01 PDT
Created attachment 64184 [details]
patch

The test is in sync with khronos.

Also tested: the previously failed WebGL Google demos run OK with this patch.
Comment 6 Kenneth Russell 2010-08-12 15:31:37 PDT
Comment on attachment 64184 [details]
patch

Overall the patch looks good; thanks for taking care of this quickly. The new tests look good.

WebCore/html/canvas/WebGLProgram.h:76
 +      WebGLShader* m_fragmentShader;
There's a deep issue here related to the lifetime of WebGLObjects. Because they are reference counted, they can theoretically be deleted at any time. (The global HashSet of RefPtrs to WebGLObjects in the WebGLRenderingContext prevents this somewhat, but there are still problems because the order the objects are stored in that HashSet is not guaranteed, so neither is deletion order.) These raw pointers may therefore go bad spontaneously. I think the only solution is to make these RefPtrs. I also think it would be great if we could just reuse the RefCounted mechanism rather than adding the new onAttached/onDetached, but I think it would be tricky -- likely involving logic like "if (refCount() <= 2) m_object = 0;" -- and also I'm not 100% sure we would be able to intercept the ref() / deref() calls since they aren't virtual in RefCountedBase. (I think since RefPtr always calls against the most specifically available subclass that we could simply shadow the superclass version and explicitly call it.)

Please make these RefPtrs and re-test. Thanks.
Comment 7 Zhenyao Mo 2010-08-12 16:25:04 PDT
Created attachment 64281 [details]
revised patch: use RefPtr for shader members in WebGLProgram

no other change
Comment 8 Kenneth Russell 2010-08-12 16:27:29 PDT
Comment on attachment 64281 [details]
revised patch: use RefPtr for shader members in WebGLProgram

Looks good to me -- assuming this change builds and was re-tested.
Comment 9 Zhenyao Mo 2010-08-12 16:30:05 PDT
Created attachment 64282 [details]
revised patch: no need to initialize RefPtr.
Comment 10 Kenneth Russell 2010-08-12 16:48:06 PDT
Comment on attachment 64282 [details]
revised patch: no need to initialize RefPtr.

Looks fine.
Comment 11 Dimitri Glazkov (Google) 2010-08-12 19:21:27 PDT
Comment on attachment 64282 [details]
revised patch: no need to initialize RefPtr.

Ok, but the attach/detach logic looks very similar to RefCounted. Can we just reuse that somehow?
Comment 12 Kenneth Russell 2010-08-12 19:36:14 PDT
(In reply to comment #11)
> (From update of attachment 64282 [details])
> Ok, but the attach/detach logic looks very similar to RefCounted. Can we just reuse that somehow?

Mo and I talked about this, but at least for the initial version we'd like to keep it separate. More thought is needed on exactly how the RefCounted reference count maps to the numbers we would need to track to decide when to delete the underlying OpenGL resource (see my comment above about "refCount() <= 2").
Comment 13 Zhenyao Mo 2010-08-13 10:12:40 PDT
Committed r65330: <http://trac.webkit.org/changeset/65330>
Comment 14 WebKit Review Bot 2010-08-13 10:51:59 PDT
http://trac.webkit.org/changeset/65330 might have broken SnowLeopard Intel Release (Tests)