elm-community / webgl

Moved to elm-explorations/webgl
https://package.elm-lang.org/packages/elm-explorations/webgl/latest
BSD 3-Clause "New" or "Revised" License
131 stars 18 forks source link

Grouping WebGL settings #27

Closed w0rm closed 7 years ago

w0rm commented 7 years ago

This is WIP on grouping settings, so we can be clever about enabling/disabling gl features and explicit about the default values.

Before, each function call would modify the environment for the next renderable. With these changes, we won't need to call gl.enable/disable, as we were doing in the crate.elm example that now has cool reflection effect thanks to @Zinggi.

crate

Zinggi commented 7 years ago

This is looking very good!

However, I'm a bit worried about performance. Let's take the create example to illustrate:

[ renderBox
    [ depth depthOptions ]
    (...)
, renderFloor
    [ depth { depthOptions | mask = False }
    , stencil { stencilOptions | ref = 1, zpass = replace }
    ]
    (...)
, renderBox
    [ stencil { stencilOptions | func = equal, ref = 1, writeMask = 0 }
    , depth depthOptions
    ]
    (...)
]

This will produce the following gl* calls:

gl.enable(gl.DEPTH_TEST);
gl.depthFunc(WebGL.Constants.less);
gl.depthMask(True);
gl.depthRange(0, 1);
// draw box
gl.disable(gl.DEPTH_TEST);

gl.enable(gl.DEPTH_TEST);
gl.depthFunc(WebGL.Constants.less);
gl.depthMask(False);
gl.depthRange(0, 1);
gl.enable(gl.STENCIL_TEST);
gl.stencilFunc(WebGL.Constants.always, 1, 4294967295);
gl.stencilOp(WebGL.Constants.keep, WebGL.Constants.keep, WebGL.Constants.replace);
gl.stencilMask(4294967295);
// draw floor
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.STENCIL_TEST);

gl.enable(gl.DEPTH_TEST);
gl.depthFunc(WebGL.Constants.less);
gl.depthMask(True);
gl.depthRange(0, 1);
gl.enable(gl.STENCIL_TEST);
gl.stencilFunc(WebGL.Constants.equal, 1, 4294967295);
gl.stencilOp(WebGL.Constants.keep, WebGL.Constants.keep, WebGL.Constants.keep);
gl.stencilMask(0);
// draw box
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.STENCIL_TEST);

...
// next iteration would repeat the above

While ideally, it would only produce these calls:

gl.enable(gl.DEPTH_TEST);
gl.depthFunc(WebGL.Constants.less);
gl.depthMask(True);
gl.depthRange(0, 1);
// draw box

gl.depthMask(False);
gl.enable(gl.STENCIL_TEST);
gl.stencilFunc(WebGL.Constants.always, 1, 4294967295);
gl.stencilOp(WebGL.Constants.keep, WebGL.Constants.keep, WebGL.Constants.replace);
gl.stencilMask(4294967295);
// draw floor

gl.depthMask(True);
gl.stencilFunc(WebGL.Constants.equal, 1, 4294967295);
gl.stencilMask(0);
// draw box
gl.disable(gl.STENCIL_TEST);

...
// next iteration:

// draw box

gl.enable(gl.STENCIL_TEST);
gl.stencilFunc(WebGL.Constants.always, 1, 4294967295);
gl.stencilMask(4294967295);
// draw floor

gl.stencilFunc(WebGL.Constants.equal, 1, 4294967295);
gl.stencilMask(0);
// draw box
gl.disable(gl.STENCIL_TEST);

To accomplish that, we'd have to keep track of which settings are currently active and only do a call if something changes.

Whether this will be worth it would have to be benchmarked of course, but this link suggests that it's worth it. Except that this is for openGl and pretty old. But I suspect it would be similar with WebGL

w0rm commented 7 years ago

@Zinggi I think this is not important at the current stage. We can add this optimisation later if needed, and it will be a patch change.

Zinggi commented 7 years ago

That's true. I will experiment with it once 2.0 is out, and if it does make a significant difference, we can patch it.