Noticed that SwapBuffer functionality is not there in WebGL, If that is the case how do we change state across draw calls and draw multiple objects in WebGL, at what point of time is swapBuffer called internally by WebGL?
First off there is no SwapBuffers in OpenGL. SwapBuffers is a platform specific thing that is not part of OpenGL.
In any case though the equivalent of SwapBuffers is implicit in WebGL. If you call any WebGL functions that affect the drawingbuffer (eg, drawArray, drawElements, clear, ...) then the next time the browser composites the page it will effectively "swapbuffers".
note that whether it actually "swaps" or "copies" is up to the browser. For example if antialiasing is enabled (the default) then internally the browser will effectively do a "copy" or rather a "blit" that converts the internal multisample buffer to something that can actually be displayed.
Also note that because the swap is implicit WebGL will clear the drawingBuffer before the next render command. This is to make the behavior consistent regardless of whether the browser decides to swap or copy internally.
You can force a copy instead of swap (and avoid the clearing) by passing {preserveDrawingBuffer: true} to getContext as the 2nd parameter but of course at the expensive of disallowing a swap.
Also it's important to be aware that the swap itself and when it happens is semi-undefined. In other words calling gl.drawXXXor gl.clear will tell the browser to swap/copy at the next composite but between that time and the time the browser actually composites other events could get processed. The swap won't happen until your current event exits, for example a requestAnimationFrame event, but, between the time your event exits and the time the browser composites more events could happen (like say mousemove).
The point of all that is that if don't use {preserveDrawingBuffer: true} you should always do all of your drawing during one event, usually requestAnimationFrame, otherwise you might get inconsistent results.
AFAIK, swap buffers call usually doesn't change any visible GL state. There're plenty of GL calls to change that state between draw calls though. As for buffer swapping, browser does that for you sometime after a callback with rendering code returns (and yes, there's no direct control over when this will actually happen).
Related
I have an interesting query with regard to #MainActor and strict concurrency checking (-Xfrontend -warn-concurrency -Xfrontend -enable-actor-data-race-checks)
I have functions (Eg, Analytics) that at the lowest level require access to the device screen scale UIScreen.main.scale which is isolated to MainActor. However I would prefer not to have to declare the entire stack of functions above the one that accesses scale as requiring MainActor.
Is there a way to do this, or do I have no other options?
How would be the best way to ensure my code only ever calls UIScreen once and keeps the result available for next time without manually defining a var and checking if its nil? Ie is there a kind of computed property that will do this?
Edit: Is there an equivalent of this using MainActor (MainActor.run doesn't do the same thing; it seems to block synchronously):
DispatchQueue.main.async {
Thanks,
Chris
Non-UI code should not rely directly on UIScreen. The scale (for example), should be passed as a parameter, or to actors in their init. If the scale changes (which it can, when screens are added or removed), then the new value should be sent to the actor. Or the actor can observe something that publishes the scale when it changes.
The key point is accessing UIScreen from a random thread is not valid for a reason. The scale can in fact change at any time. Reading it from an actor is and should be an async call.
It sounds like you have some kind of Analytics actor. The simplest implementation of this would be to just pass the scale when you create it.
I have a 2D game I've been working on in webGL, and, with few exceptions, I use one default program for drawing sprites onscreen. I call gl.useProgram once, on initialization, and if I ever need to use a different program, I reset the program to the default when I'm done.
However, I see examples where others call gl.useProgram every time they draw, and therefore at least once on every frame, or possibly as many times as there are quads to be rendered, in a worst-case scenario.
For the sake of peace of mind, I'd like to use gl.useProgram for every draw call, so I always know exactly which program is being used, but only if it's still relatively efficient to do so.
My question is, if you use gl.useProgram to set the program to the program already in use, is there a performance impact, or does webGL/javascript essentially "know" that the program remains unchanged?
A modern GPU driver applies state changes before issuing a draw command, effectively filtering any in-between changes that have no side effects. So setting the same program several times will unlikely have a serious impact. But setting the same state needlessly results in redundant state change warning in many graphic debuggers. It is considered an undesirable behavior. After you set a program with gl.UseProgram it will remain active in the context until replaced with another program or the context is lost. Even deleting the program with gl.DeleteProgram doesn't make the currently bound program invalid.
if you use gl.useProgram to set the program to the program already in use, is there a performance impact
Doing more work than less always has some impact. The question I think you're really asking is it too much impact. Only you can tell. I suspect it's tiny but how about just trying it and seeing if you notice a difference?
does webGL/javascript essentially "know" that the program remains unchanged?
There's no way to guarantee this is checked. You could look into the source code of every browser and check back every few months to see it didn't change.
But, if you're concerned just check yourself
let globalLastProgram = null
function checkedUseProgram(program) {
if (globalLastProgram !== program) {
globalLastProgram = program;
gl.useProgram(program);
}
}
Now call checkedUseProgram instead of gl.useProgram.
Or if you want wrap useProgram itself.
WebGLRenderingContext.prototype.useProgram = function(origFn) {
return function(program) {
if (this.lastProgram !== program) {
this.lastProgram = program;
origFn.call(this, program);
}
};
}(WebGLRenderingContext.prototype.useProgram);
If you don't like lastProgram being on the context you can make a wrapping function
function addWrapper(gl) {
gl.useProgram = function(origFn) {
let lastProgram;
return function(program) {
if (lastProgram !== program) {
lastProgram = program;
origFn.call(this, program);
}
};
}(gl.useProgram);
}
addWrapper(gl);
Of course all of those will have a tiny impact as well though I suspect it's hard to measure
Please refer to the background section below if the following does not make much sense, I omitted most of the context as to make the problem as clear as possible.
I have two WebGLRenderingContexts with the following traits:
WebGLRenderingContext: InputGL (Allows read and write operations on its framebuffers.)
WebGLRenderingContext: OutputGL (Allows only write operations on its framebuffers.)
GOAL: Superimpose InputGL's renders onto OutputGL's renders periodically within 33ms (30fps) on mobile.
Both the InputGL's and OutputGL's framebuffers get drawn to from separate processes. Both are available (and with complete framebuffers) within one single window.requestAnimationFrame callback. As InputGL requires read operations, and OutputGL only supportes write operations, InputGL and OutputGL cannot be merged into one WebGLRenderingContext.
Therefore, I would like to copy the framebuffer content from InputGL to OutputGL in every window.requestAnimationFrame callback. This allows me to keep read/write supported on InputGL and only use write on OutputGL. Neither of them have (regular) canvasses attached so canvas overlay is out of the question. I have the following code:
// customOutputGLFramebuffer is the WebXR API's extended framebuffer which does not allow read operations
let fbo = InputGL.createFramebuffer();
InputGL.bindFramebuffer(InputGL.FRAMEBUFFER, fbo)
// TODO: Somehow get fbo data into OutputGL (I guess?)
OutputGl.bindFramebuffer(OutputGl.FRAMEBUFFER, customOutputGLFramebuffer);
// Drawing to OutputGL here works, and it gets drawn on top of the customOutputGLFramebuffer
I am not sure if this requires binding in some particular order, or some kind of texture manipulation of some sorts, any help with this would be greatly appreciated.
Background: I am experimenting with Unity WebGL in combination with the unreleased WebXR API. WebXR uses its own, modified WebGLRenderingContext which disallows reading from its buffers (as a privacy concern). However, Unity WebGL requires reading from its buffers. Having both operate on the same WebGLRenderingContext gives errors on Unity's read operations, which means they need to be kept separate. The idea is to periodically superimpose Unity's framebuffer data onto WebXR's framebuffers.
WebGL2 is also supported in case this is required.
You can not share resources across contexts period.
The best you can do is use one via some method as a source to the other via texImage2D
For example if the context is using a canvas then draw the framebuffer to the canvas and then
destContext.texImage2D(......., srcContext.canvas);
If it's a OffscreenRenderingContext use transferToImageBitmap and then pass the resulting bitmap to texImage2D
I need to pass a string from the UI to the plugin. From the eg-sample, it appears that an LV2 atom should be written to a atom port.
If I understand it correctly
First allocate a LV2_Atom_Forge. May that object be on the stack or does it have to survive after the UI event callback has returned?
Call lv2_atom_forge_set_buffer. How do I know the required size of the buffer? The example sets it to 1024 bytes for no reason. May the buffer be allocated on the stack or does it have to survive the UI after the UI event callback has returned?
The forge is just a utility for writing atoms. The buffer it writes to is provided by the code that uses it, so the lifetime of the forge itself is irrelevant. Allocating it on the stack is fine, though it may be more convenient to keep one around in your UI struct for use in various places.
You can estimate the space required by knowing the format of atoms as described in the documentation, or simply implementing everything with a massive buffer at first and checking the size field of the top-level atom in your output. Keep in mind that this will change if you have variable-sized elements like strings in there. The data passed to the UI callback(s) is const and only valid during the call, it must be copied by the receiver if it needs to be available later.
I have UI XCTestCases (XCUITests) that perform some gestures. Our performance tests need to be able to call startMeasuring and stopMeasuring depending on the state of the app.
We have methods in our app code that return a BOOL value depending on whether it has completed rendering everything and I need to read that value.
How can I call those methods in our app?
Short version: You shouldn't, but I guess you could try signal passing.
Longer version: A major (though perhaps philosophical) point of UI Tests is that they only evaluate that which is passed to the user, or at least to the user-visible View / Accessibility Hierarchies. Using signal passing or some other method to side-channel information is not supported and is against the aesthetic of the test framework.
Instead, you could evaluate whether or not everything has finished rendering by waiting for a .Hittable predicate on the particular UI elements; or if you have elements that only become interactable once the page has finished loading (a common pattern) you could wait for those to change state.
There are a number of different ways to go about this, but the "right" answer is to find some way that's user-visible that you can evaluate.
... alternatively, have a non-visible UI element in the View Hierarchy that changes state based on the Boolean in question, if you want something that just works and don't care about philosophy.