-
Notifications
You must be signed in to change notification settings - Fork 3.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GL_ENABLE_GET_PROC_ADDRESS #20802
GL_ENABLE_GET_PROC_ADDRESS #20802
Conversation
7e3c8b1
to
ad4240f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is quite a lot in the PR. Perhaps we could split out the adding of support for the new extensions? (that change could land either before or after the adding of the new setting).
7bd3f07
to
6f96eae
Compare
I really prefer not to. I don't think the changes here have large technical complexity itself, it is mostly all just plumbing changes. |
The one thing to consider here is that this will be a breaking change, and possibly could be a breaking change to surprisingly many Emscripten users that build GLFW/GLEW/EGL based projects, since after this PR they will need to start passing It looks like SDL currently unconditionally uses that, so to mitigate the churn, I did make it enabled by default for SDL targets at least. I suppose I could do the same for GLFW/GLEW/EGL as well if we are concerned. The recommendation for Filament would be to get rid of |
How about if we land this new setting and start by only enabling in That would allows us to defer to decision around how and when to start breaking other users. Regarding intercepting the wasm-ld error message and augmenting them.. that is something I've tried to avoid doing in the past and maybe we can avoid it here too: How about including a dummy version of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't think about the fact that the code size would only need to impact GetProcAddress builds which are already quite large. Nice!
Note I've proposed renaming EXT_polygon_offset_clamp and EXT_clip_control to the WebGL WG so Emscripten will have to make changes if they do. This is fine though.
LGTM with the caveat that I'll leave decisions about breaking changes to other maintainers. I think it's a good change though.
That in kind of my point though. All that unrelated plumbing boilerplate distracts from the functional stuff when trying to understand this PR. I won't push hard for this, because I know how busy you likely are, but IMHO its always best to separate these things out, for the sake of the review process and also for future us who may be bisecting these changes. |
1f1506e
to
9de57c1
Compare
Ok, removed the new extensions from this PR. Also added the link time errors, that was a great suggestion. With that, I would be happy to start breaking users directly, since the error message will clearly say what they need to do. |
7bf3263
to
4658b0e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
BTW, what do you you think about putting this behind -sSTRICT
first? (then there would be no changes to the test/ files needed as part of this PR). Maybe no need to such a period because we have good error reporting?
@@ -4,6 +4,8 @@ | |||
* University of Illinois/NCSA Open Source License. Both these licenses can be | |||
* found in the LICENSE file. | |||
*/ | |||
#if defined(__EMSCRIPTEN_FULL_ES3__) || MAX_WEBGL_VERSION >= 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this outer #if
required?
…ET_PROC_ADDRESS=1 so that we can restrict new GL extensions from being advertised in the future that *glGetProcAddress() cannot support.
4658b0e
to
fa94c64
Compare
My impression (given the "bad Emscripten" comments from linked thread) is that the WebGL people are regarding this to be a critical problem that prevents standardization from proceeding, so it doesn't seem like people should be given an opt-in choice. I am happy that there will be a meaningful error message that hints how to fix the build error at least. Maybe there won't be too many angry users with the help of that. I don't know if there are other users like Filament who might have an issue like this with their use of |
Sounds good to me. BTW what is '"bad Emscripten" comments from linked thread'? (Sorry I don't see the link ) |
@sbc100 This PR is meant to be linked with issue #20798 |
It seems like that issue relates to "advertising extension we don't implement", and not "glGetProcAddress bloats applications". IIUC fix for "advertising extension we don't implement" (i.e. the new setting in the title of this PR) is completely separate and unrelated the "advertising extension we don't implement". So just as a point of clarity, I don't think putting |
Maybe some typo?
No, the new flag is fundamental to the bugfix. Because there may exist codebases like Filament that depend on the fact that all enumerated GL extensions should be acquirable via Utopistically, the correct fix to synchronize these two would be to repair So the realistic second best thing instead is to limit WebGL contexts to only advertise extensions that match 1:1 what But that is a drastic pessimization in the big picture, and would be horrible to ship to all users, since only a small set of users utilize If we holistically applied this change to all codebases and not just those that use By adopting this flag, we can target the above two limitations only to developers who actually do use |
// If end user enables *glGetProcAddress() functionality, then we must filter out | ||
// all future WebGL extensions from being passed to the user, and only restrict to advertising | ||
// extensions that the *glGetProcAddress() function knows to handle. | ||
#if GL_ENABLE_GET_PROC_ADDRESS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about if the user calls glGetString(GL_EXTENSIONS)
but they don't set GL_ENABLE_GET_PROC_ADDRESS
? Is it OK that they see the full unfiltered list in this case?
Similarly emscripten_webgl_get_supported_extensions
.. if GL_ENABLE_GET_PROC_ADDRESS
is not set what do we expect it to return?
How about GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS which is enabled by default.. do we want to see the full unfiltered list by default?
How about the existing wrapping of getSupportedExtensions by GL_DISABLE_HALF_FLOAT_EXTENSION_IF_BROKEN? Does that wrapper simply layer in top of this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be OK to expose the unfiltered list in all cases when GetProcAddress is not enabled, because any code that uses an entry point Emscripten doesn't implement will cause a linker error. (And any extension that doesn't have entry points is OK.) It is a little unfortunate that they will have to #ifdef __EMSCRIPTEN__
though instead of #ifdef GL_EXT_clip_control
which many codebases will already have.
Come to think of it, it must be spec-valid in OpenGL for an implementation to list extensions that aren't available in the header - because you can use an older header with a newer driver. It's less guaranteed that applications would be robust to this though.
How about the existing wrapping of getSupportedExtensions by GL_DISABLE_HALF_FLOAT_EXTENSION_IF_BROKEN? Does that wrapper simply layer in top of this one?
That wrapper shadows WebGLRenderingContext.prototype.getSupportedExtensions
with ctx.getSupportedExtensions
so I think it will apply first (at the JS level) and then this patch will apply on top.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's less guaranteed that applications would be robust to this though.
Er, my point is, Emscripten could remove them from the header instead of filtering them out, and that would be a less robust but technically valid fix (that would work for Filament at least in this case).
Actually it would be more robust than I thought - if we did this, we'd be disabling not just the static entrypoint glClipControlEXT
, but also PFNGLCLIPCONTROLEXTPROC
which should be used by any program that's using GetProcAddress on that function. Example: https://github.com/google/filament/blob/b007e9137eb029e256675eceb5fd52e6b873cecd/filament/backend/src/opengl/gl_headers.h#L132
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about if the user calls glGetString(GL_EXTENSIONS) but they don't set GL_ENABLE_GET_PROC_ADDRESS? Is it OK that they see the full unfiltered list in this case?
Yes that is ok. That is just the common case as if user had hand-written native JavaScript code and called ctx.getSupportedExtensions()
in it.
Similarly emscripten_webgl_get_supported_extensions.. if GL_ENABLE_GET_PROC_ADDRESS is not set what do we expect it to return?
Same as above. All extensions that the WebGL implementation advertises, unfiltered.
How about GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS which is enabled by default.. do we want to see the full unfiltered list by default?
Yes. The root problem is in the use of the glGetProcAddress()
function, because it is unable to truly enumerate extensions.
How about the existing wrapping of getSupportedExtensions by GL_DISABLE_HALF_FLOAT_EXTENSION_IF_BROKEN? Does that wrapper simply layer in top of this one?
Yeah, the two things should cascade well together.
This breaks code building with new SDK, and once applied, it breaks build with old SDK. I had to add
|
This seems like a generic problem that exists whenever we add a new setting to emscripten. I suppose we could consider downgrading the However, I wonder if this isn't a normal/common thing with all compiler tools. When clang or gcc adds a new flag that flag isn't expected to be silently ignored by older versions of clang, is it? I would assume the solution would be to detect which version of emcc is being used and set the new flag accordingly.. isn't that how new flags work in most command line applications? |
I was pointed to this PR as a victim of this change. My CI builds suddenly stopped working. As a long time OpenGL user, the correct fix seems to me to be filtering the string returned by glGetExtensions to only include the extensions supported by the Emscripten OpenGL emulation. The other issue mentioned here, the code size when a glGetProcAddress function is used, seems a red herring. If the application is not calling a GetProcAddress function why is the code linked into it? |
Can I ask how this change broke your build? My understanding was that it should only have broken users who's programs reference the GetProcAddress family of function, but maybe I am misunderstanding? What error are you seeing? |
My code uses emscripten_GetProcAddress(). It uses *GetProcAddress because it is a part of a library which has many non-GL uses and I do not wish to force non-GL users to have to link with OpenGL. In native OpenGL you have to (a) check if the implementation supports an extension by calling Also the OpenGL spec. says "GetString returns ... the extension names (in the EXTENSIONS string) that can be supported by the current GL context. Thus, if the client and server support different ... extensions, a compatible ... list of extensions is returned." We may consider WebGL to be the server in this case and Emscripten's emulation the client. Therefore filtering the extension list instead of returning WebGL's list verbatim will be GL spec. compliant and will fix the problem without a breaking change. |
Opened #20948 to flip the flag into opt-out from opt-in. |
It's not that it hurts code size for applications that don't use GetProcAddress - it's that it's a known "footgun" because GetProcAddress has a disproportionately huge code size, and when porting native applications it's easy to link it accidentally when you don't really need to. |
Summary: Broken as described here emscripten-core/emscripten#20802 (comment) Pull Request resolved: #80 Test Plan: Imported from GitHub, without a `Test Plan:` line. This happened after upgrading KTX-Software to `v4.3.1` in D54395401. Reviewed By: syeh1 Differential Revision: D54519137 Pulled By: corporateshark fbshipit-source-id: b40644c185874a18bfe61990b3d298901619a00c
Some renderers that are ports from native codebases have a problem that they use the
*glGetProcAddress()
functions to dynamically discover the function entry points for different GL extensions.In native GL world, there is a tacit guarantee that if an extension
GL_FOO
includes an entrypointglFoo()
, then if an implementation advertise support forGL_FOO
extension, then callingglGetProcAddress("glFoo")
can be expected to succeed.More robust user code would check not only the presence of the extension, but also that the function
glGetProcAddress("glFoo")
does not return null, but such robustness is not necessarily built in to user applications since in the native GL world, this expectation doesn't generally fail.Since some 6 years apo, our best practices document has advocated users against using
*glGetProcAddress()
functions when targeting the web: https://emscripten.org/docs/optimizing/Optimizing-WebGL.html#optimizing-load-times-and-other-best-practices , due to the massive code size bloat that it causes (but also due to the performance problems that using it brings). Users are advised to not use that function.Nevertheless, the function exists to ease porting existing codebases and to maintain parity between platforms.
One additional identified drawback is that this
*glGetProcAddress()
scheme enables GL code that is compiled to the web the possibility to activate "dormant" features from native GL side that were not enabled at the time the site is built; but later when a browser exposes a new WebGL extension, it can suddenly cause the site to try to activate those GL features.This by itself wouldn't be a problem, except that WebAssembly & WebGL do not support a facility to enable a true enumerating
*glGetProcAddress()
implementation, but we must emulate that via a big if-else string search table. And so this statically implemented if-else chain cannot automatically manage new extension entry points as they come online when browsers evolve.To fix above issues, this PR moves the
*glGetProcAddress()
functions behind a dedicated linker flag-sGL_ENABLE_GET_PROC_ADDRESS=1
that users must now pass if they want to use a*glGetProcAddress()
function. This enables our implementation to explicitly restrict to only advertising WebGL extensions that exist at the time that the site is built, so that the limited implementation of*glGetProcAddress()
won't be able to break the promise that the existence ofGL_FOO
extension should imply that callingglGetProcAddress("glFoo")
would succeed.Fixes #20798