Skip to content
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

Improve GLENUM names/macro/printing #71

Open
wants to merge 12 commits into
base: master
Choose a base branch
from

Conversation

heyx3
Copy link
Contributor

@heyx3 heyx3 commented Oct 18, 2021

  1. I cleaned up the @GenEnums macro to simplify the declaration of enums. Originally each constant was declared like const GL_ABC = convert(GLenum, 123). However, the only really important information to declare is 1) the enum's name, 2) the enum's type, and 3) the enum's value. So I changed the syntax to be the simpler GL_ABC::GLenum = 123, which the macro then expands out into the original statement. And the type is assumed to be GLenum by default, so most of the declarations are even simpler: GL_ABC = 123
  2. I added the ability to overload GLENUM to provide hard-coded names for the problematic entries like GLENUM(1). You can see this done at the bottom of the file. Now you can see that the "name" of GLENUM(1) is GL_TRUE!
  3. I overloaded Base.print() and Base.show() for the GLENUM type so that it's a lot easier to read at a glance. When printing, it looks like "GLENUM(GL_TRUE, 1)". When using show(), it looks like "GL_TRUE<1>".
  4. I added some tests for GLENUM

@heyx3
Copy link
Contributor Author

heyx3 commented Oct 18, 2021

One other small detail is that I specified the max OpenGL version of 4.6 in the Readme.

@heyx3
Copy link
Contributor Author

heyx3 commented Oct 18, 2021

Oh, and the macro also handles exporting now

@SimonDanisch
Copy link
Member

Nice!
Btw, now that you seem to clean up much more of this, I think it would make more sense to use Clang to rewrap the headers...
By now, Clang supports custom rewriting passes, which we can use to get the function pointers in the ccall...
Have a look at:
https://github.com/JuliaGraphics/RadeonProRender.jl/blob/master/build/generate-master.jl#L25

@heyx3
Copy link
Contributor Author

heyx3 commented Oct 21, 2021

Interesting, but I don't really know anything about Julia's build system or LLVM in general. That may be a bit much for me to take on :P

@SimonDanisch
Copy link
Member

Interesting, but I don't really know anything about Julia's build system or LLVM in general

Both aren't really needed ;) It's really just about pointing that script to the OpenGL header files and then run it!
But I can understand, that this could still be a whole new rabbit hole one wouldn't want to get in ;)

@heyx3
Copy link
Contributor Author

heyx3 commented Jan 19, 2022

Hi, I just noticed that GLsizei was defined incorrectly as a 64-bit value, which was leading to very strange and infrequent crashes when calling OpenGL functions that use it. I just thew a fix into this PR.

Using Clang.jl seems interesting and I am trying to understand that area more, but in the meantime, would it be OK to merge this in to fix these issues in the short- and medium-term? I also have a subsequent branch adding some of of the ARB extensions, if you're interested.

@@ -19,7 +19,7 @@ const GLhalf = Cushort
const GLenum = Cuint
const GLboolean = Cuchar
const GLclampf = Cfloat
const GLsizei = Cssize_t
const GLsizei = Cint
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those have different sizes.. Was this really incorrect before?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, sorry...Didn't see your comment... Wow! That's interesting :-O

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SimonDanisch the errors seemed to be that any time i passed in a pointer to GLsizei, for OpenGL to tell me the length of something (e.x. a uniform name string, or an error log string), it would sometimes return a ridiculously large size, on the order of hundreds of billions.

It was extremely infrequent when getting uniform names, but happened every time when trying to read the error log.

end
struct GLENUM{Sym, T}
number::T
name::Symbol
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I like this to be so heavyweight, with a symbol field and the Sym type parameter...
We already have massive compilation latency problems and putting the name into the type parameter means, that all code using GLENUM will try to specialize on Sym.
Not sure how big the problem is considering that there isn't much to specialize on.. But it still seems excessive!
Maybe it would be easier to group the enums, so that in one group they have their own type, and therefore don't overlap? I don't really see any end user package using the overload infrastructure - this is rather something that should be set in stone by ModernGL itself, or how do you plan to use this?
But it does sounds confusing to me, that when you load some package your enums suddenly get renamed...
Also, does the symbol field actually work in all cases with the C interop? I'm not sure if there are cases where we need to pass an array of enums, or what other problems could arise.
Maybe we can use the implementation from https://github.com/JuliaInterop/CEnum.jl instead, and then put a bit of work into finding some groups, that we need to separate to not get name clashes?

