RESOLVED FIXED Bug 43820
Regression in linking of programs
https://bugs.webkit.org/show_bug.cgi?id=43820
Summary Regression in linking of programs
Kenneth Russell
Reported 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).
Attachments
patch (30.39 KB, patch)
2010-08-11 20:45 PDT, Zhenyao Mo
zmo: commit-queue-
revised patch: use RefPtr for shader members in WebGLProgram (30.27 KB, patch)
2010-08-12 16:25 PDT, Zhenyao Mo
zmo: commit-queue-
revised patch: no need to initialize RefPtr. (30.11 KB, patch)
2010-08-12 16:30 PDT, Zhenyao Mo
dglazkov: review+
zmo: commit-queue-
Zhenyao Mo
Comment 1 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.
Kenneth Russell
Comment 2 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.
Zhenyao Mo
Comment 3 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.
Kenneth Russell
Comment 4 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.
Zhenyao Mo
Comment 5 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.
Kenneth Russell
Comment 6 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.
Zhenyao Mo
Comment 7 2010-08-12 16:25:04 PDT
Created attachment 64281 [details] revised patch: use RefPtr for shader members in WebGLProgram no other change
Kenneth Russell
Comment 8 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.
Zhenyao Mo
Comment 9 2010-08-12 16:30:05 PDT
Created attachment 64282 [details] revised patch: no need to initialize RefPtr.
Kenneth Russell
Comment 10 2010-08-12 16:48:06 PDT
Comment on attachment 64282 [details] revised patch: no need to initialize RefPtr. Looks fine.
Dimitri Glazkov (Google)
Comment 11 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?
Kenneth Russell
Comment 12 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").
Zhenyao Mo
Comment 13 2010-08-13 10:12:40 PDT
WebKit Review Bot
Comment 14 2010-08-13 10:51:59 PDT
http://trac.webkit.org/changeset/65330 might have broken SnowLeopard Intel Release (Tests)
Note You need to log in before you can comment on or make changes to this bug.