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

Re: [Public WebGL] using the same context with multiple canvases






On Wed, Dec 19, 2012 at 4:36 PM, Gregg Tavares (社用) <gman@google.com> wrote:
Let me try to be clearer with a more concrete proposal.

Canvas and CanvasProxy is great. You pass a CanvasProxy to a worker. 
You now have some object with some loose connection to the canvas in the page.

This is what i think I would be a good and consistent api

CanvasProxy has the same API as Canvas (minus the HTMLElement parts)

that includes

   getContext
   toDataURL

and being able to pass one to CanvasRenderingContext::drawImage, WebGLRenderingContext::teximage2D etc...

For the simple case that works just like the current API. You pass a CanvasProxy to the worker and the call getContext on it (with optional creation parameters just like getContext today)

For multiple canvases with 1 context you use the Drawingbuffer method (pick name) both in and out of workers.

main page JS example

   var canvas1 = document.createElement("canvas1");
   var canvas2 = document.createElement("canvas2");

   var db1 = new Drawingbuffer({..params..};
   var db2 = new Drawingbuffer({..params..};

   canvas1.setDrawingbuffer(db1);
   canvas2.setDrawingbuffer(db2);

   var gl = new WebGLRenderingContext();
   gl.bindDrawingbuffer(db1);
   gl.drawXXX();
   g.bindDrawingbuffer(db2);
   gl.drawXXX();

worker example with Canvases from main page

   var proxy1 = .... // some CanvasProxy passed from the page
   var proxy2 = .... // some CanvasProxy passed from the page

   var db1 = new Drawingbuffer({..params..};
   var db2 = new Drawingbuffer({..params..};

   proxy1.setDrawingbuffer(db1);
   proxy2.setDrawingbuffer(db2);

   var gl = new WebGLRenderingContext();
   gl.bindDrawingbuffer(db1);
   gl.drawXXX();
   g.bindDrawingbuffer(db2);
   gl.drawXXX();

some worker with no canvaes

   var db1 = new Drawingbuffer({..params..};
   var db2 = new Drawingbuffer({..params..};

   var gl = new WebGLRenderingContext();
   gl.bindDrawingbuffer(db1);
   gl.drawXXX();
   g.bindDrawingbuffer(db2);
   gl.drawXXX();

Ideally these would all work with canvas2d as well. 
There are examples of libraries that can switch renderers
Three.js comes to mind. There are also examples of libraries
that emulate canvas 2d on WebGL to get extra benefits 
(like being able to apply special effects) webgl-2d.js. It just
seems like it would be really nice if they could treat all this
stuff the same regardless of 2d or WebGL context.


Doh, I hit send before i was finished. Examples with canvas2d

   var canvas1 = document.createElement("canvas1");
   var canvas2 = document.createElement("canvas2");

   var db1 = new Drawingbuffer({..params..};
   var db2 = new Drawingbuffer({..params..};

   canvas1.setDrawingbuffer(db1);
   canvas2.setDrawingbuffer(db2);

   var ctx = new CanvasRenderingContext();
   ctx.setDrawingbuffer(db1);
   ctx.fillRect(...);
   ctx.setDrawingbuffer(db2);
   ctx.fillRect(...);

worker example with Canvases from main page

   var proxy1 = .... // some CanvasProxy passed from the page
   var proxy2 = .... // some CanvasProxy passed from the page

   var db1 = new Drawingbuffer({..params..};
   var db2 = new Drawingbuffer({..params..};

   proxy1.setDrawingbuffer(db1);
   proxy2.setDrawingbuffer(db2);

   var ctx = new CanvasRenderingContext();
   ctx.setDrawingbuffer(db1);
   ctx.fillRect(...);
   ctx.setDrawingbuffer(db2);
   ctx.fillRect(...);

some worker with no canvases

   var db1 = new Drawingbuffer({..params..};
   var db2 = new Drawingbuffer({..params..};

   var ctx = new CanvasRenderingContext();
   ctx.setDrawingbuffer(db1);
   ctx.fillRect(...);
   ctx.setDrawingbuffer(db2);
   ctx.fillRect(...);

Why not have the consistency? This solution seems consistent
and also has the benefit of allowing creation parameters for
canvas 2d once we convince the powers that be that they're
needed :-)

as for commit(), it seems to me it should go on DrawingBuffer as 
that's the object that's deciding if something is swapping buffers 
on commit or copying buffers on commit. 

Having it on Drawingbuffer also means it can be used in workers
without a canvas. 

It also suggests it can be used outside workers
which some people have asked for to let them choose
when they are ready to present their work.  Example:

    // in main page.
    var canvas = document.createElement("canvas");
    var db = new Drawingbuffer({implicitCommit: false});
    canvas.setDrawingBuffer(db);
    var ctx = new CanvasRenderingContext();
    ctx.setDrawingBuffer(db);

    // Draw something that takes a while in steps
    // Don't present it until it's finished.
    var stepsToGo = 100;
    var processNextStep = function() {
      // draw more stuff
     ...
      --stepsToGo;
      if (stepsToGo < 0) {
        db.commit();
        return;
      }
      setTimeout(processNextStep, 100);
   };

This is something you can't do with the current implicit commit
      
One last thing. Drawingbuffer should be passable anywhere canvas is
as in being able to pass one to CanvasRenderingContext::drawImage, 
WebGLRenderingContext::teximage2D etc...