Copy link
Contributor Author

@heyx3 heyx3 Jan 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was imagining that users might want to overload specific values to return whatever name is most relevant to the debugging work they're doing, but you're probably right that it's not a likely scenario in practice.

I'm not sure how much this increases the compilation times, as doesn't the compilation only happen after you first dispatch to it? I thought that in practice, this function is merely something you call once or twice in the REPL while debugging, or maybe 3-10 times when intercepting OpenGL errors. Did I miss a use-case?

I would guess that the project's huge compilation time comes from pre-emptively filling in the GLENUM lookup dictionary, because the GLENUM struct also has a type parameter for the Symbol, which means it's compiling hundreds of specializations upon loading the package. Speaking of which, is there a reason behind that, or would you be interested in a commit which removes it? It seems redundant anyway because it already keeps the Symbol as a field.

I'd be surprised if there are any cirumstances in which you'd send GLENUM to C. Wouldn't external libraries want plain GLenum values, rather than this package's special wrapper?

Copy link
Contributor Author

@heyx3 heyx3 Jan 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SimonDanisch Sorry, I think I misunderstood your original comment. I assumed you were talking about my new implementation of the GLENUM constructor, dispatching on Val(UInt32(i)). But it sounds like you were talking about the first type parameter of GLENUM{Sym, T}? That was already there before I made these changes, and as I said above I agree we could get rid of it.

I'm still a bit confused on the circumstances where you'd want to pass a GLENUM into C, as opposed to a plain GLenum.

Also, I just checked over the code, and I was mistaken about compilation times. The lookup dictionary for enums doesn't contain a bunch of GLENUM instances, merely the symbols, so there's no excessive compilation there. The main cost of compilation is most likely the sheer overhead of setting up so many functions and constants, which is probably hard to avoid.

On the note of my new GLENUM() constructor, I just discovered that Julia has a @nospecialize macro, which should guarantee that the compiler only makes 3 overloads -- one for Val{1}, another for Val{0}, and then the catchall for any other Val.

TL;DR I'll cut out the Sym type parameter from GLENUM, and also throw @nospecialize in there.

Copy link
Contributor Author

@heyx3 heyx3 Jan 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After updating the code, it takes about 5 seconds to precompile ModernGL on my machine, and then starting up a window (which involves a number of GL calls, GLFW calls, and also my own code) altogether takes ~3 seconds.

Copy link
Contributor Author

@heyx3 heyx3 Jan 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh and as for grouping the GL enums so you can see all the names for each value, that would be nice, but I think it would need extra engineering work. A naive implementation would lead to creating thousands of tiny dictionaries, just for a little debugging helper! I think you'd want some kind of sparse matrix. Replacing the current dictionary with something like that would probably merit its own branch.

For the record, this branch doesn't change how the dictionary lookup works; I just cleaned it up a bit by pulling its declaration out of the macro, and changed GLENUM() from having one method to having three.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I forgot to answer. I did actually missunderstand your PR. I thought it was replacing the constants with const GL_CONSTANT = GLENUM(...), which would put a lot more pressure on the implementation of GLENUM...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that makes sense now :D

Well we've got the important bug-fixes merged in, and there's already an experimental branch using Clang, so it's up to you if you still want the other stuff from this PR. I'll try to fix the merge conflicts tonight (this branch should steamroll over the other one).

Either way, do you want some ARB extensions from another branch of mine? I only added a few that were relevant to me, mainly ARB_bindless_textures.

@SimonDanisch
Copy link
Member

strange and infrequent crashes

What was the error? I'm wondering if this will fix a bug in Makie!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants