[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Public WebGL] Context loss events and multi canvas rendering



Here's the situation I'm suggesting

--main thread--

addEventListener('mousemove', askWorkerForNewDrawingBuffer);
worker.addEventListerner('message', transferDrawingBufferToCanvas);

If the context/content is lost there's no signal to the main thread here. The main thread has no idea that it needs to ask the worker for another DrawingBuffer and that its canvas is currently blank.

It doesn't seem to me that the main thread should have to count on the worker to detect this stuff. The main thread should be able to be in control. 

This seems like reasonable pseudo code to me

   initWorker();
   requestFrameFromWorkerAtCurrentState();
   >
    {
     initWorker();
     requestFrameFromWorkerAtCurrentState();
   };
   >

The worker doesn't have to deal with context/content lost.

This also seems like reasonable pseudo code to me

    var someDrawingBuffer;
    initWorker();

    // at ~60fps, render some scene using 'someDrawingBuffer' as
    // part of the scene
    function render() {
       if (someDrawingBuffer) {
         ctx2d.drawImage(someDrawingBuffer, 0, 0);
       }
       ctx2d.fillRect(Math.sin(time) * 100, 0, 100, 100);
       requestAnimationFrame(render);
    }
    render();

    // when a key is pressed request the worker generate a new DrawingBuffer
    >
    worker.addEventListener('message', function(event) {
       someDrawingBuffer = event.data;
    }

Again, in this case if the context/content is lost the animation will be drawing an empty DrawingBuffer.
The app doesn't care about the content of the canvas since it's redrawing that every frame. It only cares about the contents of someDrawingBuffer
















On Mon, Mar 4, 2013 at 7:28 PM, Kenneth Russell <kbr@google.com> wrote:
In this scenario, any event in the main thread would have to be
dispatched to the canvas, because the DrawingBuffer will have been
neutered during transferDrawingBufferToCanvas.

If you're going to continue to render from that context to new
DrawingBuffer instances and continue to hand them off to the canvas,
then I don't see an advantage to having a content lost event against
the canvas. The app will only be able to start rendering again after
the context restored event is sent to the WebGLRenderingContext, and
at that point, the worker could just initiate a render cycle.

If the app wants to send DrawingBuffers from multiple sources (and
rendered to by multiple kinds of contexts) to the canvas, maybe
there's a good reason to have only the "content lost" event on the
canvas. The app would respond by immediately creating a new
DrawingBuffer against either a context which wasn't lost, or against a
brand new one, posting it to the main thread, and transferring it to
the canvas.

-Ken



On Mon, Mar 4, 2013 at 4:11 PM, Gregg Tavares <gman@google.com> wrote:
> But a canvas will be assuming the WebGL workers thing happens as specced.
> Here's the example from the spec of rendering from a work to a canvas in the
> main thread
>
>     // render.js: -- worker --
>     var gl = new WebGLRenderingContext();
>     var dsBuffer = new DepthStencilBuffer(gl, …);
>     gl.setDepthStencilBuffer(dsBuffer);
>
>     var render = function(self) {
>        // make a new DrawingBuffer
>        var db = new DrawingBuffer(gl, ...);
>
>        // Render to drawing buffer.
>        gl.setDrawingBuffer(db);
>        gl.drawXXX(...);
>
>        // Pass the drawing buffer to the main thread for compositing
>        self.postMessage(db, [db]);
>
>        // request the next frame.
>        self.requestAnimationFrame(render);
>     }
>     render();
>
>     // Main thread:
>     var canvas = document.getElementById(“someCanvas”);
>     var worker = new Worker(“render.js”);
>     worker.addEventListener(‘message’, function(db) {
>        canvas.transferDrawingBufferToCanvas(db);
>     }, false);
>
> In the main thread there is no context. There are only DrawingBuffers and a
> Canvas. There's also no reference to the DrawingBuffer after it has been
> given to the canvas.
>
> If you're making a Maya clone which only draws based on user input then
> you'd probably like to know when either the canvas has lost its content lost
> and/or the DrawingBuffer in the main thread has lost its content so you can
> ask the worker to generate new content for you.
>
> In other words, the content objects "Canvas" and "DrawingBuffer" seem to
> need events separate from the contexts "Canvas2DRenderingContext" and
> "WebGLRenderingContext"
>
>
>
> On Mon, Mar 4, 2013 at 3:06 PM, Kenneth Russell <kbr@google.com> wrote:
>>
>> From a practical standpoint I don't think the drawing buffer will ever
>> be lost without its associated rendering context (either 2D or WebGL)
>> being lost. Gregg, what do you think?
>>
>>
>> On Mon, Mar 4, 2013 at 12:42 PM, Florian Bösch <pyalot@gmail.com> wrote:
>> > I think it only makes sense to have another event (than context lost on
>> > the
>> > context) if you can lose the drawing buffer alone (without losing the
>> > context). If you can only lose the drawing buffer as a result of a
>> > context
>> > loss, then I don't think a separate event makes sense.
>> >
>> >
>> > On Mon, Mar 4, 2013 at 9:39 PM, Kenneth Russell <kbr@google.com> wrote:
>> >>
>> >> These are good points. Conceptually the drawing buffer's contents
>> >> could be lost independently from the WebGL context, but in practice, a
>> >> DrawingBuffer's backing store (color buffer, etc.) will be allocated
>> >> in the same OpenGL share group as the WebGL context. Therefore if the
>> >> WebGL context is lost via ARB_robustness or EXT_robustness, the
>> >> drawing buffer's contents will always be lost.
>> >>
>> >> Do you think it is worth specifying another "content lost" event,
>> >> having it apply to DrawingBuffers, and trying to have it apply to
>> >> canvases as well? Or should the context lost event against the
>> >> WebGLRenderingContext be enough of a hint for application authors that
>> >> they'll need to push another DrawingBuffer into the output canvas? For
>> >> generality I agree that a "content lost" event should be specified,
>> >> but I think the same result can be reached just by holding on to the
>> >> contexts and watching for context lost.
>> >>
>> >> -Ken
>> >>
>> >>
>> >>
>> >> On Sat, Mar 2, 2013 at 12:08 AM, Florian Bösch <pyalot@gmail.com>
>> >> wrote:
>> >> > So the canonical "context lost" is not what you mean by losing a
>> >> > drawing
>> >> > buffer (which is the system reclaiming it for some reason).
>> >> >
>> >> > Context lost has a meaning for a context because it means all other
>> >> > resources by that context have become null and void. Losing your
>> >> > drawingbuffer does not mean that your contexts resources are now null
>> >> > and
>> >> > void, hence the same name should probably be avoided for whatever
>> >> > event
>> >> > you
>> >> > want to issue. More to the point:
>> >> >
>> >> > - If you still have the context used to create the drawing you can
>> >> > redraw on
>> >> > drawingbuffer restored
>> >> > - If you don't have the context anymore, there's nothing you can do
>> >> > anyways
>> >> > if you drawingbuffer lost
>> >> > - drawingbuffer lost would not have an impact on whatever context is
>> >> > attached to it in terms of the validity of that context
>> >> > - context lost would not have an impact on whatever drawing buffer
>> >> > its
>> >> > connected to in terms of the drawing buffer being valid
>> >> >
>> >> >
>> >> > On Sat, Mar 2, 2013 at 8:57 AM, Gregg Tavares <gman@google.com>
>> >> > wrote:
>> >> >>
>> >> >>
>> >> >>
>> >> >>
>> >> >> On Fri, Mar 1, 2013 at 11:49 PM, Florian Bösch <pyalot@gmail.com>
>> >> >> wrote:
>> >> >>>
>> >> >>> Is losing a drawingbuffer the same as losing a context?
>> >> >>
>> >> >>
>> >> >> It depends on what you mean.
>> >> >>
>> >> >> My point is this. Here's some code
>> >> >>
>> >> >> function makeDrawingBufferWithImageInIt() {
>> >> >>    var gl = new WebGLRenderingContext();
>> >> >>    var db = new DrawingBuffer(gl, ....);
>> >> >>    gl.setDrawingBuffer(db);
>> >> >>    gl.....
>> >> >>    gl.drawArrays();
>> >> >>    return db;
>> >> >> }
>> >> >>
>> >> >> var db = makeDrawingBuffferWithImageInIt();
>> >> >>
>> >> >> I now have this DrawingBuffer with content in it. I have no
>> >> >> reference
>> >> >> to
>> >> >> the context that created it anymore. The system will reclaim it
>> >> >> supposedly.
>> >> >> If the context is lost I'll have no idea that my DrawingBuffer's
>> >> >> content was
>> >> >> destroyed.
>> >> >>
>> >> >> Maybe that's okay? Maybe if you want to know that it was destroyed
>> >> >> you
>> >> >> need to watch for 'contextlost' on the context that created it?
>> >> >> Maybe
>> >> >> DrawingBuffer needs and event for contextlost? Maybe we need a new
>> >> >> design?
>> >> >> Maybe DrawingBuffers of a 'contentlost' event instead of a
>> >> >> 'contextlost'
>> >> >> event?
>> >> >>
>> >> >>
>> >> >>
>> >> >>>
>> >> >>>
>> >> >>>
>> >> >>> On Sat, Mar 2, 2013 at 8:32 AM, Gregg Tavares <gman@google.com>
>> >> >>> wrote:
>> >> >>>>
>> >> >>>>
>> >> >>>>
>> >> >>>>
>> >> >>>> On Fri, Mar 1, 2013 at 7:27 PM, Kenneth Russell <kbr@google.com>
>> >> >>>> wrote:
>> >> >>>>>
>> >> >>>>> Listening for context lost events on the context itself seems
>> >> >>>>> like
>> >> >>>>> the
>> >> >>>>> best and most correct solution. If that's supported, would
>> >> >>>>> DrawingBuffer need to support them? I don't think so.
>> >> >>>>
>> >> >>>>
>> >> >>>> The issue with DrawingBuffers is they can get lost too. Let's say
>> >> >>>> you
>> >> >>>> render to a DrawingBuffer once and keep it around. You pass that
>> >> >>>> DrawingBuffer to another thread, maybe you're using it to draw
>> >> >>>> into a
>> >> >>>> canvas
>> >> >>>> with drawImage. You get lost context. That lost context will
>> >> >>>> arrive
>> >> >>>> in the
>> >> >>>> other thread. A thread you might have deleted at this point.
>> >> >>>>
>> >> >>>> Maybe if you want to be able to recover from that situation you
>> >> >>>> might
>> >> >>>> be
>> >> >>>> required to keep a reference to the context so you can know that
>> >> >>>> the
>> >> >>>> context
>> >> >>>> was lost? But it seems like you'd like to be able to know from the
>> >> >>>> DrawingBuffer? Or not. It's complicated either way :-(
>> >> >>>>
>> >> >>>>
>> >> >>>>>
>> >> >>>>>
>> >> >>>>> Web workers seem to be able to actually listen for events (see
>> >> >>>>> the
>> >> >>>>> onconnect message in
>> >> >>>>>
>> >> >>>>>
>> >> >>>>>
>> >> >>>>> http://www.whatwg.org/specs/web-apps/current-work/multipage/workers.html#handler-sharedworkerglobalscope-onconnect
>> >> >>>>> ), so hopefully adding an event handling mechanism to
>> >> >>>>> WebGLRenderingContext would not cause any issues with using WebGL
>> >> >>>>> in
>> >> >>>>> workers.
>> >> >>>>>
>> >> >>>>> -Ken
>> >> >>>>>
>> >> >>>>>
>> >> >>>>> On Fri, Feb 22, 2013 at 2:31 PM, Gregg Tavares <gman@google.com>
>> >> >>>>> wrote:
>> >> >>>>> >
>> >> >>>>> >
>> >> >>>>> >
>> >> >>>>> > On Fri, Feb 22, 2013 at 5:00 AM, Florian Bösch
>> >> >>>>> > <pyalot@gmail.com>
>> >> >>>>> > wrote:
>> >> >>>>> >>
>> >> >>>>> >> I just noticed that the context loss events are registered on
>> >> >>>>> >> the
>> >> >>>>> >> canvas
>> >> >>>>> >> rather than the context.
>> >> >>>>> >>
>> >> >>>>> >>
>> >> >>>>> >> The newly proposed functionality of canvas independent
>> >> >>>>> >> contexts
>> >> >>>>> >> would make
>> >> >>>>> >> it awkward to handle context losses (you will have to register
>> >> >>>>> >> the
>> >> >>>>> >> event on
>> >> >>>>> >> every conceivable canvas and check that you don't double
>> >> >>>>> >> handle
>> >> >>>>> >> it).
>> >> >>>>> >>
>> >> >>>>> >> Would it be appropriate to extend the WebGLContext object with
>> >> >>>>> >> an
>> >> >>>>> >> event
>> >> >>>>> >> handling mechanism so it can be handled per context?
>> >> >>>>> >
>> >> >>>>> >
>> >> >>>>> > Yes, good point. They might need to be on DrawingBuffer too if
>> >> >>>>> > we
>> >> >>>>> > go
>> >> >>>>> > that
>> >> >>>>> > route.
>> >> >>>>> >
>> >> >>>>> >
>> >> >>>>
>> >> >>>>
>> >> >>>
>> >> >>
>> >> >
>> >
>> >
>
>