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

[enhancement] Isolate ProgramData from Program for allow reuse GL Program instance #139

Closed
wants to merge 8 commits into from

Conversation

eXponenta
Copy link
Contributor

@eXponenta eXponenta commented May 20, 2022

Why need this?

Sometimes needs to use multiple instance for same shader code, but with different uniforms (textures, color, any other data) which can't passed by attributes;

This PR split Program and ProgramData, now ProgramData store only info that needed for program usage.

Program now is like Material - store instance-specific values like uniforms or state.
You can spawn a lot of Programs from same shader code that with different uniform and state combination (see updated example).

Other benefits - we can easy change a ProgramData in program without update program reference in each mesh instance.
When this can be used? For example, when need use different shaders for each pass, like ShadowMap pass. You can change programData field to specific ProgramData instance for specific Program and shader will be replaced for each references automatically, but uniform and state wont changed.

@RAX7
Copy link
Contributor

RAX7 commented Jun 1, 2022

I agree that we need a way to reuse compiled shaders. But it's wrong way to cache WebGLProgram with only take to account source code text because they are dependent on rendering context (WebGLRenderingContext). WebGLProgram compiled with its WebGLRenderingContext will not works with another context.
Try this jsfiddle demo to see that issue.

@eXponenta
Copy link
Contributor Author

eXponenta commented Jun 1, 2022

@RAX7 Ogl not support multiple contexts.
It hold native webgl objects in class instances. You anyway can't use different contexts with shared objects.

It already hold VAO, texture, framebuffers.

If contexts will changed (after loose) - nothing will working.

Yep, problem that cache stored in program by sources only - easy can be moved to renderer instance or by GL reference (How in your PR) (will move to, valid notice)

By normal all native pointers should be stored in renderers instances by uuid instead of regular classes.

This has some benefits:

  1. Context will change - all natove pointers will re-constructed.
  2. Different contexts with SAME abstractions (render same scene with different cameras to different contexts without "dancing" with viewports)
  3. More stable, because state controlled inside renderers fully.
  4. Not needed pass GL property each Texture/Geometry/Program

But this is breaking changes and huge codebase.

@gordonnl what you think?

@RAX7
Copy link
Contributor

RAX7 commented Jun 1, 2022

@eXponenta

Ogl not support multiple contexts.

No, it does. Because we should pass gl instance to most items constructors, like new Program(gl, ...). It`s mean what we can have multiple gl context on a page. Take a look on next example. Its breaks when I try to use your version of OGL.

@eXponenta
Copy link
Contributor Author

eXponenta commented Jun 1, 2022

@RAX7 My PR is bugged, it PR and should be fixed of course.

I meant about:

const scene = new Transform ();
scene.add(new Mesh(...))

const camera1 = new Camera()
const camera2 = new Camera()
const renderer1 = new Renderer (context1)
const renderer2 = new Renderer (contex2)

rendere.render(scene, camera1)
renderer2.render(scene, camera2)

When you can use SAME nodes in different contexts.

This can automatic fix #74

@RAX7
Copy link
Contributor

RAX7 commented Jun 1, 2022

@eXponenta

When you can use SAME nodes in different contexts.

Wich NODES do you mean? Transform and Camera can be reused because they dont use gl context under the hood. But Mesh can not, its use.

@eXponenta
Copy link
Contributor Author

eXponenta commented Jun 1, 2022

@RAX7 and all resources: Textures, Programs, RenderTargets, Geometries.

Should be like this:

// scene nodes should be context-free
const scene = new Transform();
const geometry = new Box();
const program = new Program({
  vertex,
  fragment
});
const cube = new Mesh({ geometry, program });

cube.rotation.y -= 12;
cube.rotation.x -= 12;

cube.position.set(0, 0, 0);
cube.setParent(scene);

const camera = new Camera({ fov: 35 });
camera.position.set(0, 0, 8);
camera.lookAt([0, 0, 0]);

// create renderers for each context
function create(selector, antialias = false) {
  const canvas = document.querySelector(selector);
  const renderer = new Renderer({ canvas, antialias });

  const width = window.innerWidth / 2;
  const height = window.innerHeight;
  renderer.setSize(width, height);
  camera.perspective({ aspect: width / height });
  return () => renderer.render({ scene, camera });
}

const r1 = create('#canvas-1');
const r2 = create('#canvas-2', true);

r1();
r2();

For ex: GLTF is huge, and load ant parse it for multiple instances - bad idea. Ideal use a single loader and share data between contexts.
Then if context will be loose all need reload again, including GLTF.

Thanks for notice.
Fixed:
https://jsfiddle.net/p34fzcw0/3/

@RAX7
Copy link
Contributor

RAX7 commented Jun 1, 2022

@eXponenta nice, now demo is works!

scene nodes should be context-free

To implement that idea you need create something like a PIXIJS does. When program is create shaders does not compiling. Its compiles only before render try to get program from cache. And all this changes are:

But this is breaking changes and huge codebase.

as you sed before

@eXponenta
Copy link
Contributor Author

@RAX7

Its compiles only before render try to get program from cache. And all this changes are:

I already can move compile from constructor to Program.use method and call it before each use, and pass GL from program to it.
But there are little bit problem - huge programs complied very slow, and other problem - you can't checks program validity before first use.
For example in ThreeJS a lot of huge application try to preload shaders in application loading state to reduce lags in runtime then.

@RAX7
Copy link
Contributor

RAX7 commented Jun 1, 2022

@eXponenta

But there are little bit problem

Yes, then you solve problem you get another one. And that's why I prefer to keep things simple as possible. I don't need render-context-free classes, I don't need a super smart system with cache everything. I wish just to have cheap and fast clone method in entities. And this should help OGL keeps to be Minimal WebGL Library and solve a lot of performance issues.

@eXponenta eXponenta deleted the branch oframe:master January 9, 2023 18:31
@eXponenta eXponenta closed this Jan 9, 2023
@eXponenta eXponenta deleted the master branch January 9, 2023 18:31
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.

2 participants