-
Notifications
You must be signed in to change notification settings - Fork 40
Notes for Contributors
I've been programming on and off for over 30 years, but I am relatively new to Java and to rendering. I tend to start with experiments and then refactor heavily. I also tend to adapt my style and approach to the situation or even to my mood that day. I am doing this for fun and motivation matters.
It's also important to remember that Canvas is a work in progress and changing rapidly. I tend to leave more "noise" in code that is still experimental or likely to be replaced.
The flip side of #1 is that I'm relatively flexible. If something bothers you and there is some practical benefit to changing it, there's a good chance I'll accept your PR and appreciate you for making Canvas better. For code you are contributing, I care mostly that it is clear, performant and functional. However, see Contribution Guidelines, below.
I will frequently stop and re-evaluate the problem space and alternative approaches, including some that may seem ridiculous or impractical at the outset. I appreciate contrary and radical points of view when they lead to better idea and outcomes. For me, this is never personal. I keep it respectful and avoid making personal attacks. I expect that you will also. If you find it difficult to maintain that sort of detachment, then this may not be the project for you.
Debate is useful; shipping code is satisfying. I learn by doing, and a working, viable implementation beats a hypothetical solution. (Until that solution can be implemented!)
Point is: I tend to switch between Hmmm, what is best? and DO IT NOW! frequently and without notice. This isn't something I can change.
I don't have many rules, but here they are.
-
By contributing, you grant perpetual and non-exclusive rights under the Apache 2.0 license agreement.
-
All contributions must be your own or covered under the next rule.
-
Many rendering problems have readily adaptable code available via a compatible license. If such code is not available in a library appropriate for inclusion, then excerpts or adaptations may be contributed with appropriate attribution and disclosures, per the source license.
-
Smaller and more frequent PRs are generally preferable to big PRs that take a long time because the code base can change rapidly. "Dark launch" WIP commits will be considered for this reason - just don't break anything.
-
If you know you'll be working on a big feature for an extended time, try to create isolation from the rest of the codebase via interfaces, possibly with some reorganization. Preliminary refactoring to prepare for such efforts is absolutely OK.
-
Use
assert
where units tests aren't viable (they usually aren't) and run your JVM in dev with the -ea parameter. This is mainly useful for catching race conditions and as a safety net when reasoning about complex state that is concurrently maintained.
Canvas and the default shaders that come with it will make every reasonable effort to be compatible with machines that run Minecraft, on all operating systems supported by Mojang.
This means Canvas has to be able to run under OpenGL 2.1 with GLSL version 120. Specs for those versions are available here:
Unfortunately, because Mac OS is a supported operating system and does not support core elements in the compatibility profile, Canvas must be able to run without newer OpenGL feature available on other platforms, unless an extension is reliably available.
For shaders this means:
- We declare version #120 in the header. The default header include normally does this.
- At time of writing,
GL_EXT_gpu_shader4
is the only GLSL extension that seems to be reliably available. It also is included in the default header. - GLSL functions that are available in more recent versions and frequently needed can (and generally should) be exposed by a library method that uses conditional compilation to act as an alias when the target function is available and a GLSL implementation when not.
- These shim functions generally can and should be placed in the FREX namespace instead of Canvas.
- If circumstances make it unreliable or problematic to use the target GLSL function name, an
frx_...
function is appropriate.
Performance is always a constraint in rendering code. The following practices are recommended:
Modern processors are so fast that memory bandwidth is almost the only thing that matters. Prevent cache misses and maximize register usage at almost any cost.
LOR is a big topic but in simplest terms this means using primitive types and arrays of primitive types with minimal indirection. FastUtil collections are usually a decent choice.
Because the main client thread owns the GL context, it is (mostly) the only thread that can do anything render related. For our purposes, it is the scarce resource.
Ideally we want the client thread to be preparing for draw calls and waiting for draw calls to complete, and nothing else.
Many optimizations vary in effectiveness with different hardware/software configurations. Measure performance via instrumentation and/or VisualVM and also provide a way to turn it off.
Also highly variable and situational. For an introduction to the concerns, see this stackexchange thread
Use minimal scoping (private when possible), final
members, and concrete types. For API implementations, keep interface type hierarchies clean and avoid multiple implementations. Obviously static
methods can help here but work best when the parameters are primitive types.
Another big topic and highly situational. Atomics can help but come with their own costs and limitations. Maintaining per-thread mutable data with immutable shared data is very good when workable.